深度學習Hello World --- 手寫體識別 實戰

2020-09-29 11:01:07

最近因為學校事情比較多,也開始準備研究出一些深度學習方面的教學,但總被一些大大小小的原因在往後拖進度,這期用Python寫一篇從零到一的手寫體識別演演算法實戰課來教各位如何入門深度學習。


準備資料集

首先準備一個 mnist 資料集。
這是下載地址
mnist下載位置
四個資料集分別是訓練圖集、訓練結果、測試圖集、測試結果。
下載後存到一個資料夾中備用。


Tensorflow 資料流圖框架

首先先呼叫Python第三方庫,將資料集全部呼叫程序式
(在這裡使用 Tensorflow2.3.0 以及 scipy==1.2.1)

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior() # 這兩句話是為了避免 Tensorflow 1.x與2.x的區別而引起的錯誤
from tensorflow.examples.tutorials.mnist import input_data 
import numpy as np
import os
import scipy.misc

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

先看一下訓練集的圖片的結構

print(mnist.train.images.shape)
# -> (55000, 784) 五萬五千張圖片,每張圖片含有784向量
print(mnist.train.labels.shape)
# -> (55000, 10) 五萬五千張圖片,由0到9展示的十維向量
print(mnist.train.labels[0,:])
# -> [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.] 十個數位組成,表示第一個數為7

標出圖片的位置以及不存在則建立

dir_path = 'mnist/data/'
if not os.path.exists(dir_path):
    os.makedirs(dir_path)

提取其中五張訓練圖作為實驗,檢查訓練結果與訓練圖片的真實對應。

for i in range(5):
    image_array = mnist.train.images[i, :] # 提取第i張圖片
    image_array = image_array.reshape(28,28) # 將圖片轉換為28*28畫素的圖片
    image_file = dir_path + 'mnist_train %d.jpg' % i # 放置圖片的儲存位置和圖片名稱
    scipy.misc.toimage(image_array,cmin=0.0,cmax=1.0).save(image_file) # 下載圖片到本地,基本的圖片格式設定

我們在for迴圈裡面觀察一下image和label對應的輸出。看看訓練集的每張圖片是否對應。

	image_lable = mnist.train.labels[i, :]
    label = np.argmax(image_lable)
    print("image_train %d label is : %d" %(i,label))

首先先定義一下 Tensorflow 中的每個引數的變數。

x = tf.placeholder(tf.float32,[None,784]) # 預留位置表示,第二個引數中第一個值為None代表不固定個數,維數為784
w = tf.Variable(tf.zeros([784,10])) # 定義初始化變數,從784層向量轉化為10層的向量的過程,神經網路一層的結構
b = tf.Variable(tf.zeros([10])) # 偏執向量
y_ = tf.placeholder(tf.float32,[None,10])

# 原理 y = softmax(x*w+b) 
y = tf.nn.softmax(tf.matmul(x, w) + h)

接下來構建損失函數,在這裡使用交叉熵損失函數,這是 Tensorflow 非常經典的已經封裝好的函數,相當於構建真實的Y和輸出的Y值所對應的交叉熵。

# 在這裡labels與logits絕對不能弄混
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y))

梯度下降的迭代使得損失函數最小,在這裡使用隨機梯度下降,設定初始學習速率

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

Tensorflow 對談 Session

在之前的準備工作中,我們僅僅定義了一些 Tensorflow 所必需的一些資料變數,但是我們如果希望 Tensorflow 跑起來的話必須得使用 Tensorflow 的對談工作。在 Session 才是資料真正的開始流,建立之前並沒有真正的資料在裡面。初始化所有的變數。因為資料量比較小,我們迭代一千次梯度下降。讀取batch批次,只有到 Session.run 的時候才是真正的資料跑起來。然後我們定義準確率去檢視準確度大致多少。最終使用 test 測試資料集來驗證準確率的大小。

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    for _ in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})

    curr = tf.equal(tf.argmax(y, 1),tf.argmax(y_, 1))
    acc = tf.reduce_mean(tf.cast(curr,tf.float32))
    print(sess.run(acc,feed_dict={x:mnist.test.images,y_:mnist.test.labels}))
# -> 0.9144

總的來說,Tensorflow 入門級別也並不是很容易,但是每個人都得學的手寫體識別,堪稱神經網路的Hello World演演算法。希望每個大佬都能耐心的學下去,變得更強更禿。


全部程式碼

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
import os
import scipy.misc
mnist = input_data.read_data_sets('mnist',one_hot=True)
dir_path = 'mnist/data/'
if not os.path.exists(dir_path):
    os.makedirs(dir_path)
x = tf.placeholder(tf.float32,[None,784])
w = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y_ = tf.placeholder(tf.float32,[None,10])
y = tf.nn.softmax(tf.matmul(x, w) + b)
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    for _ in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})
    curr = tf.equal(tf.argmax(y, 1),tf.argmax(y_, 1))
    acc = tf.reduce_mean(tf.cast(curr,tf.float32))
    print(sess.run(acc,feed_dict={x:mnist.test.images,y_:mnist.test.labels}))

最後還是希望你們能給我點一波小小的關注。

奉上自己誠摯的愛心💖