参与 | zzq
审校 | reason_W
我们知道,TensorFlow是一个深度学习框架,它通常用来在服务器上训练需要大量数据的大模型。随着智能手机的普及,人们也越来越注意到手机这个巨大的新兴市场,这个市场未来的发展同样也需要人工智能。过去的几年,市场上涌现出了很多热爱机器学习并且愿意迫切推动人工智能发展的人,而现在他们已经开始向手机这个数万亿美元的市场砸钱了。
而能够在智能手机上运行TensorFlow的工具也已经被开发了出来。你是否也曾想过自己在手机上训练一个深度学习模型呢?如果你手边正好有一部Android或者iOS系统的手机的话,那刚好可以跟着这篇教程来做。
下面我将给出两个教程,一个是在安卓系统运行机器学习模型的方法,另一个则是在ios设备上运行机器学习模型的方法。
我们以在手机上实现一个图像分类功能为例。总体思路十分简单:首先使用Inception-v3模型,只对它的最后一层重新训练,然后对模型进行优化,最后嵌入到手机设备上就可以使用了。
在本教程中,ios设备需要6步,而安卓设备仅需要5步,我们将首先介绍这两种设备中相同的前三步,然后分别介绍之后的步骤。
首先,我们需要在电脑或者服务器上先使用TensorFlow创建好一个模型。因为本文是在手机上使用TensorFlow的教程,所以我就假设你已经熟练掌握创建模型这一步了。
没有掌握也没有关系,我推荐给你一个快速入门的教程如何利用用户图像在CPU上训练Inception模型
(https://towardsdatascience.com/training-inception-with-tensorflow-on-custom-images-using-cpu-8ecd91595f26)。
好了,回到本文,我们现在就得到一个已经训练好的模型了。
我们以花为例,在训练模型时,使用的数据:包括郁金香、雏菊、向日葵、蒲公英和玫瑰。当然你也可以使用其它种类的数据对模型进行训练。
之后,你会得到两个文件。首先是对所选网络最后一层重新训练以后的模型版本:
之后,你会得到两个文件。首先是对所选网络最后一层重新训练以后的模型版本:
tf_files/retrained_graph.pb
然后是一个包含类别标签的文本文件:
tf_files/retrained_labels.txt
运行下面的命令行(请确保路径是正确的)
python -m tensorflow.python.tools.optimize_for_inference \
--input=tf_files/retrained_graph.pb \
--output=tf_files/optimized_graph.pb \
--input_names="input" \
--output_names="final_result"
这将创建一个新的优化模型文件
tf_files/optimized_graph.pb
折中方案
为了减少应用程序中需要进行的预处理工作,同时也为了降低库的大小,TensorFlow只支持在推理过程中常用到的操作子集。不支持的操作过程可以查看这个链接。
(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/makefile/tf_op_files.txt)
现在,我们只要需要刚刚创建的图文件包含后面的操作就行了。
校验
为了确保之前创建的新的优化图能够正常运行,同时也为了移除optimize_for_inference文件中多余的输入和输出节点——这些节点不会改变网络的输出,我们需要进行校验。
使用图retrained_graph.pb和optimized_graph.pb中的label_file对相同的输出图像进行对比:
retrained_graph.pb使用如下指令
python -m scripts/label_image \
--graph=tf_files/retrained_graph.pb\
--image=tf_files/flower_photos/daisy/3475870145_685a19116d.jpg
optimized_graph.pb使用如下指令
python -m scripts/label_image \
--graph=tf_files/optimized_graph.pb \
--image=tf_files/flower_photos/daisy/3475870145_685a19116d.jpg
执行这些命令,如果两个输出相同,则意味着我们完美创建了optimize_graph.pb 。
由于我们要将模型嵌入到手机上,模型的大小就成了一个问题,手机无法处理如此巨大的模型。因为图所占用的大部分空间都是由权重构成的,这些权重是一些变化很小的浮点数,同时规律性又很小。
但是,数据压缩的工作原理又是基于数据中的规律性,这就会为模型压缩带来困难性。通过对网络的权重按因子进行量化,可以减小神经网络的大小。这会在网络图中带来更多的相同大小的权重(即重复),在之后的压缩中有很大的帮助。
现在我们使用quantize_graph脚本来对网络结构进行量化:
python -m scripts/quantize_graph \
--input=tf_files/optimized_graph.pb \
--output=tf_files/rounded_graph.pb \
--output_node_names=final_result \
--mode=weights_rounded
然后对模型进行压缩:
gzip -c tf_files/rounded_graph.pb > tf_files/rounded_graph.pb.gz
gzip -l tf_files/rounded_graph.pb.gz
这将创建一个名为rounded_graph.pb的文件。我们可以从中看到压缩情况有了明显的改善。
注意:如果运行quantize_graph时遇到任何错误,请下载此文件并将其复制到tensorflow库(TensorFlow安装位置)中的tools / quantization / quantanti_graph.py中。
从下面开始,教程将分为Android和iOS系统两部分。
iOS
▌步骤四:添加TensorFlow-experimental pod
将TensorFlow-experimental pod添加到你的pod文件中,这会安装一个通用二进制框架。这是在iOS上运行Tensorflow的最简单的方法。
▌步骤五:创建你的App
创建你自己的应用程序或者在XCode中加载已经创建好的的应用程序。
在项目根目录下添加一个名为Podfile的文件,其中包含以下内容:
target 'YourProjectName'
pod 'TensorFlow-experimental'
运行pod install下载并安装TensorFlow-experimental pod. 打开YourProjectName.xcworkspace并且添加你的代码。 在你的应用程序的Build Settings中,确保将$(inherited)添加到Other Linker Flags和 Header Search Paths 章节中。
▌步骤六:运行Sample
你需要Xcode 7.3或更高版本才能运行我们的iOS示例。
这有三个示例,包括:simple,benchmark,camera。你可以从这个链接(https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/ios#building-the-tensorflow-ios-libraries-from-source)直接下载代码。
然后,从Tensorflow的根目录下载Inception v1,并使用以下步骤将标签和图文件提取到simple和camera示例中的数据文件夹中:
mkdir -p ~/graphs
curl -o ~/graphs/inception5h.zip \
https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip \
&& unzip ~/{g}{r}{a}{p}{h}\frac{{s}}{\in}{c}{e}{p}{t}{i}{o}{n}{5}{h}.{z}{i}{p}-{d}~/graphs/inception5h
cp ~/graphs/inception5h/* tensorflow/examples/ios/benchmark/data/
cp ~/graphs/inception5h/* tensorflow/examples/ios/camera/data/
cp ~/graphs/inception5h/* tensorflow/examples/ios/simple/data/
切换到其中一个示例目录,下载Tensorflow-experimental pod(https://cocoapods.org/pods/TensorFlow-experimental)然后打开Xcode工作区。请注意,安装pod可能需要很长时间,因为它很大(约450MB)。如果你想运行示例代码,那么可以执行下面的命令:
cd tensorflow/examples/ios/simple
pod install
open tf_simple_example.xcworkspace #note .xcworkspace,not .xcodeproj
在XCode模拟器中运行简单的应用程序。你应该看到带有“Run Model”按钮的单屏幕应用程序。点击它,然后可以看到一个Grace Hopper图标。一旦你建立和运行它以后,你应该就能得到一个实时的相机视图,你可以指向物体获得实时的物体识别结果。
注意:我很确定我在iOS部分留下一些疏漏。如果你有任何错误,请通过这个官方链接进行评论,寻找帮助。
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/ios#building-the-tensorflow-ios-libraries-from-source
Android
在安卓上有两种方法来实现我们的目的,一个是Android Studio 另一个是 Bazel。因为使用Android Studio的人更多,所以我就使用它了。
如果你还没有安装它,请从下面这个链接下载并安装Android Studio: (https://developer.android.com/studio/index.html)
测试运行
为了检查Android Studio能否正常运行,我们将做以下几个小测试: 打开Android Studio并选择“打开一个已有的Android Studio”工程 去tensorflow-for-poets-2/android/tfmobile目录下打开Build.gradle文件并同步Gradle。如果一切正常,请点击BUILD> BUILD APK按钮
现在,就创建了一个名为app.apk的文件,把它复制到你的手机上并安装。(要记得打开手机的开发者模式哦。)
如果到目前为止都没有问题,那么后面的工作将易如反掌。
我们实现的应用程序是一个图像分类程序,它能够识别ImageNet中1000个类别的图像。
现在,要运行我们的应用程序,请执行以下两个步骤:
将模型文件添加到工程中
程序会引用手机目录android/tfmobile/assets下的graph.pb 和label.txt文件,而不再是rounded_graph.pb 和 retrained_labels.txt文件 现在,用以下命令替换文件,或者你可以手动更改
cp tf_files/rounded_graph.pb android/tfmobile/assets/graph.pb
cp tf_files/retrained_labels.txt android/tfmobile/assets/labels.txt
更改ClassifierActivity.java文件中的"output_name"
模型的输出节点有不同的名字:"final_result"。打开ClassifierActivity.java文件,按照如下方法更改output_name变量:
private static final String INPUT_NAME = "input";
private static final String OUTPUT_NAME = "final_result";
再试一遍,现在应该就可以正常运行了。