手寫數字識別數據集簡介MNIST數據集(修改的國家標准與技術研究所——Modified National Institute of Standards and Technology),是一個大型的包含手寫數字圖片的數據集。該數據集由0-9手寫數字圖片組成,共10個類別。每張圖片的大小為28 * 28。MNIST數據集共有70000張圖像,其中訓練集60000張,測試集10000張。訓練集分為55000張訓練圖像與5000張驗證圖像。MNIST圖像為單通道。 使用CNN來實現卷積神經網絡:CNN(Convolutional neural network),即卷積神經網絡。卷積理解為一個信號與另外一個信號進行疊加,產生新的信號的過程。(在卷積神經網絡中,可認為具有固定權重的滑動窗口與原窗口的數據進行對位相乘再相加的過程。)CNN主要層次:1.輸入層------輸入的是圖片。 2.卷積層------有幾組卷積和就有幾個輸出通道,卷積之后能改變輸入的大小。 3.激勵層------卷積之后進行激活,激勵不會改變大小。 4.池化層------分為最大池化(取最大值)和平均池化(取平均值)。對激勵之后的結果進行融合,也會有一個滑動窗口,與經過激勵層的結果進行疊加,疊加后取最大值或平均值;經過池化后矩陣變小,相當於變相的減少神經元的個數。以此降低模型的復雜度,防止出現過擬合。池化不會改變通道數。 功能:提取有效特征,降低模型復雜度,防止過擬合。 5.全連接層-----對提取的局部特征信息進行融合構成一個完整的圖像。(全連接層不設置連接層的個數,可以為一層,也可以為兩層。) 卷積神經網絡為了防止過擬合在全連接層設置了一個神經元的隨機失活率。 |
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
if __name__ == '__main__':
# 讀入數據。
mnist = input_data.read_data_sets("data/", one_hot=True)
with tf.name_scope("input"):
# 訓練圖像的占位符。
x = tf.placeholder(tf.float32, [None, 784])
# 訓練圖像對應分類(標簽)的占位符。
y = tf.placeholder(tf.float32, [None, 10])
# 因為卷積要求輸入的是4維數據,因此對形狀進行轉換。
# NHWC(默認) NCHW
# N number樣本的數量
# H height圖像的高度
# W width圖像的寬度
# C channel圖像的通道數
x_image = tf.reshape(x, [-1, 28, 28, 1])
# 卷積層1。
with tf.name_scope("conv_layer1"):
# 定義權重。(w就是滑動窗口)
# 5, 5, 1, 32 => 滑動窗口的高度,滑動窗口的寬度,輸入通道數,輸出通道數。
w = tf.Variable(tf.truncated_normal([5, 5, 1, 32], stddev=0.1), name="w")
# 定義偏置。
b = tf.Variable(tf.constant(0.0, shape=[32]), name="b")
# 進行卷積計算。
# strides=[1, 1, 1, 1] 步幅。針對輸入的NHWC定義的增量。
# padding: SAME 與VALID。SAME,只要滑動窗口不全移除輸入區域就可以。
# VALID,滑動窗口必須完全在輸入區域之內。
conv = tf.nn.bias_add(tf.nn.conv2d(x_image, w, strides=[1, 1, 1, 1], padding='SAME'), b, name="conv")
# 使用激活函數進行激活。
activation = tf.nn.relu(conv)
# 池化操作。
# ksize:池化的窗口。
pool = tf.nn.max_pool(activation, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 卷積層2。
with tf.name_scope("conv_layer2"):
w = tf.Variable(tf.truncated_normal([5, 5, 32, 64], stddev=0.1), name="w")
b = tf.Variable(tf.constant(0.0, shape=[64]), name="b")
conv = tf.nn.bias_add(tf.nn.conv2d(pool, w, strides=[1, 1, 1, 1], padding='SAME'), b, name="conv")
activation = tf.nn.relu(conv)
pool = tf.nn.max_pool(activation, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 全連接層1。
with tf.name_scope("full_layer1"):
# 7 * 7 * 64
# 原始圖像是28 * 28,經過卷積與激勵后,沒有改變,經過2 * 2池化后,變成 14 * 14。
# 第一層卷積之后結果為14 * 14,經過第二層卷積與激勵后,沒有改變,經過2 * 2池化后,變成 7 * 7。
# 第二層卷積之后,我們圖像的形狀為 NHWC => [N, 7, 7, 64]
# 4維變成2二維,將后面三維拉伸成為1維。 =》 [N, 7 * 7 * 64]
w = tf.Variable(tf.truncated_normal([7 * 7 * 64, 1024], stddev=0.1), name="w")
b = tf.Variable(tf.constant(0.0, shape=[1024]), name="b")
# 將第二層卷積之后的結果轉換成二維結構。
pool = tf.reshape(pool, [-1, 7 * 7 * 64])
activation = tf.nn.relu(tf.matmul(pool, w) + b)
# 執行dropout(隨機丟棄)
keep_prob = tf.placeholder(tf.float32)
# 進行隨機丟棄,keep_prob指定神經元的保留率。
drop = tf.nn.dropout(activation, keep_prob)
# 全連接層2。
with tf.name_scope("full_layer2"):
w = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1), name="w")
b = tf.Variable(tf.constant(0.0, shape=[10]), name="b")
logits = tf.matmul(drop, w) + b
# 損失值與准確率計算層。
with tf.name_scope("compute"):
# 計算損失值。
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits))
# 將損失值加入到tensorboard中。
#tf.summary.scalar('loss',loss)
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
# 計算准確率
correct = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
#tf.summary.scalar('accuracy',accuracy)
#合並所有的summary
#merged = tf.summary.merge_all()
# 創建Session。
with tf.Session() as sess:
# 對全局變量進行初始化。
sess.run(tf.global_variables_initializer())
#train_writer = tf.summary.FileWriter('logs/train',sess.graph)
#test_writer = tf.summary.FileWriter('logs/test',sess.graph)
# 可以嘗試更大的次數,可以將准確率提升到99%以上。
for i in range(1, 3001):
batch = mnist.train.next_batch(64)
# 每100步報告一次在驗證集上的准確度
if i % 100 == 0:
train_accuracy = accuracy.eval(
feed_dict={x: batch[0], y: batch[1], keep_prob: 1.0})
test_accuracy = accuracy.eval(
feed_dict={x: mnist.test.images[:5000], y: mnist.test.labels[:5000], keep_prob: 1.0})
print(f"step {i}, training accuracy {train_accuracy * 100:.2f}%")
print(f"step {i}, test accuracy {test_accuracy * 100:.2f}%")
train_step.run(feed_dict={x: batch[0], y: batch[1], keep_prob: 0.5})
# 計算並寫入訓練集計算的結果。
#summary = sess.run(merged,feed_dict={x:batch[0], y:batch[1] ,keep_prob:1.0})
#train_writer.add_summary(summary, i)
# 計算並寫入測試集計算的結果。
#summary = sess.run(merged,feed_dict={x:mnist.test.images, y:mnist.test.labels, keep_prob:1.0})
#test_writer.add_summary(summary,i)
部分運行結果:
step 100, training accuracy 81.25%
step 100, test accuracy 85.28%
step 200, training accuracy 90.62%
step 200, test accuracy 91.00%
step 300, training accuracy 100.00%
step 300, test accuracy 92.14%
step 400, training accuracy 96.88%
step 400, test accuracy 93.88%
step 500, training accuracy 93.75%
step 500, test accuracy 94.34%
step 600, training accuracy 98.44%
step 600, test accuracy 94.64%
