AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

AI on Android:安卓平台上的人工智能应用实战(01.环境的搭建):https://blog.csdn.net/NJP_NJP/article/details/88366318

上一篇我们介绍了Windows10x64系统平台上的环境搭建过程,其他系统环境的待见过程很类似,具体请查看各个官网。搭建好了环境之后我们就来使用我们的工具来完成一个图像分类模型的再训练过程。

推荐官方教程:https://tensorflow.google.cn/hub/tutorials/image_retraining

官网上关于模型的再训练过程讲解的很详细,想深入了解原理的同学推荐可以去官网阅读一下。

第一步:克隆Github项目到本地

为了更好地帮助大家学习和实践,我将官方的实例代码整合并修改了一下:https://github.com/NaJiPeng/AI-On-Android.git

项目中有两个文件夹:retrain和tflite,retrain是我们再训练模型时要用到的,tflite是我们将模型接入Android应用中要用到的。

retrain项目中有两个.py文件,retrain.py是用来再训练模型的,label_image.py是用来测试我们训练好的模型的。项目文件中还有一个flower_photos目录,其中还有几个以花的名称命名的子目录,子目录中就是用来训练模型的各个种类的花的图片了。

tflite项目是一个Android项目,项目结构与正常的Android项目一致就不多做介绍了。值得注意的是在assets目录中有三个文件:BUILD文件,graph.lite文件和labels.txt文件,其中决定图像识别结果的就是graph.lite文件,模型运作时模型加载器会加载这个.lite文件,再通过labels.txt的标签列表将图像识别结果转换成我们可以看得懂的形式输出。

我们将项目克隆到本地之后就可以进行下一步啦。

第二步:执行模型再训练过程

在运行retrain.py之前我们先打开项目看看代码:选中retrain文件夹,鼠标右键选中“Open Folder as a PyCharm Community Edition Project”,用PyCharm打开项目,接着打开retrain.py查看代码(如果提示错误别忘记更改项目的Python解释器,具体步骤见上一篇文章)。

AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

为了方便调试与修改,我将脚本中可能会用到的参数抽取成了一个参数列表放在了retrain.py的文件头部:

# 参数配置列表:

# 所需图片的文件夹
IMAGE_DIR = "flower_photos"
# 训练完成的graph的保存位置
OUTPUT_GRAPH = "flower_output/graph.pb"
# 多少步保存一次中间graph,0表示不保存中间graph
INTERMEDIATE_STORE_FREQUENCY = 0
# 中间graph的保存位置
INTERMEDIATE_OUTPUT_GRAPHS_DIR = "flower_output/intermediate_graph/"
# 标签列表文件的保存位置
OUTPUT_LABELS = "flower_output/labels.txt"
# TensorBoard摘要文件的保存位置(TensorBoard可用于可视化训练过程)
SUMMARIES_DIR = "flower_output/retrain_logs"
# 检查点名称
CHECKPOINT_NAME = "flower_output/_retrain_checkpoint"
# 训练步数
HOW_MANY_TRAINING_STEPS = 4000
# 学习率
LEARNING_RATE = 0.01
# 要用作测试集的图像的百分比
TESTING_PERCENTAGE = 10
# 要用作验证集的图像的百分比
VALIDATION_PERCENTAGE = 10
# 多少步评估一次训练结果
EVAL_STEP_INTERVAL = 10
# 一次训练多少个图像
TRAIN_BATCH_SIZE = 100
# 用多少个图像评估最终结果,-1表示应用整个验证集
TEST_BATCH_SIZE = -1
# 每次验证评估用多少个图像
VALIDATION_BATCH_SIZE = 100
# 是否打印错误分类的图像列表
PRINT_MISCLASSIFIED_TEST_IMAGES = False
# 瓶颈层缓存位置
BOTTLENECK_DIR = "flower_output/bottleneck"
# 输出层的名称
FINAL_TENSOR_NAME = "final_result"
# 是否允许左右翻转图像
FLIP_LEFT_RIGHT = False
# 随机剪裁图像的百分比
RANDOM_CROP = 0
# 随机缩放图像的百分比
RANDOM_SCALE = 0
# 随机调亮度的百分比
RANDOM_BRIGHTNESS = 0
# 选用的训练模型
TFHUB_MODULE = 'https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/feature_vector/1'
# 保存模型文件夹
SAVED_MODEL_DIR = ""

每个参数都有它特定的含义,改变这些参数可能会影响最终的训练模型结果。

IMAGE_DIR参数就是我们事先准备好的数据集,数据集必须事先已经被分好类了,并且子目录的名称就决定了这个类别的label。模型的最终输出结果由graph.lite和label.txt表示,这两个文件的保存位置由OUTPUT_GRAPH和OUTPUT_LABELS配置。SUMMARIES_DIR表示的是TensorBoard摘要文件的保存位置,稍后我们在训练模型的过程中可以通过命令行来启用训练过程可视化工具,通过图像的形式直观地观察训练过程的参数变化情况。

接下来是一些对训练过程的有影响的参数:HOW_MANY_TRAINING_STEPS表示训练总步数,这里用默认的4000步;LEARNING_RATE表示学习率,也就是模型学习的速度,这个数值过大会导致模型不收敛,这里使用较小的0.01;TESTING_PERCENTAGE表示你的数据集中有百分之多少用作测试集,VALIDATION_PERCENTAGE表示你的数据集中有百分之多少用作验证集,这两个参数就将你准备的数据集分成了三部分:训练集、验证集、测试集,训练集用来拟合模型和数据,验证集用来调整模型的超参数,测试集只是用来评估模型的工作效果;TRAIN_BATCH_SIZE表示每一步“喂给”模型的训练集图像个数,这里使用默认的100;

EVAL_STEP_INTERVAL、TEST_BATCH_SIZE、VALIDATION_BATCH_SIZE、PRINT_MISCLASSIFIED_TEST_IMAGES表示与验证过程相关的参数,这里不多说了,注释很详细。

BOTTLENECK_DIR表示瓶颈层缓存位置,瓶颈是为了提高训练过程速度设计的,训练刚开始时首先不会直接把图像喂给模型进行拟合,而是先为每一个图像数据创建一个瓶颈缓存,等所有瓶颈缓存创建完成后再进行训练过程,训练时不直接去读取原始图像数据而是去读取这个瓶颈缓存数据,这样可以大大地提高模型训练的速度。

FLIP_LEFT_RIGHT表示在训练模型的过程中,是否会随机对你的图片进行左右翻转;RANDOM_CROP、RANDOM_SCALE、RANDOM_BRIGHTNESS这些参数表示会在训练模型的过程中,会随机地对你的图像集合中的图像进行剪裁、缩放、亮度调整的程度。这样做的目的是使你每次喂给模型的图像都是不同的,这在某种程度上就扩大了你的数据集,启用这些功能的代价就是瓶颈缓存将不再起作用,训练的速度将大大降低,这里为了保证训练过程的速都就全部停用以上功能了。注意:FLIP_LEFT_RIGHT功能对于有些模型的训练不适合,比如手写数字的识别或者字母的识别等,左右翻转图像之后将失去图像的本身意义;而RANDOM_CROP、RANDOM_SCALE、RANDOM_BRIGHTNESS这些参数一般不易过大,取5~10%比较合适。

TFHUB_MODULE表示你训练所使用的模型,tfhub上提供了许多图像识别模型供你选择,不同的模型准确率和响应时间不同,一般来说速度越快的模型越不准确,你需要在速度和准确性之间权衡一下,想要替换模型只需要把对应的地址复制到TFHUB_MODULE处即可,本例子使用的是mobilenet_v1模型。关于模型详情见:https://tfhub.dev/s?module-type=image-feature-vector

配置好这些参数之后我们来运行retrain.py脚本,来执行模型的再训练过程。运行开始之后会在窗口中打印各种训练过程中的各种信息。首先会为每个图片创建瓶颈缓存,窗口中会打印每个图像的瓶颈缓存文件创建过程。之后会正式开始模型的训练过程,在窗口中会打印训练步数、交叉熵、训练集准确度、验证集准确率这些信息(交叉熵用来表示预测的概率结果与真实情况的偏差的大小)。一般来说随着训练步数的增加交叉熵会不断降低,准确度会不断上升。

接着在一旁的Terminal窗口中输入命令:

tensorboard --logdir flower_output/retrain_logs

启动训练可视化工具tensorboard,接着用浏览器打开窗口中打印出的地址,你会看到训练过程的准确度与交叉熵的实时变化过程的折线图:

AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

接着就静静等待训练过程的结束吧。

第三步:验证训练好的模型

训练完成之后我们会看到retrain目录下多了一个flower_output文件夹,其中有graph.pd和labels.txt文件,这两个文件就可以表示我们训练好的模型了。

我们打开label_image.py文件,同样的文件头部有一个参数列表:

# 参数配置列表:

# 验证图片文件
IMAGE = "flower_photos/daisy/5547758_eea9edfd54_n.jpg"
# graph文件
GRAPH = "flower_output/graph.pb"
# labels文件
LABELS = "flower_output/labels.txt"
# 输入图像高度
INPUT_HEIGHT = 224
# 输入图像宽度
INPUT_HEIGHT = 224
# 输入像素数据的均值
INPUT_MEAN = 0
# 输入像素数据的标准值
INPUT_STD = 255
# 输入层名称
INPUT_LAYER = "Placeholder"
# 输出层名称
OUTPUT_LAYER = "final_result"

IMAGE表示要识别的图片路径,这里就先取一张训练集里面的雏菊图片,GRAPH指的是生成的.pd文件路径;LABELS指的是生成的.txt文件路径;

INPUT_HEIGHT和INPUT_HEIGHT分别表示模型图像输入的高度和宽度。这个跟你所选取的模型有关,每种模型的输入图像尺寸可能不同,具体的详见:https://tfhub.dev/s?module-type=image-feature-vector

INPUT_MEAN和INPUT_STD一般取默认值;

INPUT_LAYER和OUTPUT_LAYER表示输入输出层的名称,这里输入层为Placeholder,输出层在retrain.py里我们指定为了final_result。

接着我们可以运行label_image.py的脚本来看看模型的效果,右键Run label_image.py,接着你会看到在窗口中会打印出模型的预测结果,也就是各种花的种类的可能性:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)可以看到模型预测此图片为雏菊的概率为99.98%以上。接着我们随便从网上找了一张向日葵的照片:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

接着我们把图片sunflower.jpg复制到retrain目录下,然后更改IMAGE=“sunflower.jpg”,再次运行脚本:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)可以看到sunflowers的概率有99.91%以上,说明我们的模型工作的非常好,也可以多找一些照片来测试,方法与上诉步骤一致,这里就不多说了,大家可以自己试一试。

第四步(可选):训练属于自己的模型

上面已经介绍了完了整个模型的再训练过程,我们不妨照猫画虎训练一个自己感兴趣的图像分类模型出来(这里训练一个能简单分辨小动物的模型)。

1.获取图片数据:

网络上有许多专门搜索图片或者壁纸的网站,我们可以从这些网站上获取我们的图像数据来训练我们的模型。从网络上获取的海量图片如果一个一个下载的话不知道要下载到什么时候,如果你懂的一些爬虫的知识的话也可以自己编写一个爬虫从网络上爬取你想要的数据来训练你的模型。但是大多Android工程师可能没有接触过这方面的知识(比如我),这里我们就使用一个好用的图片批下载工具来代替爬虫吧,这个工具叫Image Downloader,是Chrome浏览器的一个插件,我们可以在Chrome应用商店里免费下载:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

接着打开壁纸搜索网站:https://alpha.wallhaven.cc/

由于我们打算训练一个能简单分辨小动物的模型,所以我们先搜索:cat

AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

我们取消选定”Anime“和”People“过滤项,接着选中"SFW"过滤项,防止出现”不好的图片“。排列方式选择”Random“保证每次刷新会出现新的壁纸图片。接着我们下拉加载几页之后,点击右上角的Image Downloader插件,我们将插件中的宽高限定最小宽度300px,最小高度200px,确保下载的图片都是壁纸(不是Logo之类的),接着输入文件夹名称:cat,勾选”select all“,点击download下载所有图片。下载时会一直弹出下载提示,不过问题不大,我们可以继续刷新页面继续下载新的一批图片,直到”cat“图片下载到1000左右。AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

接着我们用同样的方法下载”dog“,”fox“:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

接着我们把这三个文件夹放在”animals_photos“文件夹中,并移动到”retrain“目录下,至此图片搜集工作就完成了。

2.模型再训练:

修改retrain.py文件:

# 参数配置列表:

# 所需图片的文件夹
IMAGE_DIR = "animals_photos"
# 训练完成的graph的保存位置
OUTPUT_GRAPH = "animals_output/graph.pb"
# 多少步保存一次中间graph,0表示不保存中间graph
INTERMEDIATE_STORE_FREQUENCY = 0
# 中间graph的保存位置
INTERMEDIATE_OUTPUT_GRAPHS_DIR = "animals_output/intermediate_graph/"
# 标签列表文件的保存位置
OUTPUT_LABELS = "animals_output/labels.txt"
# TensorBoard摘要文件的保存位置(TensorBoard可用于可视化训练过程)
SUMMARIES_DIR = "animals_output/retrain_logs"
# 检查点名称
CHECKPOINT_NAME = "animals_output/_retrain_checkpoint"
# 训练步数
HOW_MANY_TRAINING_STEPS = 4000
# 学习率
LEARNING_RATE = 0.01
# 要用作测试集的图像的百分比
TESTING_PERCENTAGE = 10
# 要用作验证集的图像的百分比
VALIDATION_PERCENTAGE = 10
# 多少步评估一次训练结果
EVAL_STEP_INTERVAL = 10
# 一次训练多少个图像
TRAIN_BATCH_SIZE = 100
# 用多少个图像评估最终结果,-1表示应用整个验证集
TEST_BATCH_SIZE = -1
# 每次中间过程评估用多少个图像
VALIDATION_BATCH_SIZE = 100
# 是否打印错误分类的图像列表
PRINT_MISCLASSIFIED_TEST_IMAGES = False
# 瓶颈层缓存位置
BOTTLENECK_DIR = "animals_output/bottleneck"
# 输出层的名称
FINAL_TENSOR_NAME = "final_result"
# 是否允许左右翻转图像
FLIP_LEFT_RIGHT = False
# 随机剪裁图像的百分比
RANDOM_CROP = 0
# 随机缩放图像的百分比
RANDOM_SCALE = 0
# 随机调亮度的百分比
RANDOM_BRIGHTNESS = 0
# 选用的训练模型
TFHUB_MODULE = 'https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/feature_vector/1'
# 保存模型文件夹
SAVED_MODEL_DIR = ""

将图像目录和目标目录都改成animals…接着运行retrain.py,接下来静静地等待训练完成或者打开可视化界面都可以。

3.模型验证:

百度一张二哈的照片:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)再百度张波斯猫的照片:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

再百度张赤狐的照片:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

将照片放在retrain目录下,然后更改label_mage.py的参数:

# 参数配置列表:

# 验证图片文件
IMAGE = "dog.jpg"
# graph文件
GRAPH = "animals_output/graph.pb"
# labels文件
LABELS = "animals_output/labels.txt"
# 输入图像高度
INPUT_HEIGHT = 224
# 输入图像宽度
INPUT_WIDTH = 224
# 输入像素数据的均值
INPUT_MEAN = 0
# 输入像素数据的标准值
INPUT_STD = 255
# 输入层名称
INPUT_LAYER = "Placeholder"
# 输出层名称
OUTPUT_LAYER = "final_result"

接着运行label_mage.py参看运行结果:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

更改 IMAGE = “cat.jpg”,运行,查看结果:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

更改 IMAGE = “fox.jpg”,运行,查看结果:AI on Android:安卓平台上的人工智能应用实战(02.模型的再训练)

可以看到模型可以将这三种动物准确的分辨出来。