Mnist手寫數字識別之CNN實現
Mnist手寫數字識別之CNN實現
最近有點閒,想整一下機器學習,本以為自己程式設計還不錯,想想機器學習也不難,結果被自己啪啪啪的打臉,還疼的不行。
廢話不多說,開始搞事情。
本部落格的主要內容是:通過TF一步一步用卷積神經網路(CNN)實現手寫Mnist數字識別
如果你很牛逼,就不用看我嗶嗶了,我菜鳥一隻,本部落格中涉及到多個方面的知識,有的是引用其他部落格的知識,會給出相應的連線,我就做一個知識的整理者。(ps:應該沒有人整理的有我這麼清楚明瞭吧。)
實驗環境:本程式碼是在win10系統上執行得出的結果,python版本3.6,其他相關的依賴庫和檔案均為2019/1/10截止前最新版本。
目錄結構:
- 一、TF相關函式的使用介紹;
- 二、CNN網路模型以及相關實現;
- 三、執行結果展示;
- 四、Tensor圖;
- 五、程式碼實現。
一、TF相關函式使用介紹:
注:下面相關函式的解釋均來自TF的官方文件,配套中文翻譯帶示例。
1.tf.reshape()
2. tf.layers.conv2d()
注:此函式實際上是卷積層函式,對張量進行卷積,此函式對應的是CNN中的卷積層。具體的引數如下:
3. tf.layers.max_pooling2d()
注:此函式的輸入是經過 tf.layers.conv2d() 卷積後的張量,此函式對應的是CNN中的池化層
4.tf.layers.dense()
5. tf.layers.dropout()
6. tf.losses.softmax_cross_entropy()
7. tf.metrics.accuracy()
二、CNN網路模型以及相關實現
首先在開始CNN之前,請把這張圖死記硬背記住,因為所有的一切都是圍繞著這張圖來實現的。
接下來就是你需要自己去看著三篇部落格的內容:很重要對後續的程式碼理解,而且圖文並茂,生動形象,逼真到你不要不要的。按照這個順序看,容易理解一些。
1、深入學習卷積神經網路中卷積層和池化層的意義
2、卷積神經網路(一)——卷積、邊緣化與池化層
3、卷積神經網路中卷積、反捲積、池化解析
三、執行結果展示
此結果是訓練了5000次後的模型,準確率還是蠻高的。最後從測試資料集中選取位置在20的影象進行測試。
從上圖可以看出,採用Relu這個啟用函式,剛開始的時候收斂速度非常快,經過幾百步的訓練就可以得到相對於比較高的識別率了。
最後的執行結果如下所示,都預測正確了,準確率達到了96%,你要是有強迫症,你可以訓練20000次,估計正確率能達到98左右,但是前提是你的電腦要牛掰,不然就是漫長的等待:
四、Tensor圖
五、程式碼實現
下面的程式碼寫的很詳細,每一步是幹啥的都寫了,結合上面所說的知識,理解應該不是很難
# -*- coding: UTF-8 -*-
import numpy as np
import tensorflow as tf
# down load and load Mnist library(55000 * 28 * 28)
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
# 代表訓練資料, /255. 的目的是其取值範圍在【0,255】
input_x = tf.placeholder(tf.float32, [None, 28 * 28]) / 255.
# 代表的是10個標籤,0,1,2,3....9
output_y = tf.placeholder(tf.int32, [None, 10])
# shape 前面使用-1,能夠自動的對其形狀進行推導
input_x_image = tf.reshape(input_x, [-1, 28, 28, 1])
# 從測試資料集中選取3000個測試資料進行驗證模型,
# 每次都使用這一批相同的測試資料進行測試,能夠保證唯一性
test_x = mnist.test.images[:3000] # picture
test_y = mnist.test.labels[:3000] # label
# 建立 CNN 模型
# 構建第一層 CNN 模型,卷積層
cover1 = tf.layers.conv2d(
inputs=input_x_image, # shape is [28, 28, 1]
filters=32, # 設定卷積深度為32,意思也就是說有32個卷積核
kernel_size=[5, 5], # 設定卷積核的大小
strides=1, # 設定卷積的步長
padding="same", # 進行卷積後,大小不變
activation=tf.nn.relu # 使用 Relu 這個啟用函式
) # [28, 28, 32]
# 構建第一層池化層,作用是對第一層卷積後的結果進行降維,獲得池化大小區域內的單個數據進行填充
pool1 = tf.layers.max_pooling2d(
inputs=cover1, # shape [28,28,32]
pool_size=[2, 2], # 設定池化層的大小
strides=2 # 設定池化層的步長
) # shape [14, 14, 32]
# 構建第二層 CNN 模型,卷積層
cover2 = tf.layers.conv2d(
inputs=pool1, # shape is [14, 14, 32]
filters=64, # 採用64個卷積核
kernel_size=[5, 5], # 設定卷積核的大小
strides=1, # 設定卷積的步長
padding="same", # 進行卷積後,大小不變
activation=tf.nn.relu # 使用 Relu 這個啟用函式
) # shape [14, 14, 64]
# 構建第二層池化層,作用是對第二層卷積後的結果進行降維,獲得池化大小區域內的單個數據進行填充
pool2 = tf.layers.max_pooling2d(
inputs=cover2, # shape [14,14,64]
pool_size=[2, 2], # 設定池化層的大小
strides=2 # 設定池化層的步長
) # shape [7, 7, 64]
# 展開第二層池化後的資料,使得其維度為一維陣列
flat = tf.reshape(pool2, [-1, 7 * 7 * 64]) # shape [7*7*64]
# 設定全連線層網路,共有 1024 個神經元,並且採用Relu這個啟用函式
dense = tf.layers.dense(inputs=flat, units=1024, activation=tf.nn.relu)
# 為了避免1024個全連線網路神經元出現過擬合,採用Dropout丟棄掉一半的連線,即rate = 0.5
dropout = tf.layers.dropout(inputs=dense, rate=0.5, training=True)
# 定義最後輸出10個節點,因為是0-9的數字,一共10個
logites = tf.layers.dense(inputs=dropout, units=10) # shape [1*1*10]
# 通過使用 softmax 對所有的預測結果和正確結果進行比較並計算概率,
# 然後再使用交叉熵計算概率密度誤差,也就是我們的損失函式
loss = tf.losses.softmax_cross_entropy(onehot_labels=output_y, logits=logites)
# 採用 Adam 優化器去優化誤差,設定學習率為0.001,能夠更好的進行優化
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
# 計算正確率,正確率的計算步驟:
# 1、對所有的待檢測資料進行識別並與正確的結果進行判斷,返回bool型別;
# 2、將所有的bool結果進行float操作然後求均值,這個均值就是正確率;
# tf.metrics.accuracy() will return (accuracy,update_op)
accuracy = tf.metrics.accuracy(
labels=tf.argmax(output_y, axis=1), # 正確的數字(label)
predictions=tf.argmax(logites, axis=1) # 預測的數字(label)
)[1]
with tf.Session() as sess:
# 初始化區域性和全域性變數
init = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init)
# 儲存tensor圖
tf.summary.FileWriter('./log', sess.graph)
# 定義一共訓練10000次
for i in range(5000):
# 每次的資料從mnist訓練資料集中選取 50 份出來訓練
batch = mnist.train.next_batch(50) # get 50 sample
train_loss, train_op_ = sess.run([loss, train_op], {input_x: batch[0], output_y: batch[1]})
# 每訓練100次列印一次訓練模型的識別率
if i % 100 == 0:
test_accuracy = sess.run(accuracy, {input_x: test_x, output_y: test_y})
print('Step=%d, Train loss=%.6f, [Test accuracy=%.6f]' % (i, train_loss, test_accuracy))
# 最後一次測試:從測試資料集中選取前 20 張圖片進行識別
# 1.利用現在的模型進行預測數字,test_output 形狀是[20,10]
test_output = sess.run(logites, {input_x: test_x[:20]})
# 2.獲取最大可能性的數字,一維直接返回具體值,二維以上返回下標索引
inferenced = np.argmax(test_output, 1)
# 3.列印預測的數字和實際對應的數字
print('inferenced number:')
print(inferenced)
print('Real number:')
print(np.argmax(test_y[:20], 1))
最後你執行可能需要mnist這個資料集,你自己去百度或者官網下載下來,解壓一下就可以。最後附上我的工程結構圖。