TensorFlow Lite模型,云侧训练与安卓端侧推理
引言
本次博客主要基于TensorFlow官网的demo进行学习,把学习过程的心得理解记录。其主要内容为TensorFlow云侧训练深度模型,并转换为手机端lite深度模型,最后在安卓手机端侧利用该模型进行推理得出预测结果。本次学习以mnist数据集为例,毕竟入手深度学习,mnist相当于学习编程语言的Hello World!利用的工具有Anaconda的Jupyter Notebook,和Android Studio。
一、云侧深度模型的训练代码
1.加载数据集的格式分析
import tensorflow as tf
import numpy as np
import os
import matplotlib.pyplot as plt
class MNISTLoader():
def __init__(self):
mnist = tf.keras.datasets.mnist
(self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
# MNIST中的圖片預設為uint8(0-255的數字)。以下程式碼將其正規化到0-1之間的浮點數,並在最後增加一維作為顏色通道
self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1) # [60000, 28, 28, 1]
self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1) # [10000, 28, 28, 1]
self.train_label = self.train_label.astype(np.int32) # [60000]
self.test_label = self.test_label.astype(np.int32) # [10000]
self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
导入TensorFlow和numpy包即可,我们会用到TensorFlow的Keras,它是用 Python 编写的高级神经网络 API,支持快速的构建网络框架。
1.1 从数据集加载的数据格式
先对MNISTLoader这个类进行分析,该类先加载了数据集数据,如下。
(train_data, train_label), (test_data, test_label) = mnist.load_data()
打印数据格式如下。
print("train_data:变量类型={0},变量形状={1},数据类型={2}".format(type(train_data), train_data.shape, train_data.dtype))
print("train_label:变量类型={0},变量形状={1},数据类型={2}".format(type(train_label), train_label.shape,train_label.dtype))
print("test_data:变量类型={0},变量形状={1},数据类型={2}".format(type(test_data), test_data.shape,test_data.dtype))
print("test_label:变量类型={0},变量形状={1},数据类型={2}".format(type(test_label), test_label.shape,test_label.dtype))
打印结果如下。
train_data:变量类型=<class 'numpy.ndarray'>,变量形状=(60000, 28, 28),数据类型=uint8
train_label:变量类型=<class 'numpy.ndarray'>,变量形状=(60000,),数据类型=uint8
test_data:变量类型=<class 'numpy.ndarray'>,变量形状=(10000, 28, 28),数据类型=uint8
test_label:变量类型=<class 'numpy.ndarray'>,变量形状=(10000,),数据类型=uint8
也就是说加载了60000张28×28的图片作为训练集,10000张28×28的图片作为测试集。其中的数据类型为uint8,取值为0~255。
接着又用了np.expand_dims()为图片的数据集进行了维度扩展,axis=-1表示在原来的变量形状的最后一个维度增加多一维,-1在python的索引通常都是表示最后一个索引。为什么要增加这么个维度呢?因为最后一个维度的数值表示图片的通道数。比如图片为RGB图时,最后一个维度的数值是3,而mnist的数据集为灰度图片,即单通道表示的图片,所以最后一个维度数值是1。train_label、test_label的数据则是用0~9表示对应数据集的各个类。
1.2 对加载的数据进行处理
对加载的数据进行的运算,主要包括对图片进行0~1数值的归一化,维度扩展,和数据类型转换;对标签值进行数值类型转换。注意对数值类型转换尤为重要,这跟后续在安卓端编程中需要用到什么数据类型来作为输入输出要对应起来。数据转换的语句如下。
train_data = np.expand_dims(train_data.astype(np.float32) / 255.0, axis=-1)
train_label = train_label.astype(np.int32)
再次运行如下语句查看数据格式
print("train_data:变量类型={0},变量形状={1},数据类型={2}".format(type(train_data), train_data.shape, train_data.dtype))
print("train_label:变量类型={0},变量形状={1},数据类型={2}".format(type(train_label), train_label.shape, train_label.dtype))
得到了新的数据格式,作为最终输入到模型进行训练的数据格式
train_data:变量类型=<class 'numpy.ndarray'>,变量形状=(60000, 28, 28, 1),数据类型=float32
train_label:变量类型=<class 'numpy.ndarray'>,变量形状=(60000,),数据类型=int32
2. 深度模型搭建
用Keras的Sequential来按顺序搭建模型,超级简单。需要添加的神经网络层,只需要add进来就可以了,Keras提供了很多常用的网络层。同时目前最新版本的Keras搭建模型时,每一层(包括首层输入层)的输入会根据上一层的输出自动推断,所以不需要input_shape参数。
model = tf.keras.models.Sequential()
model