您好,登錄后才能下訂單哦!
本篇文章為大家展示了如何通過MNIST手寫數(shù)字識別分析神經(jīng)網(wǎng)絡(luò)搭建,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
下面將通過一個(gè)經(jīng)典的案例:MNIST手寫數(shù)字識別,以代碼的形式來為大家梳理一遍神經(jīng)網(wǎng)絡(luò)的整個(gè)過程。
MNIST手寫數(shù)字?jǐn)?shù)據(jù)集來源于是美國國家標(biāo)準(zhǔn)與技術(shù)研究所,是著名的公開數(shù)據(jù)集之一,通常這個(gè)數(shù)據(jù)集都會被作為深度學(xué)習(xí)的入門案例。數(shù)據(jù)集中的數(shù)字圖片是由250個(gè)不同職業(yè)的人純手寫繪制,數(shù)據(jù)集獲取的網(wǎng)址為:http://yann.lecun.com/exdb/mnist/。(下載后需解壓)
具體來看,MNIST手寫數(shù)字?jǐn)?shù)據(jù)集包含有60000張圖片作為訓(xùn)練集數(shù)據(jù),10000張圖片作為測試集數(shù)據(jù),且每一個(gè)訓(xùn)練元素都是28*28像素的手寫數(shù)字圖片,每一張圖片代表的是從0到9中的每個(gè)數(shù)字。該數(shù)據(jù)集樣例如下圖所示:
如果我們把每一張圖片中的像素轉(zhuǎn)換為向量,則得到長度為28*28=784的向量。因此我們可以把MNIST數(shù)據(jù)訓(xùn)練集看作是一個(gè)[60000,784]的張量,第一個(gè)維度表示圖片的索引,第二個(gè)維度表示每張圖片中的像素點(diǎn)。而圖片里的每個(gè)像素點(diǎn)的值介于0-1之間。如下圖所示:
此外,MNIST數(shù)據(jù)集的類標(biāo)是介于0-9的數(shù)字,共10個(gè)類別。通常我們要用獨(dú)熱編碼(One_Hot Encoding)的形式表示這些類標(biāo)。所謂的獨(dú)熱編碼,直觀的講就是用N個(gè)維度來對N個(gè)類別進(jìn)行編碼,并且對于每個(gè)類別,只有一個(gè)維度有效,記作數(shù)字1 ;其它維度均記作數(shù)字0。例如類標(biāo)1表示為:([0,1,0,0,0,0,0,0,0,0]);同理標(biāo)簽2表示為:([0,0,1,0,0,0,0,0,0,0])。最后我們通過softmax函數(shù)輸出的是每張圖片屬于10個(gè)類別的概率。
接下來通過Tensorflow代碼,實(shí)現(xiàn)MINIST手寫數(shù)字識別的過程。首先,如程序1所示,我們導(dǎo)入程序所需要的庫函數(shù)、數(shù)據(jù)集:
程序1:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
接下來,我們讀取MNIST數(shù)據(jù)集,并指定用one_hot的編碼方式;然后定義batch_size、batch_num兩個(gè)變量,分別代表一次性傳入神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練的批次大小,以及計(jì)算出訓(xùn)練的次數(shù)。如程序2所示:
程序2:
mnist_data=input_data.read_data_sets("MNIST.data",one_hot=True)
batch_size=100
batch_num=mnist_data.train.num_examples//batch_size
我們需要注意的是:在執(zhí)行第一句命令時(shí),就會從默認(rèn)的地方下載MNIST數(shù)據(jù)集,下載下來的數(shù)據(jù)集會以壓縮包的形式存到指定目錄,如下圖所示。這些數(shù)據(jù)分別代表了訓(xùn)練集、訓(xùn)練集標(biāo)簽、測試集、測試集標(biāo)簽。
接著我們定義兩個(gè)placeholder,程序如下所示:
程序3:
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
其中,x代表訓(xùn)練數(shù)據(jù),y代表標(biāo)簽。具體來看,我們會把訓(xùn)練集中的圖片以batch_size批次大小,分批傳入到第一個(gè)參數(shù)中(默認(rèn)為None);X的第二個(gè)參數(shù)代表把圖片轉(zhuǎn)換為長度為784的向量;Y的第二個(gè)參數(shù)表示10個(gè)不同的類標(biāo)。
接下來我們就可以開始構(gòu)建一個(gè)簡單的神經(jīng)網(wǎng)絡(luò)了,首先定義各層的權(quán)重w和偏執(zhí)b。如程序4所示:
程序4:
weights = {
'hidden_1': tf.Variable(tf.random_normal([784, 256])),
'out': tf.Variable(tf.random_normal([256, 10]))
}
biases = {
'b1': tf.Variable(tf.random_normal([256])),
'out': tf.Variable(tf.random_normal([10]))
}
因?yàn)槲覀儨?zhǔn)備搭建一個(gè)含有一個(gè)隱藏層結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò)(當(dāng)然也可以搭建兩個(gè)或是多個(gè)隱層的神經(jīng)網(wǎng)絡(luò)),所以先要設(shè)置其每層的w和b。如上程序所示,該隱藏層含有256個(gè)神經(jīng)元。接著我們就可以開始搭建每一層神經(jīng)網(wǎng)絡(luò)了:
程序5:
def neural_network(x):
hidden_layer_1 = tf.add(tf.matmul(x, weights['hidden_1']), biases['b1'])
out_layer = tf.matmul(hidden_layer_1, weights['out']) + biases['out']
return out_layer
如程序5所示,我們定義了一個(gè)含有一個(gè)隱藏層神經(jīng)網(wǎng)絡(luò)的函數(shù)neural_network,函數(shù)的返回值是輸出層的輸出結(jié)果。
接下來我們定義損失函數(shù)、優(yōu)化器以及計(jì)算準(zhǔn)確率的方法。
程序6:
#調(diào)用神經(jīng)網(wǎng)絡(luò)
result = neural_network(x)
#預(yù)測類別
prediction = tf.nn.softmax(result)
#平方差損失函數(shù)
loss = tf.reduce_mean(tf.square(y-prediction))
#梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
#預(yù)測類標(biāo)
correct_pred = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#計(jì)算準(zhǔn)確率
accuracy = tf.reduce_mean(tf.cast(correct_pred,tf.float32))
#初始化變量
init = tf.global_variables_initializer()
如程序6所示:首先使用softmax函數(shù)對結(jié)果進(jìn)行預(yù)測,然后選擇平方差損失函數(shù)計(jì)算出loss,再使用梯度下降法的優(yōu)化方法對loss進(jìn)行最小化(梯度下降法的學(xué)習(xí)率設(shè)置為0.2)。接著使用argmax函數(shù)返回最大的值所在的位置,再使用equal函數(shù)與正確的類標(biāo)進(jìn)行比較,返回一個(gè)bool值,代表預(yù)測正確或錯(cuò)誤的類標(biāo);最后使用cast函數(shù)把bool類型的預(yù)測結(jié)果轉(zhuǎn)換為float類型(True轉(zhuǎn)換為1,F(xiàn)alse轉(zhuǎn)換為0),并對所有預(yù)測結(jié)果統(tǒng)計(jì)求平均值,算出最后的準(zhǔn)確率。要注意:最后一定不要忘了對程序中的所有變量進(jìn)行初始化。
最后一步,我們啟動(dòng)Tensorflow默認(rèn)會話,執(zhí)行上述過程。代碼如下所示:
程序7:
step_num=400
with tf.Session() as sess:
sess.run(init)
for step in range(step_num+1):
for batch in range(batch_num):
batch_x,batch_y = mnist_data.train.next_batch(batch_size)
sess.run(train_step,feed_dict={x:batch_x,y:batch_y})
acc = sess.run(accuracy,feed_dict={x:mnist_data.test.images,y:mnist_data.test.labels})
print("Step " + str(step) + ",Training Accuracy "+ "{:.3f}" + str(acc))
print("Finished!")
上述程序定義了MNIST數(shù)據(jù)集的運(yùn)行階段,首先我們定義迭代的周期數(shù),往往開始的時(shí)候準(zhǔn)確率會隨著迭代次數(shù)快速提高,但漸漸地隨著迭代次數(shù)的增加,準(zhǔn)確率提升的幅度會越來越小。而對于每一輪的迭代過程,我們用不同批次的圖片進(jìn)行訓(xùn)練,每次訓(xùn)練100張圖片,每次訓(xùn)練的圖片數(shù)據(jù)和對應(yīng)的標(biāo)簽分別保存在 batch_x、batch_y中,接著再用run方法執(zhí)行這個(gè)迭代過程,并使用feed_dict的字典結(jié)構(gòu)填充每次的訓(xùn)練數(shù)據(jù)。循環(huán)往復(fù)上述過程,直到最后一輪的訓(xùn)練結(jié)束。
最后我們利用測試集的數(shù)據(jù)檢驗(yàn)訓(xùn)練的準(zhǔn)確率,feed_dict填充的數(shù)據(jù)分別是測試集的圖片數(shù)據(jù)和測試集圖片對應(yīng)的標(biāo)簽。輸出結(jié)果迭代次數(shù)和準(zhǔn)確率,完成訓(xùn)練過程。我們截取400次的訓(xùn)練結(jié)果,如下圖所示:
以上我們便完成了MNIST手寫數(shù)字識別模型的訓(xùn)練,接下來可以從以下幾方面對模型進(jìn)行改良和優(yōu)化,以提高模型的準(zhǔn)確率。
首先,在計(jì)算損失函數(shù)時(shí),可以選擇交叉熵?fù)p失函數(shù)來代替平方差損失函數(shù),通常在Tensorflow深度學(xué)習(xí)中,softmax_cross_entropy_with_logits函數(shù)會和softmax函數(shù)搭配使用,是因?yàn)榻徊骒卦诿鎸Χ喾诸悊栴}時(shí),迭代過程中權(quán)值和偏置值的調(diào)整更加合理,模型收斂的速度更加快,訓(xùn)練的的效果也更加好。代碼如下所示:
程序8:
#預(yù)測類別
prediction = tf.nn.softmax(result)
#交叉熵?fù)p失函數(shù)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
#梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
#預(yù)測類標(biāo)
correct_pred = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#計(jì)算準(zhǔn)確率
accuracy = tf.reduce_mean(tf.cast(correct_pred,tf.float32))
如程序8所示:我們把兩個(gè)參數(shù):類標(biāo)y以及模型的預(yù)測值prediction,傳入到交叉熵?fù)p失函數(shù)softmax_cross_entropy_with_logits中,然后對函數(shù)的輸出結(jié)果求平均值,再使用梯度下降法進(jìn)行優(yōu)化。最終的準(zhǔn)確率如下圖所示:
我們可以明顯看到,使用交叉熵?fù)p失函數(shù)對于模型準(zhǔn)確率的提高還是顯而易見的,訓(xùn)練過程迭代200次的準(zhǔn)確率已經(jīng)超過了平方差損失函數(shù)迭代400次的準(zhǔn)確率。
除了改變損失函數(shù),我們還可以改變優(yōu)化算法。例如使用adam優(yōu)化算法代替隨機(jī)梯度下降法,因?yàn)樗氖諗克俣纫入S機(jī)梯度下降更快,這樣也能夠使準(zhǔn)確率有所提高。如下程序所示,我們使用學(xué)習(xí)率為0.001的AdamOptimizer作為優(yōu)化算法(其它部分不變):
程序9:
#Adam優(yōu)化算法
train_step = tf.train.AdamOptimizer(1e-2).minimize(loss)
此外,如果你了解了過擬合的概念,那么很容易可以聯(lián)想到測試集準(zhǔn)確率不高的原因,可能是因?yàn)橛?xùn)練過程中發(fā)生了“過擬合”的現(xiàn)象。所以我們可以從防止過擬合的角度出發(fā),提高模型的準(zhǔn)確率。我們可以采用增加數(shù)據(jù)量或是增加正則化項(xiàng)的方式,來緩解過擬合。這里,我們?yōu)榇蠹医榻Bdropout的方式是如何緩解過擬合的。
Dropout是在每次神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程中,使得部分神經(jīng)元工作而另外一部分神經(jīng)元不工作。而測試的時(shí)候激活所有神經(jīng)元,用所有的神經(jīng)元進(jìn)行測試。這樣便可以有效的緩解過擬合,提高模型的準(zhǔn)確率。具體代碼如下所示:
程序10:
def neural_network(x):
hidden_layer_1 = tf.add(tf.matmul(x, weights['hidden_1']), biases['b1'])
L1 = tf.nn.tanh(hidden_layer_1)
dropout1 = tf.nn.dropout(L1,0.5)
out_layer = tf.matmul(dropout1, weights['out']) + biases['out']
return out_layer
如程序10所示,我們在隱藏層后接了dropout,隨機(jī)關(guān)掉50%的神經(jīng)元,最后的測試結(jié)果如下圖所示,我們發(fā)現(xiàn)準(zhǔn)確率取得了顯著的提高,在神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)中沒有添加卷積層和池化層的情況下,準(zhǔn)確率達(dá)到了92%以上。
上述內(nèi)容就是如何通過MNIST手寫數(shù)字識別分析神經(jīng)網(wǎng)絡(luò)搭建,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。