前面兩篇隨筆實現的單層神經網絡 和多層神經網絡, 在MNIST測試集上的正確率分別約為90%和96%。在換用多層神經網絡后,正確率已有很大的提升。這次將采用卷積神經網絡繼續進行測試。
1、模型基本結構
如下圖所示,本次采用的模型共有8層(包含dropout層)。其中卷積層和池化層各有兩層。
在整個模型中,輸入層負責數據輸入;卷積層負責提取圖片的特征;池化層采用最大池化的方式,突出主要特征,並減少參數維度;全連接層再將個特征組合起來;dropout層可以減少每次訓練的計算量,並可以一定程度上避免過擬合問題;最后輸出層再綜合各特征數據,得出最終結果。
Dropout層起始並沒有增加訓練參數,只是隨機的將某些節點間的連接弧斷開,使其在本次中暫時的不參與訓練。

2、數據預處理
首先讀取用於訓練的數據。
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('./data/mnist', one_hot=True)
在前面的輸入層中,輸入的每個樣本都是一維的數據,而卷積神經網絡的樣本數據將是多維的。因此我們需要將讀取到的數據再reshape一下,使其符合要求。
data.reshape([batchSize, 28, 28, 1])
3、輸入層
輸入層的shape為:bitchSize * 28 * 28 * 1,第一個參數表示每個mini-batch的樣本數量,由傳入None可以讓TensorFlow自動推斷;后面三個參數表示每個樣本的高為28,寬為28,通道數為1。
inputLayer = tf.placeholder(tf.float32, shape=[None, 28, 28, 1])
4、卷積層
第一個卷積層的卷積核大小為5 * 5,數量為32個。padding方式采用‘SAME’。第二個卷積層類似,只是通道數,輸出維度不一樣。
1 convFilter1 = tf.Variable(tf.truncated_normal([5, 5, 1, 32], mean=0, stddev=0.1)) 2 convBias1 = tf.Variable(tf.truncated_normal([32], mean=0, stddev=0.1)) 3 convLayer1 = tf.nn.conv2d(input=inputLayer, filter=convFilter1, strides=[1, 1, 1, 1], padding='SAME') 4 convLayer1 = tf.add(convLayer1, convBias1) 5 convLayer1 = tf.nn.relu(convLayer1)
5、池化層
滑動窗口的大小為 2 * 2,在高和寬的維度上的滑動步幅也為2,其他維度為1。本模型中第二個池化層與第一個池化層一樣。
poolLayer1 = tf.nn.max_pool(value=convLayer1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
6、全連接層
全連接層將前面在每個樣本中提取到的多維特征展開成一維,作為全連接層的輸入。
1 fullWeight = tf.Variable(tf.truncated_normal(shape=[7 * 7 * 64, 1024], mean=0, stddev=0.1)) 2 fullBias = tf.Variable(tf.truncated_normal(shape=[1024], mean=0.0, stddev=0.1)) 3 fullInput = tf.reshape(poolLayer2, [-1, 7 * 7 * 64]) 4 fullLayer = tf.add(tf.matmul(fullInput, fullWeight), fullBias) 5 fullLayer = tf.nn.relu(fullLayer)
7、Dropout層
dropout層可以防止過擬合問題。這里指定的保留率為0.8。
dropLayer = tf.nn.dropout(fullLayer, keep_prob=0.8)
8、輸出層
最終輸出10個數字的分類。
1 outputWeight = tf.Variable(tf.truncated_normal(shape=[1024, 10], mean=0.0, stddev=0.1)) 2 outputBias = tf.Variable(tf.truncated_normal(shape=[10], mean=0, stddev=0.1)) 3 outputLayer = tf.add(tf.matmul(dropLayer, outputWeight), outputBias)
模型的其他部分與前面的多層神經網絡差不多,這里不再贅述。
9、模型在訓練集與測試集上的表現
從模型圖上可以看到,本次采用的模型的復雜度比前面的多層神經網絡高很多。正因如此,每次迭代計算也比前面的耗時的多,后者單次耗時為前者的1500多倍。可見雖然只增加了幾層(當然除了層數的增加還有節點數的增加),但增加的計算量非常的多。
下面兩張圖為卷積神經網絡前面部分和后面部分迭代的輸出結果,可以發現到最后卷積神經網絡在訓練集上已經接近100%的准確率。


在測試集上的准確率也達到了 98% 到 99%,比多層神經網絡提供了約2個百分點。

附:
完整代碼如下:
1 import tensorflow as tf 2 from tensorflow.examples.tutorials.mnist import input_data 3 import time 4 5 # 讀取數據 6 mnist = input_data.read_data_sets('./data/mnist', one_hot=True) 7 8 # 輸入層 9 inputLayer = tf.placeholder(tf.float32, shape=[None, 28, 28, 1]) 10 11 # 卷積層(1) 12 convFilter1 = tf.Variable(tf.truncated_normal([5, 5, 1, 32], mean=0, stddev=0.1)) 13 convBias1 = tf.Variable(tf.truncated_normal([32], mean=0, stddev=0.1)) 14 convLayer1 = tf.nn.conv2d(input=inputLayer, filter=convFilter1, strides=[1, 1, 1, 1], padding='SAME') 15 convLayer1 = tf.add(convLayer1, convBias1) 16 convLayer1 = tf.nn.relu(convLayer1) 17 18 # 池化層(1) 19 poolLayer1 = tf.nn.max_pool(value=convLayer1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 20 21 # 卷積層(2) 22 convFilter2 = tf.Variable(tf.truncated_normal([5, 5, 32, 64], mean=0, stddev=0.1)) 23 convBias2 = tf.Variable(tf.truncated_normal([64], mean=0, stddev=0.1)) 24 convLayer2 = tf.nn.conv2d(input=poolLayer1, filter=convFilter2, strides=[1, 1, 1, 1], padding='SAME') 25 convLayer2 = tf.add(convLayer2, convBias2) 26 convLayer2 = tf.nn.relu(convLayer2) 27 28 # 池化層(2) 29 poolLayer2 = tf.nn.max_pool(value=convLayer2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 30 31 # 全連接層 32 fullWeight = tf.Variable(tf.truncated_normal(shape=[7 * 7 * 64, 1024], mean=0, stddev=0.1)) 33 fullBias = tf.Variable(tf.truncated_normal(shape=[1024], mean=0.0, stddev=0.1)) 34 fullInput = tf.reshape(poolLayer2, [-1, 7 * 7 * 64]) 35 fullLayer = tf.add(tf.matmul(fullInput, fullWeight), fullBias) 36 fullLayer = tf.nn.relu(fullLayer) 37 38 # dropout層 39 dropLayer = tf.nn.dropout(fullLayer, keep_prob=0.8) 40 41 # 輸出層 42 outputWeight = tf.Variable(tf.truncated_normal(shape=[1024, 10], mean=0.0, stddev=0.1)) 43 outputBias = tf.Variable(tf.truncated_normal(shape=[10], mean=0, stddev=0.1)) 44 outputLayer = tf.add(tf.matmul(dropLayer, outputWeight), outputBias) 45 46 # 標簽 47 outputLabel = tf.placeholder(tf.float32, shape=[None, 10]) 48 49 # 損失函數及目標函數 50 loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=outputLabel, logits=outputLayer)) 51 target = tf.train.AdamOptimizer().minimize(loss) 52 53 # 記錄起始訓練時間 54 startTime = time.time() 55 56 # 訓練 57 with tf.Session() as sess: 58 sess.run(tf.global_variables_initializer()) 59 batchSize = 64 60 for i in range(1000): 61 batch = mnist.train.next_batch(batchSize) 62 inputData = batch[0].reshape([batchSize, 28, 28, 1]) 63 labelData = batch[1] 64 sess.run([target, loss], feed_dict={inputLayer: inputData, outputLabel: labelData}) 65 66 corrected = tf.equal(tf.argmax(outputLabel, 1), tf.argmax(outputLayer, 1)) 67 accuracy = tf.reduce_mean(tf.cast(corrected, tf.float32)) 68 accuracyValue = sess.run(accuracy, feed_dict={inputLayer: inputData, outputLabel: labelData}) 69 print(i, 'train set accuracy:', accuracyValue) 70 71 # 打印結束時間 72 endTime = time.time() 73 print('train time:', endTime - startTime) 74 75 # 測試 76 corrected = tf.equal(tf.argmax(outputLabel, 1), tf.argmax(outputLayer, 1)) 77 accuracy = tf.reduce_mean(tf.cast(corrected, tf.float32)) 78 testImages = mnist.test.images.reshape([-1, 28, 28, 1]) 79 testLabels = mnist.test.labels 80 accuracyValue = sess.run(accuracy, feed_dict={inputLayer: testImages, outputLabel: testLabels}) 81 print("accuracy on test set:", accuracyValue) 82 83 sess.close()
本文地址:https://www.cnblogs.com/laishenghao/p/9738912.html
