TensorFlow筆記(4)——優(yōu)化手寫(xiě)數(shù)字識(shí)別模型之代價(jià)函數(shù)和擬合

前言

上篇筆記我們利用MNIST數(shù)據(jù)集訓(xùn)練了一個(gè)手寫(xiě)數(shù)字識(shí)別的模型,但是準(zhǔn)確率非常的低,維持在91%左右,我們可以嘗試著將準(zhǔn)確率提高到96%以上,在實(shí)驗(yàn)之前我們需要先了解一些基本的概念,本篇文章可能會(huì)有些枯燥,因?yàn)榇蠖喽际抢碚撝R(shí)。

本文重點(diǎn)

  1. 激活函數(shù)
  2. 代價(jià)函數(shù)
  3. 擬合

什么是激活函數(shù)?激活函數(shù)是干嘛的?

想了解什么是激活函數(shù),就要先了解神經(jīng)網(wǎng)絡(luò)的基本模型,下圖所示為一單一人工神經(jīng)網(wǎng)絡(luò)的基本模型圖:


單一人工神經(jīng)網(wǎng)絡(luò)的基本模型圖

神經(jīng)網(wǎng)絡(luò)中的每個(gè)神經(jīng)元節(jié)點(diǎn)接受上一層神經(jīng)元的輸出值作為本神經(jīng)元的輸入值,并將輸入值傳遞給下一層,輸入層神經(jīng)元節(jié)點(diǎn)會(huì)將輸入屬性值直接傳遞給下一層(隱藏層或輸出層)。在多層神經(jīng)網(wǎng)絡(luò)中,上層節(jié)點(diǎn)的輸出和下層節(jié)點(diǎn)的輸入之間具有一個(gè)函數(shù)關(guān)系,這個(gè)函數(shù)稱(chēng)為激活函數(shù)(又稱(chēng)激勵(lì)函數(shù))。

如果我們不運(yùn)用激活函數(shù)的話,則輸出信號(hào)將僅僅是一個(gè)簡(jiǎn)單的線性函數(shù)。線性函數(shù)一個(gè)一級(jí)多項(xiàng)式?,F(xiàn)如今,線性方程是很容易解決的,但是它們的復(fù)雜性有限,并且從數(shù)據(jù)中學(xué)習(xí)復(fù)雜函數(shù)映射的能力更小。一個(gè)沒(méi)有激活函數(shù)的神經(jīng)網(wǎng)絡(luò)將只不過(guò)是一個(gè)線性回歸模型(Linear regression Model)罷了,它功率有限,并且大多數(shù)情況下執(zhí)行得并不好。我們希望我們的神經(jīng)網(wǎng)絡(luò)不僅僅可以學(xué)習(xí)和計(jì)算線性函數(shù),而且還要比這復(fù)雜得多。同樣是因?yàn)闆](méi)有激活函數(shù),我們的神經(jīng)網(wǎng)絡(luò)將無(wú)法學(xué)習(xí)和模擬其他復(fù)雜類(lèi)型的數(shù)據(jù),例如圖像、視頻、音頻、語(yǔ)音等。這就是為什么我們要使用人工神經(jīng)網(wǎng)絡(luò)技術(shù),諸如深度學(xué)習(xí)(Deep learning),來(lái)理解一些復(fù)雜的事情,一些相互之間具有很多隱藏層的非線性問(wèn)題,而這也可以幫助我們了解復(fù)雜的數(shù)據(jù)。

那么為什么我們需要非線性函數(shù)?

非線性函數(shù)是那些一級(jí)以上的函數(shù),而且當(dāng)繪制非線性函數(shù)時(shí)它們具有曲率?,F(xiàn)在我們需要一個(gè)可以學(xué)習(xí)和表示幾乎任何東西的神經(jīng)網(wǎng)絡(luò)模型,以及可以將輸入映射到輸出的任意復(fù)雜函數(shù)。神經(jīng)網(wǎng)絡(luò)被認(rèn)為是通用函數(shù)近似器(Universal Function Approximators)。這意味著他們可以計(jì)算和學(xué)習(xí)任何函數(shù)。幾乎我們可以想到的任何過(guò)程都可以表示為神經(jīng)網(wǎng)絡(luò)中的函數(shù)計(jì)算。

而這一切都?xì)w結(jié)于這一點(diǎn),我們需要應(yīng)用激活函數(shù)f(x),以便使網(wǎng)絡(luò)更加強(qiáng)大,增加它的能力,使它可以學(xué)習(xí)復(fù)雜的事物,復(fù)雜的表單數(shù)據(jù),以及表示輸入輸出之間非線性的復(fù)雜的任意函數(shù)映射。因此,使用非線性激活函數(shù),我們便能夠從輸入輸出之間生成非線性映射。

激活函數(shù)的另一個(gè)重要特征是:它應(yīng)該是可以區(qū)分的。我們需要這樣做,以便在網(wǎng)絡(luò)中向后推進(jìn)以計(jì)算相對(duì)于權(quán)重的誤差(丟失)梯度時(shí)執(zhí)行反向優(yōu)化策略,然后相應(yīng)地使用梯度下降或任何其他優(yōu)化技術(shù)優(yōu)化權(quán)重以減少誤差。

二次代價(jià)函數(shù)

二次代價(jià)函數(shù)的公式如下:
C=\frac{1}{2n}\sum_{x}^{ }\left \| y(x)-{a}^L(x) \right \|^2

其中,C表示代價(jià),x表示樣本,y表示實(shí)際值,a表示輸出值,n表示樣本的總數(shù)。為簡(jiǎn)單起見(jiàn),以一個(gè)樣本為例進(jìn)行說(shuō)明,此時(shí)二次代價(jià)函數(shù)為:
C=\frac{(y-a)^2}{2}
其中a=\delta (z),z=\sum W_j*X_j+b,\delta (z)是激活函數(shù)

加入我們使用梯度下降法來(lái)調(diào)整權(quán)值參數(shù)的大小,權(quán)值w和偏置b的梯度推導(dǎo)如下:
\frac{\partial C}{\partial w}=(a-y)\sigma'(z)x
\frac{\partial C}{\partial b}=(a-y)\sigma'(z)
其中,z表示神經(jīng)元的輸入,\sigma表示激活函數(shù)。從以上公式可以看出,w和b的梯度跟激活函數(shù)的梯度成正比,激活函數(shù)的梯度越大,wb的大小調(diào)整得越快,訓(xùn)練收斂得就越快。而神經(jīng)網(wǎng)絡(luò)常用的激活函數(shù)為sigmoid函數(shù),該函數(shù)的曲線如下所示:

所以在這種情況下,權(quán)值和偏置的變化就會(huì)出現(xiàn)如下異常:

假設(shè)我們目標(biāo)是收斂到 1。A 點(diǎn)為 0.82 離目標(biāo)比較遠(yuǎn),梯度比較大,權(quán)值調(diào)整比較大。B 點(diǎn)為 0.98 離目標(biāo)比較近,梯度比較小,權(quán)值調(diào)整比較小。調(diào)整方案合理。
假如我們目標(biāo)是收斂到 0. A 點(diǎn)為 0.82 離目標(biāo)比較近,梯度比較大,權(quán)值調(diào)整比較大。B 點(diǎn)為 0.98 離目標(biāo)比較遠(yuǎn),梯度比較小,權(quán)值調(diào)整比較小。調(diào)整方案不合理。

那么可能有人就會(huì)說(shuō),如果我們想要解決上述問(wèn)題,選擇一個(gè)梯度不變化或變化不明顯的激活函數(shù)不就解決問(wèn)題了嗎?圖樣圖森破,那樣雖然簡(jiǎn)單粗暴地解決了這個(gè)問(wèn)題,但可能會(huì)引起其他更多更麻煩的問(wèn)題。而且,類(lèi)似sigmoid這樣的函數(shù)(比如tanh函數(shù))有很多優(yōu)點(diǎn),非常適合用來(lái)做激活函數(shù),具體請(qǐng)自行g(shù)oogle之。

在這里我們不改變激活函數(shù),選擇將代價(jià)函數(shù)改為交叉熵代價(jià)函數(shù)。

交叉熵代價(jià)函數(shù)

先放公式:C=-\frac{1}{n}\sum_{x}^{ }[ylna+(1-y)ln(1-a)]
其中,C表示代價(jià),x表示樣本,y表示實(shí)際值,a表示輸出值,n表示樣本的總數(shù)。那么,重新計(jì)算參數(shù)w的梯度:

其中:{\sigma }'(z)=\sigma (z)(1-\sigma (z))
因此,w的梯度公式中原來(lái)的{\sigma }'(z)被消掉了;另外,該梯度公式中的\sigma (z)-y表示輸出值與實(shí)際值之間的誤差。所以,當(dāng)誤差越大,梯度就越大,參數(shù)w調(diào)整得越快,訓(xùn)練速度也就越快。同理可得,b的梯度為:
\frac{\partial C}{\partial b}=\frac{1}{n}\sum_{x}^{ }(\sigma (z)-y)
實(shí)際情況證明,交叉熵代價(jià)函數(shù)帶來(lái)的訓(xùn)練效果往往比二次代價(jià)函數(shù)要好。

  • 權(quán)值和偏置值的調(diào)整與{\sigma }'(z)無(wú)關(guān),另外,梯度公式中的\sigma (z)-y表示輸出值與實(shí)際值的誤差。所以當(dāng)誤差越大時(shí),梯度就越大,參數(shù) w 和 b 的調(diào)整就越快,訓(xùn)練的速度也就越快。
  • 如果輸出神經(jīng)元是線性的,那么二次代價(jià)函數(shù)就是一種合適的選擇。如果輸出神經(jīng)元是 S 型函數(shù),那么比較適合用交叉熵代價(jià)函數(shù)。

對(duì)數(shù)釋然代價(jià)函數(shù)(log-likelihood cost)

  • 對(duì)數(shù)釋然函數(shù)常用來(lái)作為softmax回歸的代價(jià)函數(shù),然后輸出層神經(jīng)元是sigmoid函數(shù),可以采用交叉熵代價(jià)函數(shù)。而深度學(xué)習(xí)中更普遍的做法是將softmax作為最后一層,此時(shí)常用的代價(jià)函數(shù)是對(duì)數(shù)釋然代價(jià)函數(shù)。
  • 對(duì)數(shù)似然代價(jià)函數(shù)與softmax的組合和交叉熵與sigmoid函數(shù)的組合非常相似。對(duì)數(shù)釋然代價(jià)函數(shù)在二分類(lèi)時(shí)可以化簡(jiǎn)為交叉熵代價(jià)函數(shù)的形式。
    在tensorflow中用:
tf.nn.sigmoid_cross_entropy_with_logits()來(lái)表示跟sigmoid搭配使用的交叉熵。
tf.nn.softmax_cross_entropy_with_logits()來(lái)表示跟softmax搭配使用的交叉熵。

使用TensorFlow比較兩種代價(jià)函數(shù)的效果

以上一篇文章手寫(xiě)數(shù)字識(shí)別的模型為例子,在這給出采用交叉熵函數(shù)的模型的代碼:

import datetime

# 4.1 交叉熵代價(jià)函數(shù)
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

start = datetime.datetime.now()

# 載入數(shù)據(jù)
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
# 每個(gè)批次的大小
batch_size = 50
# 計(jì)算一共有多少個(gè)批次
n_batch = mnist.train.num_examples // batch_size

# 定義兩個(gè)placeholder
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])

# 創(chuàng)建一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
prediction = tf.nn.softmax(tf.matmul(x, W)+b)

# 二次代價(jià)函數(shù)
# loss = tf.reduce_mean(tf.square(y-prediction))
# 交叉熵代價(jià)函數(shù)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(
    labels=y, logits=prediction))
# 使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 初始化變量
init = tf.global_variables_initializer()

# 結(jié)果存放在一個(gè)布爾型列表中
# argmax返回一維張量中最大的值所在的位置
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
# 求準(zhǔn)確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(30):
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys})
        acc = sess.run(accuracy, feed_dict={
                       x: mnist.test.images, y: mnist.test.labels})
        print("Iter "+str(epoch)+",Testing Accuracy "+str(acc))

end = datetime.datetime.now()
print((end-start).seconds)

在這里我們將二次代價(jià)函數(shù)更改為了交叉熵代價(jià)函數(shù):

# 二次代價(jià)函數(shù)
# loss = tf.reduce_mean(tf.square(y-prediction))
# 交叉熵代價(jià)函數(shù)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(
    labels=y, logits=prediction))

接下來(lái)我們來(lái)對(duì)比下訓(xùn)練的結(jié)果:


使用二次代價(jià)函數(shù)的訓(xùn)練結(jié)果

使用交叉熵代價(jià)函數(shù)的訓(xùn)練結(jié)果

由上圖可知,使用二次代價(jià)函數(shù)訓(xùn)練第10次的精確度為0.9063,而使用交叉熵代價(jià)函數(shù)訓(xùn)練到第2次的精確度就已經(jīng)超過(guò)0.9了,結(jié)果顯而易見(jiàn)。

擬合

擬合分為三種:1.欠擬合(underfitting);2. 正確擬合(just right);3. 過(guò)擬合(overfitting);如下圖所示:

擬合

其中每個(gè)x表示的是樣本,每條曲線代表的是模型。
下圖是分類(lèi)問(wèn)題中的擬合情況,和上述情況類(lèi)似。
擬合

在這里介紹過(guò)擬合,下面是wikipedia對(duì)于overfitting的解釋。
在統(tǒng)計(jì)學(xué)和機(jī)器學(xué)習(xí)中,overfitting一般在描述統(tǒng)計(jì)學(xué)模型隨機(jī)誤差或噪音時(shí)用到。它通常發(fā)生在模型過(guò)于復(fù)雜的情況下,如參數(shù)過(guò)多等。overfitting會(huì)使得模型的預(yù)測(cè)性能變?nèi)?,并且增加?shù)據(jù)的波動(dòng)性。

發(fā)生overfitting是因?yàn)樵u(píng)判訓(xùn)練模型的標(biāo)準(zhǔn)不適用于作為評(píng)判該模型好壞的標(biāo)準(zhǔn),模型通常會(huì)增強(qiáng)模型在訓(xùn)練模型的預(yù)測(cè)性能。但是模型的性能并不是由模型在訓(xùn)練集的表現(xiàn)好壞而決定,它是由模型在未知數(shù)據(jù)集上的表現(xiàn)確定的。當(dāng)模型開(kāi)始“memorize”訓(xùn)練數(shù)據(jù)而不是從訓(xùn)練數(shù)據(jù)中“l(fā)earning”時(shí),overfitting就出現(xiàn)了。比如,如果模型的parameters大于或等于觀測(cè)值的個(gè)數(shù),這種模型會(huì)顯得過(guò)于簡(jiǎn)單,雖然模型在訓(xùn)練時(shí)的效果可以表現(xiàn)的很完美,基本上記住了數(shù)據(jù)的全部特點(diǎn),但這種模型在未知數(shù)據(jù)的表現(xiàn)能力會(huì)大減折扣,因?yàn)楹?jiǎn)單的模型泛化能力通常都是很弱的。


上面這個(gè)圖,是通過(guò)線性函數(shù)和多項(xiàng)式函數(shù)來(lái)擬合這些數(shù)據(jù)點(diǎn),顯然多項(xiàng)式函數(shù)擬合效果很完美,包含了所有的點(diǎn),而線性函數(shù)丟失了大部分點(diǎn)。但實(shí)際上,線性函數(shù)有一個(gè)很好的泛化能力,如果用這些點(diǎn)來(lái)做一個(gè)回歸線,多項(xiàng)式函數(shù)過(guò)擬合的情況更糟糕。

過(guò)擬合不僅和參數(shù)的個(gè)數(shù)以及數(shù)據(jù)有關(guān),也和數(shù)據(jù)形狀模型結(jié)構(gòu)的一致性有關(guān)。

為了避免過(guò)擬合,有必要使用一些額外的技術(shù)(如交叉驗(yàn)證、正則化、early stopping、貝斯信息量準(zhǔn)則、赤池信息量準(zhǔn)則或model comparison),以指出何時(shí)會(huì)有更多訓(xùn)練而沒(méi)有導(dǎo)致更好的一般化。

Overfitting的概念在機(jī)器學(xué)習(xí)中很重要。通常一個(gè)學(xué)習(xí)算法是借由訓(xùn)練樣本來(lái)訓(xùn)練的,在訓(xùn)練時(shí)會(huì)伴隨著訓(xùn)練誤差。當(dāng)把該模型用到未知數(shù)據(jù)的測(cè)試時(shí),就會(huì)相應(yīng)的帶來(lái)一個(gè)validation error。下面通過(guò)訓(xùn)練誤差和驗(yàn)證誤差來(lái)詳細(xì)分析一下overfitting。如下圖:

在上圖總,藍(lán)色表示訓(xùn)練誤差training error,紅色表示validation error。當(dāng)訓(xùn)練誤差達(dá)到中間的那條垂直線的點(diǎn)時(shí),模型應(yīng)該是最優(yōu)的,如果繼續(xù)減少模型的訓(xùn)練誤差,這時(shí)就會(huì)發(fā)生過(guò)擬合。

其實(shí)你可以這樣來(lái)理解overfitting:數(shù)據(jù)集中信息分為兩部分,一部分是和預(yù)測(cè)未來(lái)數(shù)據(jù)有關(guān)的數(shù)據(jù),另一部分是無(wú)關(guān)的,兩者地位是平等的。用來(lái)作為預(yù)測(cè)的評(píng)判標(biāo)準(zhǔn)越不精確,表明噪聲數(shù)據(jù)就越多,需要忽略掉的數(shù)據(jù)也就越多,而關(guān)鍵就是究竟那一部分應(yīng)該忽略掉。所以我們把一個(gè)學(xué)習(xí)算法對(duì)噪聲的削減能力就叫做它的魯棒性。我們需要的就是魯棒性很強(qiáng)的學(xué)習(xí)算法

舉一個(gè)簡(jiǎn)單的例子,一個(gè)零售購(gòu)物的數(shù)據(jù)庫(kù)包括購(gòu)買(mǎi)項(xiàng)、購(gòu)買(mǎi)人、日期、和購(gòu)買(mǎi)時(shí)間。根據(jù)這個(gè)數(shù)據(jù)可以很容易的建立一個(gè)模型,并且在訓(xùn)練集上的擬合效果也會(huì)很好,通過(guò)使用日期、購(gòu)買(mǎi)時(shí)間來(lái)預(yù)測(cè)其它屬性列的值,但是這個(gè)模型對(duì)于新數(shù)據(jù)的泛化能力很弱,因?yàn)檫@些過(guò)去的數(shù)據(jù)不會(huì)再次發(fā)生。

防止過(guò)擬合的幾種方式

這里推薦閱讀機(jī)器學(xué)習(xí)中用來(lái)防止過(guò)擬合的方法有哪些?,說(shuō)的比較詳細(xì)。

  1. 增加數(shù)據(jù)集
    你的模型可以存儲(chǔ)很多很多的信息,這意味著你輸入模型的訓(xùn)練數(shù)據(jù)越多,模型就越不可能發(fā)生過(guò)擬合。原因是隨著你添加更多數(shù)據(jù),模型會(huì)無(wú)法過(guò)擬合所有的數(shù)據(jù)樣本,被迫產(chǎn)生泛化以取得進(jìn)步。 收集更多的數(shù)據(jù)樣本應(yīng)該是所有數(shù)據(jù)科學(xué)任務(wù)的第一步,數(shù)據(jù)越多會(huì)讓模型的準(zhǔn)確率更高,這樣也就能降低發(fā)生過(guò)擬合的概率。
  1. 正則化方法 C=C_0+\frac{\lambda }{2n}\sum_{w}^{ }w^2
    正則化是指約束模型的學(xué)習(xí)以減少過(guò)擬合的過(guò)程。它可以有多種形式,推薦閱讀機(jī)器學(xué)習(xí)中用來(lái)防止過(guò)擬合的方法有哪些?,說(shuō)的比較詳細(xì)。
  2. Dropout

    由于深度學(xué)習(xí)依賴(lài)神經(jīng)網(wǎng)絡(luò)處理從一個(gè)層到下一個(gè)層的信息,因而從這兩方面著手比較有效。其理念就是在訓(xùn)練中隨機(jī)讓神經(jīng)元無(wú)效(即dropout)或讓網(wǎng)絡(luò)中的連接無(wú)效(即dropconnect)。
    droppout

這樣就讓神經(jīng)網(wǎng)絡(luò)變得冗長(zhǎng)和重復(fù),因?yàn)樗鼰o(wú)法再依賴(lài)具體的神經(jīng)元或連接來(lái)提取具體的特征。等完成模型訓(xùn)練后,所有的神經(jīng)元和連接會(huì)被保存下來(lái)。試驗(yàn)顯示這種方法能起到和神經(jīng)網(wǎng)絡(luò)集成方法一樣的效果,可以幫助模型泛化,這樣就能減少過(guò)擬合的問(wèn)題。

我們來(lái)用代碼體驗(yàn)下dropout:

import datetime
# 4.2 Dropout
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

start = datetime.datetime.now()

# 載入數(shù)據(jù)
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
# 每個(gè)批次的大小
batch_size = 50
# 計(jì)算一共有多少個(gè)批次
n_batch = mnist.train.num_examples // batch_size

# 定義兩個(gè)placeholder
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)

# 創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò)
W1 = tf.Variable(tf.truncated_normal([784, 2000], stddev=0.1))
b1 = tf.Variable(tf.zeros([2000])+0.1)
L1 = tf.nn.tanh(tf.matmul(x, W1)+b1)
L1_drop = tf.nn.dropout(L1, keep_prob)

W2 = tf.Variable(tf.truncated_normal([2000, 2000], stddev=0.1))
b2 = tf.Variable(tf.zeros([2000])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop, W2)+b2)
L2_drop = tf.nn.dropout(L2, keep_prob)

W3 = tf.Variable(tf.truncated_normal([2000, 1000], stddev=0.1))
b3 = tf.Variable(tf.zeros([1000])+0.1)
L3 = tf.nn.tanh(tf.matmul(L2_drop, W3)+b3)
L3_drop = tf.nn.dropout(L3, keep_prob)

W4 = tf.Variable(tf.truncated_normal([1000, 10], stddev=0.1))
b4 = tf.Variable(tf.zeros([10])+0.1)

prediction = tf.nn.softmax(tf.matmul(L3_drop, W4)+b4)

# 二次代價(jià)函數(shù)
# loss = tf.reduce_mean(tf.square(y-prediction))
# 交叉熵代價(jià)函數(shù)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(
    labels=y, logits=prediction))
# 使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 初始化變量
init = tf.global_variables_initializer()

# 結(jié)果存放在一個(gè)布爾型列表中
# argmax返回一維張量中最大的值所在的位置
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
# 求準(zhǔn)確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(20):
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(train_step, feed_dict={
                     x: batch_xs, y: batch_ys, keep_prob: 1.0})

        test_acc = sess.run(accuracy, feed_dict={
            x: mnist.test.images, y: mnist.test.labels, keep_prob: 1.0})

        train_acc = sess.run(accuracy, feed_dict={
            x: mnist.train.images, y: mnist.train.labels, keep_prob: 1.0})

        print("Iter "+str(epoch)+",Testing Accuracy " +
              str(test_acc)+",Train Accuracy"+str(train_acc))

end = datetime.datetime.now()
print((end-start).seconds)

相較于之前的代碼我們更改了以下一些地方:

W1 = tf.Variable(tf.truncated_normal([784, 2000], stddev=0.1))
b1 = tf.Variable(tf.zeros([2000])+0.1)
L1 = tf.nn.tanh(tf.matmul(x, W1)+b1)
L1_drop = tf.nn.dropout(L1, keep_prob)

W2 = tf.Variable(tf.truncated_normal([2000, 2000], stddev=0.1))
b2 = tf.Variable(tf.zeros([2000])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop, W2)+b2)
L2_drop = tf.nn.dropout(L2, keep_prob)

W3 = tf.Variable(tf.truncated_normal([2000, 1000], stddev=0.1))
b3 = tf.Variable(tf.zeros([1000])+0.1)
L3 = tf.nn.tanh(tf.matmul(L2_drop, W3)+b3)
L3_drop = tf.nn.dropout(L3, keep_prob)

W4 = tf.Variable(tf.truncated_normal([1000, 10], stddev=0.1))
b4 = tf.Variable(tf.zeros([10])+0.1)

prediction = tf.nn.softmax(tf.matmul(L3_drop, W4)+b4)

我額外的為神經(jīng)網(wǎng)絡(luò)添加了兩個(gè)隱藏層,為了方便體現(xiàn)出差異,我將每個(gè)隱藏層的神經(jīng)元數(shù)量設(shè)置的比較多。
然后在訓(xùn)練過(guò)程中,

for epoch in range(10):
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(train_step, feed_dict={
                     x: batch_xs, y: batch_ys, keep_prob: 1.0})

        test_acc = sess.run(accuracy, feed_dict={
            x: mnist.test.images, y: mnist.test.labels, keep_prob: 1.0})

        train_acc = sess.run(accuracy, feed_dict={
            x: mnist.train.images, y: mnist.train.labels, keep_prob: 1.0})

        print("Iter "+str(epoch)+",Testing Accuracy " +
              str(test_acc)+",Train Accuracy"+str(train_acc))

其中keep_prob表示啟用神經(jīng)元占神經(jīng)元總數(shù)的百分比(1.0表示全部使用),train_acc表示用訓(xùn)練樣本來(lái)測(cè)試訓(xùn)練出來(lái)的模型的精確度,test_acc表示用測(cè)試樣本來(lái)測(cè)試訓(xùn)練出來(lái)的模型的精確度,用這兩個(gè)數(shù)據(jù)來(lái)反映出擬合程度。訓(xùn)練結(jié)果如下圖所示:


在這里我們總共就訓(xùn)練了10次,而且數(shù)據(jù)量并不大,此時(shí)test_acc和train_acc就已經(jīng)差了兩個(gè)百分點(diǎn),如果應(yīng)用到其他項(xiàng)目中,數(shù)據(jù)量變大之后就不是2個(gè)百分點(diǎn)的事情了,所以說(shuō)如果神經(jīng)元數(shù)量過(guò)多是會(huì)造成過(guò)度擬合的。

總結(jié)

在本文中為了提高精確度,引入了代價(jià)函數(shù)這個(gè)概念,為了更好的理解代價(jià)函數(shù)因此提前介紹了什么是激活函數(shù)以及為什么需要激活函數(shù)。在只用一層神經(jīng)網(wǎng)絡(luò)的時(shí)候通過(guò)更改代價(jià)函數(shù),我們可以使精確度達(dá)到93%左右(訓(xùn)練次數(shù)較多時(shí)),但這還是不夠,所以我們嘗試多添加幾層神經(jīng)元,但是這時(shí)候就會(huì)出現(xiàn)“過(guò)擬合”這個(gè)新的問(wèn)題了,通常有三種方式解決過(guò)擬合的問(wèn)題。之后的文章將會(huì)在此基礎(chǔ)上介紹以下優(yōu)化器,并且告知大家如何使用谷歌免費(fèi)的GPU服務(wù)加速深度學(xué)習(xí)的模型訓(xùn)練。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文章主要分為:一、深度學(xué)習(xí)概念;二、國(guó)內(nèi)外研究現(xiàn)狀;三、深度學(xué)習(xí)模型結(jié)構(gòu);四、深度學(xué)習(xí)訓(xùn)練算法;五、深度學(xué)習(xí)的優(yōu)點(diǎn)...
    艾剪疏閱讀 22,206評(píng)論 0 58
  • 原文地址:http://www.cnblogs.com/subconscious/p/5058741.html 神...
    Albert陳凱閱讀 5,588評(píng)論 0 48
  • 直觀的草圖 我的第一份工作是在造船廠當(dāng)質(zhì)檢員。那時(shí)候船舶建造的自動(dòng)化程度比較低,船上有些狹窄的區(qū)域需要裝焊時(shí),工人...
    南多先生閱讀 308評(píng)論 2 9
  • --------------------------學(xué)習(xí)過(guò)程見(jiàn)解,錯(cuò)誤之處還請(qǐng)指出----------------...
    薛小皮閱讀 1,669評(píng)論 0 0
  • 【今日三問(wèn)】 1、你覺(jué)得你和周?chē)娜擞凶龅接行贤▎??(情感交?傳遞信息/影響說(shuō)服) 我感覺(jué)并沒(méi)有很有效,在和別...
    北葵向暖_2e25閱讀 185評(píng)論 0 0

友情鏈接更多精彩內(nèi)容