基於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 | 神經網路 |