1. 程式人生 > >Mnist手寫數字識別之CNN實現

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這個資料集,你自己去百度或者官網下載下來,解壓一下就可以。最後附上我的工程結構圖。
在這裡插入圖片描述