基於tensorflow的手寫數字識別

基於tensorflow的手寫數字識別

來自專欄移動公司數據分析

之前在github上找了個人臉識別的項目自己做了下,算是嘗試了下CNN卷積神經網路,但是一直對卷積 池化 權值共享沒有很深的了解,今天有時間認認真真把CNN的整個過程好好學習推導了下,受益匪淺。順手就把之前課程裡面的一個項目拿出來練練手,識別手寫數字,挺有意思的。

下面先介紹下卷積,這塊我一直沒理解透,這次在CSDN上看了cheney康的文章才理解的比較透徹。

1、什麼是卷積:圖像中不同數據窗口的數據和卷積核(一個濾波矩陣)作內積的操作叫做卷積。其計算過程又稱為濾波(filter),本質是提取圖像不同頻段的特徵。

2、什麼是卷積核:也稱為濾波器filter,帶著一組固定權重的神經元,通常是n*m二維的矩陣,n和m也是神經元的感受野。n*m 矩陣中存的是對感受野中數據處理的係數。一個卷積核的濾波可以用來提取特定的特徵(例如可以提取物體輪廓、顏色深淺等)。通過卷積層從原始數據中提取出新的特徵的過程又成為feature map(特徵映射)。filter_size是指filter的大小,例如3*3; filter_num是指每種filter_size的filter個數,通常是通道個數

3、什麼是卷積層:多個濾波器疊加便成了卷積層。

4、一個卷基層有多少個參數:一個卷積核使用一套權值以便」掃視』數據每一處時以同樣的方式抽取特徵,最終得到的是一種特徵。 在tensorflow定義conv2d時需要指定卷積核的尺寸,本人現在的理解是一個卷積層的多個卷積核使用相同的m*n, 只是權重不同。 則一個卷積層的參數總共m*n*filter_num個,比全連接少了很多。

5、通道(chennel)怎麼理解:通道可以理解為視角、角度。例如同樣是提取邊界特徵的卷積核,可以按照R、G、B三種元素的角度提取邊界,RGB在邊界這個角度上有不同的表達;再比如需要檢查一個人的機器學習能力,可以從特徵工程、模型選擇、參數調優等多個方面檢測

6、計算例子:

解析:圖中input 7*7*3中,7*7代表圖像的像素/長寬,3代表R、G、B 三個顏色通道,可以看到周邊有填充0; 有兩個卷積核Filter w0、Filter w1,每個filter對應每個通道有一組w權重;一個filter滑動到一個位置後計算三個通道的卷積,求和,加bias,得到這個filter在該位置的最終結果;每個filter的輸出是各個通道的匯總;輸出的個數與filter個數相同。所以最右邊能得到兩個不同的輸出。

1的計算過程:

第一個通道和對應權重的結果:0*1+0*1+0*(-1)+0*(-1)+0*0+1*1+0*(-1)+0*(-1)+1*0 = 1

第二個通道和對應權重的結果:0*(-1)+0*0+0*(-1)+0*0+1*0+1*(-1)+0*1+0*(-1)+2*0 = -1

第三個通道和對應權重的結果:0*0+0*1+0*0+0*1+2*0+0*1+0*0+0*(-1)+0*0 = 0

偏置:1

1+(-1)+ 0 + 1 = 1

主要就是這個卷積的過程,這塊最難了。池化相對來說簡單一些。

圖形識別這塊真的非常非常耗費資源,我的電腦沒有獨立GPU,都是基於CPU的,用TF運算速度上不去,這個小項目下載的圖片庫里有5萬張圖片,我選了3000張,訓練次數我只選擇了200次,初始2萬次我算了一個小時沒出結果,改成200次幾分鐘就出來了,結果果然不夠精準,有識別錯誤哈哈。

下面貼代碼和運行結果:

# -*- coding: UTF-8 -*-

import numpy as np

import tensorflow as tf

# 下載並載入 MNIST 手寫數字型檔(55000 * 28 * 28)55000 張訓練圖像

from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets(mnist_data, one_hot=True)

# one_hot 獨熱碼的編碼(encoding)形式

# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 的十位數字

# 0 : 1000000000

# 1 : 0100000000

# 2 : 0010000000

# 3 : 0001000000

# 4 : 0000100000

# 5 : 0000010000

# 6 : 0000001000

# 7 : 0000000100

# 8 : 0000000010

# 9 : 0000000001

# None 表示張量(Tensor)的第一個維度可以是任何長度

input_x = tf.placeholder(tf.float32, [None, 28 * 28]) / 255. # 輸入

output_y = tf.placeholder(tf.int32, [None, 10]) # 輸出:10個數字的標籤

input_x_images = tf.reshape(input_x, [-1, 28, 28, 1]) # 改變形狀之後的輸入

# 從 Test(測試)數據集里選取 3000 個手寫數字的圖片和對應標籤

test_x = mnist.test.images[:3000] # 圖片

test_y = mnist.test.labels[:3000] # 標籤

# 構建我們的卷積神經網路:

# 第 1 層卷積

conv1 = tf.layers.conv2d(

inputs=input_x_images, # 形狀 [28, 28, 1]

filters=32, # 32 個過濾器,輸出的深度(depth)是32

kernel_size=[5, 5], # 過濾器在二維的大小是(5 * 5)

strides=1, # 步長是1

padding=same, # same 表示輸出的大小不變,因此需要在外圍補零 2 圈

activation=tf.nn.relu # 激活函數是 Relu

) # 形狀 [28, 28, 32]

# 第 1 層池化(亞採樣)

pool1 = tf.layers.max_pooling2d(

inputs=conv1, # 形狀 [28, 28, 32]

pool_size=[2, 2], # 過濾器在二維的大小是(2 * 2)

strides=2 # 步長是 2

) # 形狀 [14, 14, 32]

# 第 2 層卷積

conv2 = tf.layers.conv2d(

inputs=pool1, # 形狀 [14, 14, 32]

filters=64, # 64 個過濾器,輸出的深度(depth)是64

kernel_size=[5, 5], # 過濾器在二維的大小是(5 * 5)

strides=1, # 步長是1

padding=same, # same 表示輸出的大小不變,因此需要在外圍補零 2 圈

activation=tf.nn.relu # 激活函數是 Relu

) # 形狀 [14, 14, 64]

# 第 2 層池化(亞採樣)

pool2 = tf.layers.max_pooling2d(

inputs=conv2, # 形狀 [14, 14, 64]

pool_size=[2, 2], # 過濾器在二維的大小是(2 * 2)

strides=2 # 步長是 2

) # 形狀 [7, 7, 64]

# 平坦化(flat)

flat = tf.reshape(pool2, [-1, 7 * 7 * 64]) # 形狀 [7 * 7 * 64, ]

# 1024 個神經元的全連接層

dense = tf.layers.dense(inputs=flat, units=1024, activation=tf.nn.relu)

# Dropout : 丟棄 50%, rate=0.5

dropout = tf.layers.dropout(inputs=dense, rate=0.5)

# 10 個神經元的全連接層,這裡不用激活函數來做非線性化了

logits = tf.layers.dense(inputs=dropout, units=10) # 輸出。形狀[1, 1, 10]

# 計算誤差(計算 Cross entropy(交叉熵),再用 Softmax 計算百分比概率)

loss = tf.losses.softmax_cross_entropy(onehot_labels=output_y, logits=logits)

# Adam 優化器來最小化誤差,學習率 0.001

train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

# 精度。計算 預測值 和 實際標籤 的匹配程度

# 返回(accuracy, update_op), 會創建兩個局部變數

accuracy = tf.metrics.accuracy(

labels=tf.argmax(output_y, axis=1),

predictions=tf.argmax(logits, axis=1),)[1]

# 創建會話

sess = tf.Session()

# 初始化變數:全局和局部

init = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())

sess.run(init)

for i in range(200):

batch = mnist.train.next_batch(50) # 從 Train(訓練)數據集里取「下一個」 50 個樣本

train_loss, train_op_ = sess.run([loss, train_op], {input_x: batch[0], output_y: batch[1]})

if i % 100 == 0:

test_accuracy = sess.run(accuracy, {input_x: test_x, output_y: test_y})

print(("Step=%d, Train loss=%.4f, [Test accuracy=%.2f]")

% (i, train_loss, test_accuracy))

# 測試:列印 20 個預測值 和 真實值 的對

test_output = sess.run(logits, {input_x: test_x[:20]})

inferenced_y = np.argmax(test_output, 1)

print(inferenced_y, Inferenced numbers) # 推測的數字

print(np.argmax(test_y[:20], 1), Real numbers) # 真實的數字

print("程序結束")

輸出結果:

Step=0, Train loss=2.2997, [Test accuracy=0.17]

Step=100, Train loss=0.1835, [Test accuracy=0.56]

[7 2 1 0 4 1 4 9 5 9 0 6 9 0 1 5 9 7 5 4] Inferenced numbers

[7 2 1 0 4 1 4 9 5 9 0 6 9 0 1 5 9 7 3 4] Real numbers

程序結束


推薦閱讀:

TensorFlow | TF修鍊手冊(六)——批標準化與梯度剪裁
淺入淺出TensorFlow 4 - 訓練CIFAR數據
TensorFlow-線性回歸
TensorFlow分散式訓練加速之梯度壓縮
TensorFlow.js tutorial(1)簡介與安裝

TAG:TensorFlow | 深度學習DeepLearning | 神經網路 |