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

一.   概述

上篇文章,說明了 Tensorflow 2.x 的基本運算概念以及官方改革推從的 動態圖(Eager) 的設計理念 ! 相信各位是有一定程度的了解,因此本篇就將帶領各位一步步運用動態圖的概念去搭建神經網路架構、訓練模組、最後實現手寫識別 !! 趕快跟上 AI 潮流,開啟 Jupyter Notebook 來實作吧 !! 如下圖所示,為系列博文之示意架構圖。此架構圖隸屬於 i.MX8M Plus 的方案博文中,並屬於 eIQ 機器學習開發環境 內的 推理引擎層(Inference Engines Layer) 的子系列 !! 目前章節介紹 “Tensorflow 2. x 建立手寫識別”!!  若欲架設 1.x 的版本,請參照該系列其他的建立手寫識別章節。

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

 

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

 

 

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

 

二.  Tensorflow 2.x  建立手寫識別

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

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

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

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

 

深度學習概念示意圖

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

 

深度學習步驟示意圖

 

 

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

 (2)  收集資料

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

 


 開啟 Jupyter Notebook 撰寫代碼 : 

#---------------------------------------------------------------------------------------------------------------
# 讀取手寫識別數據
#---------------------------------------------------------------------------------------------------------------
import tensorflow as tf
import tensorflow.keras.layers as layers
import numpy as np
import os
from MNIST_data import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot = True)
print('\nLoading MNIST DataBase\n',
'train number=',mnist.train.num_examples,"\n", 'vakidation number=',mnist.validation.num_examples,"\n",
'test number=',mnist.test.num_examples,"\n", 'train image shape', mnist.train.images.shape,"\n",
'label image shape', mnist.train.labels.shape,"\n", 'train image size' , mnist.train.images[0].size,"\n")

***  Tensorflow 2.x 版本已合併 Keras API ,故以下所介紹的範例部分會用到 Keras 的代碼。 


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

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


 

 

 

(3)  建立卷積神經網路

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

 


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

Tensorflow 2.x 函式使用方式 : https://www.tensorflow.org/api_docs/python/tf/keras

#---------------------------------------------------------------------------------------------------------------
# 建立 卷積神經網路(動態圖)
#---------------------------------------------------------------------------------------------------------------
inputs_ = layers.Input(shape=(28, 28, 1)) #輸入層 input layer
C1_Conv = layers.Conv2D(filters=16,kernel_size=5, activation='relu')(inputs_)#卷積層 convolution layer 1
C1_Pool = layers.MaxPooling2D(2, 2)(C1_Conv) #池化層 pool layer 1
C2_Conv = layers.Conv2D(32, 5, activation = tf.nn.relu)(C1_Pool) #卷積層 convolution layer 2
C2_Pool = layers.MaxPooling2D(2, 2)(C2_Conv) #池化層 pool layer 2
flat1 = layers.Flatten()(C2_Pool) #平坦層 flatten layer (將多個維度的輸入壓平成一個維度)
Dense1 = layers.Dense((7*7*36), activation = tf.nn.relu)(flat1) #全部連階層 fully connnected layer
Dropout = layers.Dropout(0.3)(Dense1)
outputs = layers.Dense(10, activation="softmax")(Dropout) #輸出層 output layer
model = tf.keras.Model(inputs=inputs_, outputs=outputs)

 

 

(4)  訓練卷積神經網路

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

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

 

#---------------------------------------------------------------------------------------------------------------
# 建立卷積神經網路(訓練模型)
#---------------------------------------------------------------------------------------------------------------
#設定訓練網路(函式、變數)
optimizer = tf.keras.optimizers.Adam() #最佳化設定 optimizer
loss_object = tf.keras.losses.SparseCategoricalCrossentropy() #損失函數
train_loss = tf.keras.metrics.Mean(name='train_loss')
test_loss = tf.keras.metrics.Mean(name='test_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy') #準確度
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')

@tf.function #啟動 Auto Graph
def train_step(image, label):
with tf.GradientTape() as tape:
predictions = model(image) #計算準確度
loss = loss_object(label, predictions) #計算損失
gradients = tape.gradient(loss, model.trainable_variables) #利用 GrudientTape 紀錄梯度資訊
optimizer.apply_gradients(zip(gradients, model.trainable_variables)) #梯度最佳化
train_loss(loss)
train_accuracy(label, predictions)

@tf.function #啟動Auto Graph
def test_step(images, labels):
predictions = model(images) #計算準確度
t_loss = loss_object(labels, predictions) #計算損失
test_loss(t_loss)
test_accuracy(labels, predictions)

#讀取資料庫
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

#建構訓練資料
x_train = x_train.astype(np.float32).reshape(-1, 28, 28) #調整資料大小
x_train = np.expand_dims(x_train, axis=3) #擴展資料
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(128) #拆分批次資料
#建構測試資料
x_test = x_test.astype(np.float32).reshape(-1, 28, 28) #調整資料大小
x_test = np.expand_dims(x_test, axis=3) #擴展資料
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = test_dataset.batch(128) #拆分批次資料

#開始訓練模型 tranning model
epoch_list=[];accuracy_list=[];loss_list=[];
for epoch in range(20):
for image, label in train_dataset:
train_step(image, label)

for test_images, test_labels in test_dataset:
test_step(test_images, test_labels)

template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}\n'
print(template.format(epoch+1, train_loss.result(), train_accuracy.result(),
test_loss.result() , test_accuracy.result()))

epoch_list.append(epoch)
loss_list.append(format(train_loss.result()))
accuracy_list.append(format(train_accuracy.result()))

# Reset the metrics for the next epoch
train_loss.reset_states()
train_accuracy.reset_states()
test_loss.reset_states()
test_accuracy.reset_states()


開始訓練 (結果) : 


 

 

(5)  進行手寫識別預測

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

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

 

#---------------------------------------------------------------------------------------------------------------
# 預測結果
#---------------------------------------------------------------------------------------------------------------
import matplotlib.pyplot as plt

def plt_mnist(x, y, plt_num=5):
plt.figure(figsize=(8,8))
for index, (image, label) in enumerate(zip(x[0:plt_num], y[0:plt_num])):
plt.subplot(2, 3, (index+1))
plt.imshow(np.reshape(image, (28,28)), cmap=plt.cm.gray)
plt.title('{}: label: {}\n'.format('Predict', label), fontsize = 10)

predict_ = model.predict(x_test)
predict = [tf.argmax(e).numpy() for e in predict_]
plt_mnist(x_test, predict)


儲存模組 : 

 

tf.saved_model.save( model, "Tensorflow_2_HandWrite" )


預測結果 (結果) : 

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

 

 

三.  結語

依上述介紹,即可開始建立 Tensorflow 2.x 手寫識別範例 並看到預測結果,此實作結果與 Tensorflow 1.x 的結果沒有什麼太大差異,僅有實現方法不同 !! 而此範例在測試集所呈現的準確度約 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

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


 

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

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

評論