【ATU Book-i.MX8系列 - TFLite】Tensorflow Keras 建立手寫識別

一.   概述

上篇文章,說明如何搭建 Tensorflow Keras 環境以及 Keras 使用版本為 2.3.1 。此外,若各位想了解 TF 1.x 與 2.x 的差異,可以前往本系列的其他文章去認識 Tensorflow 1.x 與 2.x 的主要運作模式。本章節將快速帶領初學者使用 Tensorflow 的高階 API – Keras 來搭建手寫辨識 ! 事不宜遲,動手一起體驗吧!! 如下圖所示,為系列博文之示意架構圖。此架構圖隸屬於 i.MX8M Plus 的方案博文中,並屬於 eIQ 機器學習開發環境 內的 推理引擎層(Inference Engines Layer) 的子系列 !! 目前章節介紹 “Tensorflow Keras 建立手寫識別”!! 若欲架設 Tensorflow 1.x 或 2.x 的版本,請參照該系列其他的建立手寫識別章節。

若新讀者欲理解人工智慧、機器學習以及深度學習的差異,可點選查閱下方博文
大大通精彩博文   探討機器學習與深度學習之差異

 

 TFlite 系列博文 - 文章架構示意圖 (1)


 

 

TFlite 系列博文 - 文章架構示意圖 (2)

 

 

二.  Tensorflow Keras  建立手寫識別

使用搭建環境 : Python 3.6 + Windows 10 + Tensorflow 2.1.0 + Keras 2.3.1

本節將介紹如何使用原生 TensorFlow 建立手寫辨識之 CNN 卷積神經網路,並以拆分細節的方式來闡述。
若欲快速建立神經網路或是模組化的撰寫程序,請參照 TensorFlow 的進階 API : Keras、TFLearn、TF-Slim。

(1)  深度學習基礎概念 :

在練習手寫識別之卷積網路前,我們必須簡單地了解一下深度學習的概念,以利於加深印象 !! 所謂的 深度學習(Deep Learning) 是隸屬於人工智能與機器學習的一項新穎知識,隨著運算能力大幅度提升而神經網路的概念受到重用,竟而提倡出「深度」的概念 !! 如下圖所示,白話一點就是不斷利用 卷積(Convolution) 的概念,提取出影像中細節 !! 透過一層一層的提取,也讓資料量不斷增加就如同深度一般 !!

 

深度學習概念示意圖

這裡將深度學習拆分成四大步驟,分別為 收集資料 、建立卷積神經網路架構、訓練卷積神經網路架構、預測結果。建立神經網路的第一步,往往都是收集資料 ( database資料庫) …而初學者不必須要花費心力去收集,僅需要善用網路上或官方提供的資源即可。有了資料後,就可以開始去搭建神經網路架構,對於架構的設計是需要有一定程度的知識理解,這裡建議先學會使用為主,後續再來探討深入細節 !! 在架設好之後,就可以進行神經網路的訓練,這將透過所建立的網路架構與資料去學習圖片中的手寫數字。在訓練之前必須先每張圖片標記上分類 (官方已經標註),也就是常見的 label.txt 檔案!! 利用這些分類定義告知機器什麼是數字 1、數字2 … 而訓練過後所記錄下的分類規則 (權重) 就是所謂的 模組(model)。最後我們就可以使用模組來驗證預測結果是否正確 !!

 

深度學習步驟示意圖

 

 

深度學習四大步驟 :收集資料 、建立卷積神經網路架構、訓練卷積神經網路架構、預測結果

 (2)  收集資料

 下載經典的手寫辨識資料集 MNIST : 


 開啟 Jupyter Notebook 撰寫代碼 : 

#---------------------------------------------------------------------------------------------------------------
# 載入函式庫
#---------------------------------------------------------------------------------------------------------------
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, LeakyReLU, Conv2D
import numpy as np
#---------------------------------------------------------------------------------------------------------------
# 讀取手寫識別數據
#---------------------------------------------------------------------------------------------------------------
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 28,28,1).astype('float32') /255
x_test = x_test.reshape(10000, 28,28,1).astype('float32') /255
print('\nLoading MNIST DataBase\n',
'train number =',x_train.shape[0],"\n", 'test number =', x_test.shape[0],"\n",
'train image shape', x_train.shape,"\n",'label image shape', y_train.shape,"\n",
'train image size', x_train.shape[1]* x_train.shape[2],"\n")


下載完成手寫辨識數據集
 MNIST : 

若顯示以下資訊則代表,下載成功並顯示資料集資訊

 


下載完成 MNIST 數據集之後,下一步須使用 熱編碼 的方式,將標籤轉成特定形式的編碼結構以利於程式運算。

 熱編碼(One-Hot Encoding) : 

One-Hot 熱編碼是種非常有效的方式,以 N 個獨立狀態暫存器來進行編碼。換句話說,假設標籤特徵有 [“男”, “女”, “混合”] 則編碼後會以 [ 100, 010, 001] 來表示其資訊 !! 如同下圖所表示,依序對應的實際標籤為 5、0、4、1、9、2、1、3、1、4 。

 


 延續上一步,進行 獨熱編碼(One-Hot Encoding) 代碼 : 

#---------------------------------------------------------------------------------------------------------------
# 將標籤轉換為 獨熱編碼(One-Hot Encoding)
#---------------------------------------------------------------------------------------------------------------
num_classes = 10
y_train_onehot = keras.utils.to_categorical(y_train, num_classes)
y_test_onehot = keras.utils.to_categorical(y_test, num_classes)​

 

 

(3) 建立卷積神經網路

建立卷積神經網路架構須一步步建立起輸入層、卷積層、池化層、全部連接層、隱藏層、輸出層才能構成神經網路架構,如同下圖所示。而本篇文章只介紹經典的模型架構,細節的架設就不於此探討,這裡強調建立原生 Tenosrflow 1.x 技術,須先以 TensorFlow 靜態圖的概念,建置好架構後即可運作。

 

 

 延續上一步,建立 卷積神經網路架構(CNN) 代碼 : 


Tensorflow Keras 函式使用方式 :
https://keras.io/zh/

#---------------------------------------------------------------------------------------------------------------
# 建立神經網路架構
#---------------------------------------------------------------------------------------------------------------
model = Sequential()
model.add(Conv2D(filters=16,kernel_size=(5,5),padding='same',input_shape=(28,28,1),activation='relu')) #卷積層 convolution layer 1
model.add(MaxPooling2D(pool_size=(2,2))) #池化層 Pool layer 1
model.add(Conv2D(filters=36,kernel_size=(5,5),padding='same',activation='relu')) #卷積層convolution layer 2
model.add(MaxPooling2D(pool_size=(2,2))) #池化層 Pool layer 2
model.add(Dropout(0.25))
model.add(Flatten())# 平坦層 flatten layer
model.add(Dense(128,activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(10,activation='softmax')) #輸出層 output

 

 模組結構 (Model Struction) : 

Keras 提供了一種極為便利的函式可將所建構的模組架構呈現出來。如下圖所示,為上述代碼所建構的神經網路分別由卷積層、最大池化層、平坦層、全部連接層等等建構起來,並顯示每一層的輸出大小,可說對於初學者而言是相當友善的。

 

 

(4)  訓練卷積神經網路

建立卷積神經網路架構後,即可利用訓練數據來訓練神經網路構成模型(Model)

延續上一步,建立 訓練模型 代碼 : 

#---------------------------------------------------------------------------------------------------------------
# 訓練神經網路架構
#---------------------------------------------------------------------------------------------------------------
#最佳化設定 optimizer
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

#開始訓練模型 tranning model
batch_size = 100
epochs = 20
history = model.fit(x_train, y_train_onehot,batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(x_test, y_test_onehot))


 開始訓練 (結果) : 

 

 

(5)  進行手寫識別預測

訓練完成模型後,即可使用測試數據預測結果是否恰當。

 延續上一步,建立 預測模型 代碼 : 

#---------------------------------------------------------------------------------------------------------------
# 顯示訓練過程
#---------------------------------------------------------------------------------------------------------------
import matplotlib.pyplot as plt
def show_train_history(train_history, train, validation):
plt.plot(train_history.history[train])
plt.plot(train_history.history[validation])
plt.title('Train History')
plt.ylabel(train)
plt.xlabel('Epoch')
plt.legend(['train','validation'], loc='upper left')
plt.show()

show_train_history(history,'accuracy','val_accuracy')
show_train_history(history,'loss','val_loss')
#---------------------------------------------------------------------------------------------------------------
# 預測結果
#---------------------------------------------------------------------------------------------------------------
def plot_images_labels_prediction(images,labels,prediction,idx,num=10):
fig = plt.gcf()
fig.set_size_inches(12,14)
images_reshape = images.reshape(images.shape[0], 28,28)
if num>25: num = 25
for i in range(0,num):
ax = plt.subplot(5,5,i+1)
ax.imshow(images_reshape[idx],cmap='binary')
title = "label"+str(labels[idx])
if len(prediction)>0:
title+="predict="+str(prediction[idx])
ax.set_title(title,fontsize=10)
ax.set_xticks([])
ax.set_yticks([])
idx+=1
plt.show()
prediction = model.predict_classes(x_test)
plot_images_labels_prediction(x_test, y_test,prediction, idx=340)


 儲存模組 : 

model.save('./tf2_keras_handwrite.h5')​


繪出損失曲線與準確度 (結果) : 

如下圖所示,為每次訓練過程的準確度與損失曲線的分析,可以發現隨著訓練次數提升,辨識的準確度會越來越高、錯誤率則會越來越低,到最後接近飽和,即表示完成訓練。


預測結果 (結果) : 

觀察圖片上手寫的數字與預測值(predict) 是否相同

 

 

 

三.  結語

相信各位已經成功的建立手寫識別範例並看到預測結果,此實作結果與 Tensorflow 1.x  與 2.x 的結果沒有什麼太大差異,僅有實現方法不同 ( Keras 實現方式最為簡潔、迅速) !! 此礎範例在測試集所的準確度約 98% 左右 !! 預測結果是相當不錯的 !! 若想深度研究仍須要思考測試與訓練資料的樣本、神經網路的架構、學習率、過擬合(Overfitting)、梯度消失等等機器學習會遇到的問題,而本篇系列暫不探討此部分,後續文章將朝輕量化模組的部分前進,以 NXP i.MX8 平台帶領讀者實現 Tensorflow Lite 手寫識別,體驗輕量化網路運算速度 !! 敬請期待 !!

 

 

四.  參考文件

[1] ITREAD    - 從0.1到2.0一文看盡TensorFlow奮鬥史
[2] 軟體之心  - 包裝再升級?Tensorflow 2.0的重大改變
[3] WiKi        -  Keras開源神經網路庫
[4] 科技報橘 -  手機上的輕量版 AI 運算,TensorFlow Lite 問世!
[5] Anaconda - 官方網站
[6] Tensorflow – 官方網站
[7] 深智數位 – Tensorflow 1.x/2.x 完整工程實作
[8] 軟體之心 - 包裝再升級?Tensorflow 2.0的重大改變
[9] iT1邦幫忙 - Tensorflow 的 Eager Mode
[10] 軟體之心 - Keras 手寫辨識 MNIST

如有任何相關 Tensorflow Lite 技術問題,歡迎至博文底下留言提問 !!
接下來還會分享更多 Tensorflow Lite 的技術文章 !!敬請期待 【ATU Book-i.MX8 系列 - TFLite
 !!

 

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論