【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次,发文人进小黑屋喔~

评论