TensorFlow在iOS和Mac上的使用

一、环境


1首先你得安装好Xcode 8,确定开发者目录指向你安装Xcode的位置并且已经被激活。(如果你在安装Xcode之前已经安装了Homebrew,这可能会指向错误的地址,导致TensorFlow安装失败):


sudo xcode-select -s /Applications/Xcode.app/Contents/Developer


2、安装Homebrewhttps://brew.sh/index_zh-cn.html


3Homebrew安装其他软件


brew install python3

brew cask install java

brew install bazel

brew install automake

brew install libtool

brew install wget


4、命令:brew list 查看已安装的软件

TensorFlow在iOS和Mac上的使用


5、成功安装了python3,那pip3也随着被安装了,使用python3 的包管理器pip3来安装所需要的包。


pip3 install numpy

pip3 install scipy

pip3 install scikit-learn

pip3 install pandas

pip3 install tensorflow


6、命令:pip3 list 查看已安装的包

TensorFlow在iOS和Mac上的使用


这些包会安装在/usr/local/lib/python3.6/site-packages目录下。


7、下载TensorFlow源码,需要使用源码文件编译模型,并且使用官方iOSDemo

克隆TensorFlow GitHub仓库。注意,一定要保存在没有空格的路径下,否则bazel会拒绝构建。我是克隆到我的主目录下:


cd /Users/javalong/Downloads/Tensorflow

git clone https://github.com/tensorflow/tensorflow

  

一旦GitHub仓库克隆完毕,你就需要运行配置脚本(configure script:


cd /Users/javalong/Downloads/Tensorflow/tensorflow-master

./configure


这里有些地方可能需要你自行配置,比如:


Please specify the location of python. [Default is /usr/bin/python]:


我写的是/usr/local/bin/python3,因为我使用的是Python 3.6。如果你选择默认选项,就会使用Python 2.7来创建TensorFlow


Please specify optimization flags to use during compilation [Default is 

-march=native]:


这里只需要按Enter键。后面两个问题,只需要选择n(表示 no)。当询问使用哪个Python库时,按Enter键选择默认选项(应该是Python 3.6 库)。剩下的问题都选择n。随后,这个脚本将会下载大量的依赖项并准备构建TensorFlow所需的一切。


8、构建静态库

有两种方法构建TensorFlow1.Mac上使用bazel工具;2.IOS上,使用Makefile。我们是在IOS上构建,所以选择第2种方式。不过因为会用到一些工具,也会用到第一种方式。


TensorFlow的目录中执行以下脚本:


tensorflow/contrib/makefile/build_all_ios.sh


这个脚本首先会下载一些依赖项,然后开始构建。一切顺利的话,它会创建三个链入你的app的静态库:libtensorflow-core.a libprotobuf.a libprotobuf-lite.a

还有另外两个工具需要构建,在终端运行如下两行命令:


bazel build tensorflow/python/tools:freeze_graph

bazel build tensorflow/python/tools:optimize_for_inference


Note: 这个过程至少需要20分钟,因为它会从头开始构建TensorFlow(本次使用的是bazel)。如果遇到问题,请参考官方指导



9iOS工程配置引用参考:


9.1Other Linker Flags : 

-force_load $(SRCROOT)/../../makefile/gen/lib/libtensorflow-core.a

如图:

TensorFlow在iOS和Mac上的使用


9.2、Header Search Paths : 

$(SRCROOT)/../../makefile/gen/proto $(SRCROOT)/../../makefile/downloads/eigen $(SRCROOT)/../../makefile/downloads $(SRCROOT)/../../makefile/downloads/protobuf/src/ $(SRCROOT)/../../../..


9.3、Libaray Search Paths :

$(SRCROOT)/../../makefile/gen/lib $(SRCROOT)/../../makefile/gen/protobuf_ios/lib


如图:

TensorFlow在iOS和Mac上的使用


9.4、Demo工程与makefile目录相对关系如图:

TensorFlow在iOS和Mac上的使用


10、库的引用如图:

TensorFlow在iOS和Mac上的使用


二、模型训练


1.下载数据


cd /Users/javalong/Desktop

mkdir Test

cd Test

curl -O http://download.tensorflow.org/example_images/flower_photos.tgz

tar xzf flower_photos.tgz


进入flower_photos,可以看到5个文件夹,daisy dandelion roses sunflowers tulips


TensorFlow在iOS和Mac上的使用



2. 利用预训练模型训练数据


模型是谷歌的Inceptionv3http://arxiv.org/abs/1512.00567)。在2012年的imageNet上进行训练,并在2012ImageNet上取得了3.4%top-5准确率(人类的只有5%

这么一个复杂的网络若是直接自己训练,起码需要几天甚至十几天的时间。所以这里我采用复用深度学习的方法。即模型前面的层的参数都不变,而只训练最后一层的方法。最后一层是一个softmax分类器,这个分类器在原来的网络上是1000个输出节点(ImageNet1000个类),所以需要删除网络的最后的一层,变为所需要的输出节点数量,然后再进行训练。

tensorflow/examples/image_retraining/retrain.py 中采用的方法是这样的:将自己的训练集中的每张图像输入网络,最后在瓶颈层(bottleneck),就是倒数第二层,会生成一个2048维度的特征向量,将这个特征保存在一个txt文件中,再用这个特征来训练softmax分类器。


进入tensorflow源代码目录


2.1

cd /Users/javalong/Downloads/Tensorflow/tensorflow-master


2.2

python3 tensorflow/examples/image_retraining/retrain.py \

--bottleneck_dir=/Users/javalong/Desktop/Test/ \

--how_many_training_steps 100000 \

--model_dir=/Users/javalong/Desktop/Test/inception2 \

--output_graph=/Users/javalong/Desktop/Test/retrained_graph2.pb \

--output_labels=/Users/javalong/Desktop/Test/retrained_labels.txt \

--image_dir=/Users/javalong/Desktop/Test/flower_photos


脚本会下载Inceptionv3模型,80多兆,可以提前下载好放到Testinception2目录下

模型路径:http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz

训练完成后,在Test目录下看到模型文件retrained_graph.pb和标签retrained_labels.txt


3. 模型验证


新建文件label_image.py,注意格式,代码缩进使用tab


#-*- coding:utf-8 -*-

import os

import numpy as np

import tensorflow as tf

from sklearn import metrics



# 随便一张玫瑰花图片

image_path = "test1.jpg"


# read in the image_data

image_data = tf.gfile.FastGFile(image_path, "rb").read()


# Loads label file, strips off carriage return

label_lines = [line.strip() for line in tf.gfile.GFile("retrained_labels.txt")]


# Unpersists graph from file

with tf.gfile.FastGFile("retrained_graph2.pb", "rb") as f:

    graph_def = tf.GraphDef()

    graph_def.ParseFromString(f.read())

    _ = tf.import_graph_def(graph_def, name="")


with tf.Session() as sess:

# Feed the image_data as input to the graph and get first prediction

    softmax_tensor = sess.graph.get_tensor_by_name("final_result:0")

    preditions = sess.run(softmax_tensor, {"DecodeJpeg/contents:0":image_data})

# sort to show labels of first prediction in order of confidence

    top_k = preditions[0].argsort()[-len(preditions[0]):][::-1]

    for node_id in top_k:

        human_string = label_lines[node_id]

        score = preditions[0][node_id]

        print('%s (score = %.5f' %(human_string, score))


执行文件

python label_image.py 


得到类似下图结果

TensorFlow在iOS和Mac上的使用




、编译模型


将模型文件转化成ios可以上可以运行的文件


1、首先编译tensorflow源码示例中的label_image来测试retrained_graph2.pb模型

1.1

cd /Users/javalong/Downloads/Tensorflow/tensorflow-master


1.2

bazel build tensorflow/examples/label_image:label_image


1.3

bazel-bin/tensorflow/examples/label_image/label_image \

--output_layer=final_result \

--labels=/Users/javalong/Desktop/Test/retrained_labels.txt \

--image=/Users/javalong/Desktop/Test/flower_photos/daisy/5547758_eea9edfd54_n.jpg \

--graph=/Users/javalong/Desktop/Test/retrained_graph2.pb


如图所示:

TensorFlow在iOS和Mac上的使用


2、优化模型并去掉ios不支持的算子

翻译文章中说明如下:

由于移动设备内存有限,并且app需要下载,因此TensorFlowiOS版本只支持那些推理中常见的算子(ops,提供英文原文以防翻译错误),没有大量支持扩展的依赖项。你可以在tensorflow/contrib/makefile/tf_op_files.txt这个文件中找到可以使用的算子列表。

文章中提到,DecodeJpeg是不能使用的算子之一,因为其实现方法依赖于libjpeg,而它在iOS上运行非常麻烦(painful to support),并且增加binary footprint(不懂。。。)。尽管可以用iOS原生的图像库实现,大部分应用其实直接图像buffer而不需要对jpeg进行编码。

问题麻烦的地方在于,我们使用的Inception模型包括了DecodeJpeg算子。我们通过直接将图片数据传给Mul结点绕过DecodeJpeg操作。尽管如此,图被加载的时候,如果平台不支持,即使算子没有被调用,还是会报错,因此我们利用optimize_for_inference去掉所有没有被输入和输出结点用到的结点。这个脚本同时会完成一些优化来加速,例如将batch normalization转换成卷积权重(the convolutional weights)来减少计算次数。


2.1、

bazel build tensorflow/python/tools:optimize_for_inference


2.2

bazel-bin/tensorflow/python/tools/optimize_for_inference \

--input=/Users/javalong/Desktop/Test/retrained_graph2.pb \

--output=/Users/javalong/Desktop/Test/optimized_graph.pb \

--input_names=Mul \

--output_names=final_result


如图所示:

TensorFlow在iOS和Mac上的使用


同样可以通过label_image验证optimized_graph.pb模型的有效性。


3、将模型的权重变成256之内的常数

优化前模型87.5M,优化后的模型还是有87.2M,可以损失一定的精确度,将模型的权重从浮点型转化成整数。

3.1、 

bazel build tensorflow/tools/quantization:quantize_graph


3.2

bazel-bin/tensorflow/tools/quantization/quantize_graph --input=/Users/javalong/Desktop/Test/optimized_graph.pb \

--output=/Users/javalong/Desktop/Test/rounded_graph.pb \

--output_node_names=final_result \

--mode=weights_rounded


如图所示:

TensorFlow在iOS和Mac上的使用


4、验证rounded_graph.pb模型

4.1、

bazel-bin/tensorflow/examples/label_image/label_image \

--output_layer=final_result \

--labels=/Users/javalong/Desktop/Test/retrained_labels.txt \

--image=/Users/javalong/Desktop/Test/flower_photos/daisy/5547758_eea9edfd54_n.jpg \

--graph=/Users/javalong/Desktop/Test/rounded_graph.pb


如图所示:

TensorFlow在iOS和Mac上的使用


5、内存映射(memory mapping

由于app87M的模型权值加载到内存中,会对RAM带来压力导致稳定性问题,因为OS可能会杀死占用内存太多的应用。幸运的是,这些缓冲区的内容是只读的,能以os在内存遇到压力的时候很容易释放的方式将模型映射到内存中。为此,我们将模型转换成可以从GraphDef分别加载到形式。

5.1、

bazel build tensorflow/contrib/util:convert_graphdef_memmapped_format


5.2

bazel-bin/tensorflow/contrib/util/convert_graphdef_memmapped_format \

--in_graph=/Users/javalong/Desktop/Test/rounded_graph.pb \

--out_graph=/Users/javalong/Desktop/Test/mmapped_graph.pb


需要注意的是,此时模型文件已经不是一般的GraphDef protobuf,所以如果还按照以前的方法加载会遇到错误。


5.3、

bazel-bin/tensorflow/examples/label_image/label_image \

--output_layer=final_result \

--labels=/Users/javalong/Desktop/Test/retrained_labels.txt \

--image=/Users/javalong/Desktop/Test/flower_photos/daisy/5547758_eea9edfd54_n.jpg \

--graph=/Users/javalong/Desktop/Test/mmapped_graph.pb


如图所示:

TensorFlow在iOS和Mac上的使用


四、使用iOS Demo工程


1demo是在tensorflow官方提供的ios示例代码camera的基础上进行的修改,工程路径:tensorflow/contrib/ios_examples/camera

2、将rounded_graph.pbretrained_labels.txt导入到data目录下。

3、修改CameraExampleViewController.mm中要加载到文件,图片等尺寸,结点的名字和如何缩放像素值。


TensorFlow在iOS和Mac上的使用


4、最后程序运行的结果如下:


TensorFlow在iOS和Mac上的使用




上一篇:支付宝UI篇-扫码和AR


下一篇:HealthKit之实战锚点读取