基於CNN的手寫數字識別程序
一、數據准備
訓練及測試數據采用Tensorflow官方提供的MNIST數據集,具體內容如下表所示:
文件 | 內容 |
---|---|
圖片信息 | 大小為28*28的灰度手寫數字圖像,數字從0到9 |
train-images-idx3-ubyte.gz | 訓練集圖片,55000張訓練圖片,5000張驗證圖片 |
train-labels-idx1-ubyte.gz | 訓練集圖片對應的數字標簽 |
t10k-images-idx3-ubyte.gz | 測試集圖片,共10000張 |
t10k-labels-idx1-ubyte.gz | 測試集圖片對應的數字標簽 |
程序中數據導入代碼如下:
from tensorflow.examples.tutorials.mnist import input_data
minst = input_data.read_data_sets('/tmp/data', one_hot=True)
另外也將Tensorflow中一些常用操作封裝成函數,便於調用。
import tensorflow.compat.v1 as tf
#權重W初始化函數
def weight_variable(shape):
initial = tf.truncated_normal(shape=shape, stddev=0.1)
#從標准偏差為0.1的正態分布中截取數值進行初始化
return tf.Variable(initial)
#偏置b初始化函數
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
#值為0.1
return tf.Variable(initial)
二、網絡結構
采用LeNet卷積神經網絡典型結構,結構圖如下:
1.卷積
(1)作用
以若干個卷積核部分覆蓋在輸入圖上,按照設定的步長遍歷輸入圖並進行卷積運算,從而達到提取圖像特征的目的。
(2)卷積核
卷積核一般為尺寸不大於輸入圖的方陣,以符合一定規律的隨機值(如截取自正態分布)進行初始化。本程序設兩次卷積操作,使用的卷積核設定如下:
卷積核 | 尺寸 | 輸入通道數 | 輸出通道數 |
---|---|---|---|
filter_1 | 5*5 | 1 | 32 |
filter_2 | 5*5 | 32 | 64 |
(3)激活
為使分類結果更符合要求,卷積計算后的結果需要再加上偏置b(初始化為0.1)。上述運算均為線性運算。在此之后,采用ReLU非線性函數繼續運算,也就是激活。
(4)程序實現
將上述步驟封裝為一個卷積層函數Conv2d()
#卷積層函數,返回值為卷積特征圖
def Conv2d(image, shape):
#shape為卷積核參數,格式[長,寬,輸入通道數,輸出通道數]
w = weight_variable(shape)
b = bias_variable([shape[3]])
#shape[3]即shape第三維的值,即輸出通道數
res_conv = tf.nn.conv2d(input=image, filter=w, strides=[1,1,1,1], padding='SAME') + b
return tf.nn.relu(res_conv)
其中函數tf.nn.conv2d(input,filter,strides,padding)
是Tensorflow提供的卷積函數,參數說明如下:
-
input,待卷積圖像;
-
filter,卷積核;
-
strides,步長,格式為[1,橫向步長,縱向步長,1]
-
padding,填充圖像邊緣('SAME')/不填充圖像邊緣('VALID')。若填充圖像邊緣,則使得圖像邊緣像素也能成為卷積中心。
2.池化
(1)作用
在輸入特征圖上滑動一個窗口,取窗口中的某些特定數值(如最大值、平均值)構成池化特征圖。池化操作可以概括圖像局部信息,改變特征圖的大小,但不改變其通道數。
(2)池化窗
類似於卷積核,需要設定尺寸和步長。程序中池化操作均采用大小為5*5,步長為1的池化窗。但不作為一個單獨變量,而體現在池化函數的參數中。
(3)程序實現
程序采用最大池化,封裝為一個池化函數MaxPool()
def MaxPool(image):
return tf.nn.max_pool(image, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
實際上只是調用了函數tf.nn.max_pool(image, ksize, strides, padding)
參數說明如下:
-
input,輸入特征圖圖像;
-
ksize,池化窗的大小,取一個四維向量,一般是[1, height, width, 1];
-
strides,步長,格式為[1,橫向步長,縱向步長,1];
-
padding,填充圖像邊緣('SAME')/不填充圖像邊緣('VALID').
3.全連接
(1)作用
對特征圖進行“投票”,從而得到一個特征在各個類別的概率。
(2)扁平化
將經過一系列卷積和池化操作后所得到的特征圖展開成一維,便於全連接。
(3)程序實現
def Flat(input,size):
ori_size = int(input.get_shape()[1])
w = weight_variable(shape = [ori_size, size])
b = bias_variable(shape = [size])
return tf.matmul(input, w) + b
#扁平化
x_flat = tf.reshape(res_pool2, shape=[-1, 7 * 7 * 64])
res_flat = tf.nn.relu(Flat(x_flat, 1024))
#全連接
keep_prob = tf.placeholder(tf.float32)
full1_drop = tf.nn.dropout(res_flat, keep_prob=keep_prob)
#dropout防止過擬合,其中keep_prob為神經元保留率
res_y = Flat(full1_drop, 10)
#輸出分類結果,即0~9共10個標簽