作者简介:

<b>matthijs hollemans</b>
荷兰人,独立开发者,专注于底层编码,gpu优化和算法研究。目前研究方向为ios上的深度学习及其在app上的应用。
前面已经训练好模型,下面创建一个利用tensorflow
1.0)。
首先你得安装好xcode 8,确定开发者目录指向你安装xcode的位置并且已经被激活。(如果你在安装xcode之前已经安装了homebrew,这可能会指向错误的地址,导致tensorflow安装失败):
我们将使用名为bazel的工具来安装tensorflow。先使用homebrew安装所需要的包:
<b>note:</b>在macos
sierra 上,运行下面的配置脚本报错了,我只能克隆主分支来代替。在os
x ei caption 上使用r1.0分支就不会有任何问题。
一旦github仓库克隆完毕,你就需要运行配置脚本(configure script):
这里有些地方可能需要你自行配置,比如:
我写的是/usr/local/bin/python3,因为我使用的是python 3.6。如果你选择默认选项,就会使用python 2.7来创建tensorflow。
这里只需要按enter键。后面两个问题,只需要选择n(表示 no)。当询问使用哪个python库时,按enter键选择默认选项(应该是python 3.6 库)。剩下的问题都选择n。随后,这个脚本将会下载大量的依赖项并准备构建tensorflow所需的一切。
有两种方法构建tensorflow:1.在mac上使用bazel工具;2.在ios上,使用makefile。我们是在ios上构建,所以选择第2种方式。不过因为会用到一些工具,也会用到第一种方式。
在tensorflow的目录中执行以下脚本:
这个脚本首先会下载一些依赖项,然后开始构建。一切顺利的话,它会创建三个链入你的app的静态库:libtensorflow-core.a, libprotobuf.a, libprotobuf-lite.a。
还有另外两个工具需要构建,在终端运行如下两行命令:
这一步是可选的,不过因为已经安装了所有需要的包,在mac上构建tensorflow就没那么困难了。使用pip包代替官方的tensorflow包进行安装。
现在你就可以创建一个自定义的tensorflow版本。例如,当运行<b>train.py</b>脚本时,如果出现“the
tensorflow library wasn’t compiled to use sse4.1 instructions”提醒,你可以编译一个允许这些指令的tensorflow版本。
在终端运行如下命令来构建tensorflow:
-march=native选项添加了对sse,avx,avx2,fma等指令的支持(如果这些指令能够在你的cpu上运行)。然后安装包:
我们将要创建的app会载入之前训练好的模型,并作出预测。之前在<b>train.py</b>中,我们将图保存到了 /tmp/voice/graph.pb文件中。但是你不能在ios app中直接载入这个计算图,因为图中的部分操作是tensorflow
c++库并不支持。所以就需要用到上面我们构建的那两个工具。
freeze_graph将包含训练好的w和b的graph.pb和检查点文件合成为一个文件,并移除ios不支持的操作。在终端运行tensorflow目录下的这个工具:
optimize_for_inference工具进一步简化了可计算图,它以frozen.pb作为输入,以/tmp/voice/inference.pb作为输出。这就是我们将嵌入ios app中的文件,按如下方式运行这个工具:
1. app是用c++写的(源文件后缀名为.mm),因为tensorflow没有swift api,只有c++的;
2.inference.pb文件已经包含在项目中,如果有需要的话,你可以用你自己的inference.pb文件替换掉;
3.这个app使用了accelerate框架;
4.这个app使用了已经编译好的静态库。
在项目设置界面打开构建参数标签页,在other linker flags,你会看见如下信息:
除非你的名字也是“matthijs”,否则需要用你克隆的tensorflow存放的路径进行替换。(tensorflow出现了两次,所以文件名为tensorflow/tensorflow/...)。
note: 你也可以将这3个文件拷贝到项目文件夹中,就不必担心路径出错了。我之所以没有这样做,是因为libtensorflow-core.a
文件有440mb大。
再检查header search
paths,目前的设置是:
然后你还要将这些路径更新到您克隆仓库的位置,还有些build
settings我也做了修改:
1.enable bitcode: no
2.warnings / documentation comments: no
3.warnings / deprecated functions: no
目前tensorflow并不支持字节码,所以我禁用了这个功能。我也关闭了警告功能,否则你编译app时会遇到很多问题。(虽然你还是会遇到值转换问题的警告,禁止这个警告功能也没毛病)。
完成other linker flags和 the header
search paths的设置之后,就可以构建并运行app了。下面看一下这个使用tensorflow的ios app是如何工作的。
ios上的tensorflow使用c++写的,不过需要你写的c++代码有限,通常,你只需要做下面几件事:
1.从.pb文件中载入计算图和权重;
2.使用图创建会话;
3.将数据放入输入张量;
4.在图上运行一个或多个节点;
5.得到输出张量结果。
在演示的app中,这些都是写在viewcontroller.mm中。首先载入图:
这个c++ api 支持的操作要比python
api少。这里他说的是损失函数节点中l2loss操作在ios上不支持。这就是为什么我们要使用freeze_graph简化图。
在载入图之后,创建会话:
会话创建好之后,就可以进行预测了。predict:方法需要一个包含20个浮点数的元组,代表声学特征,然后传入图中,该方法如下所示:
首先定义张量x作为输入数据。这个张量维度为{1,
20},因为它一次接收一个样本,每个样本有20个特征。然后从float *数组将数据拷贝至张量中。
接下来运行会话:
运行如下代码:
这条代码看起来并没有python版的简洁。我们创建了feed字典,运行的节点列表,以及保存结果的向量。最后,打印结果:
本来只需要运行inference节点就可以得到男性/女性的预测结果,但我还想看计算出来的概率,所以后面运行了y_pred节点。
你可以在iphone模拟器或者设备上运行这个app。在模拟器上,你可能会得到诸如 “the tensorflow library wasn’t compiled to use sse4.1
instructions”的消息,但是在设备上则不会报错。
app会做出来两种预测:男性/女性。运行这个app,你会看到下面的输出,它先打印出图中的节点:
这个图只包含进行预测的节点,并不需要训练相关的节点。然后就会输出结果:
如果用python脚本测试同样的数据,会得到相同的答案。
优点:
2.tensorflow有比bnns和metal更多的特性;
3.你可以在模拟器上运行。metal总是要在设备上运行。
缺点:
1.目前不支持gpu。tensorflow使用 accelerate 框架能够发挥cpu向量指令的优势,原始速度比不上metal;
2.tensorflow
api使用c++写的,所以你不得不写一些c++代码,并不能直接使用swift编写。
3.相比于python api,c++ api有限。这意味着你不能在设备上进行训练,因为不支持反向传播中用到的自动梯度计算。
4.tensorflow静态库增加了app包大概40mb的空间。通过减少支持操作的数量,可以减少这个额外空间,不过这很麻烦。而且,这还不包括模型的大小。
目前,我个人并不提倡在ios上使用tensorflow。优点并没有超过缺点,作为一款有潜力的产品,谁知道未来会怎样呢?
note: 如果决定在你的ios app中使用tensorflow,那你必须知道别人很容易从app安装包中拷贝图的.pb文件窃取你的模型。由于固化的图文件包含模型参数和图定义,反编译简直轻而易举。如果你的模型具有竞争优势,你可能需要做出预案防止你的机密被窃取。
ios
app上使用tensorflow的一个弊端是他是运行在cpu上的。对于数据和模型较小的项目,tensorflow能够满足我们的需求。但是对于更大的数据集,特别是深度学习,你就必须要使用gpu代替cpu,在ios上就意味着要使用metal。
训练后,我们需要将学习到的参数w和b保存成metal能够读取的格式。其实只要以二进制格式保存为浮点数列表就可以了。
w.eval()计算w目前的值,并以返回numpy数组(和sess.run(w)作用是一样的)。然后使用tofile()将numpy数组保存为二进制文件。
之前我们使用下面的公式计算逻辑斯蒂回归:
这和神经网络中全连接层进行的计算相同,为了实现metal版分类器,我们只需要使用mpscnn fully connected 层。首先将w.bin和b.bin载入到data对象:
然后创建全连接层:
因为输入是20个数字,我设计了作用于一个1x1的有20个输入信道(input channels)的全连接层。预测结果y_pred是一个数字,所以全连接层只有一个输出信道。输入和输出数据放在mpsimage 中:
和app上的tensorflow一样,这里也有一个predict 方法,这个方法以组成一条样本的20个浮点数作为输入。下面是完整的方法:
和运行session的结果是一样的。convert(example:to:)和tofloatarray()方法加载和输出mpsimage 对象的辅助函数。
你需要在设备上运行这个app,因为模拟器不支持metal。输出结果如下:
注意到这些概率和用tensorflow预测到的概率不完全相同,这是因为metal使用16位浮点数,但结果相当接近。
rajca
aaron hillegass
以上为译文
文章原标题《getting
started with tensorflow on ios》,由matthijs hollemans发布。
译者:李烽 ;审校:董昭男