最近领导考虑到生产成本的问题,想要在CPU上运行神经网络,于是研究了一阵Intel推出的OpenVINO工具包。下面主要是介绍在Ubuntu16.04上使用OpenVINO配置TensorFlow模型。
OpenVINO深度学习部署工具套件
OpenVINO的深度学习部署工具套件主要包括两部分,一个是模型优化器,另外一个是推理引擎。模型优化器是由Python编写的,推理引擎是一套C++函数库以及C++的类。
工作原理是对训练产生的网络模型进行优化,优化结果转换成中间表示文件,得到IR文件(xml文件和bin文件)。xml文件中包含优化以后的网络拓扑结构,bin文件优化之后的模型参数和模型变量。
对于TensorFlow框架,对应的模型为pb文件。
环境准备工作
安装
首先,官网上有详细的安装步骤:Install the Intel® Distribution of OpenVINO™ toolkit for Linux*
但是,配置环境总是一件麻烦的事,鬼知道会缺失什么依赖包,到头来没装好不说,还可能影响已有的环境┑( ̄Д  ̄)┍。在即将入坑之际,我发现了现成的docker image,于是果断选择跳过官方指导。。。
sudo docker run -it cortexica/openvino /bin/bash
(使用sudo docker search openvino命令可找到很多相关的images,cortexica/openvino这个image的描述里提到了Ubuntu16.04,所以我选择了这一个)
配置模型优化器
运行容器,进入模型优化器 prerequisites文件夹(不同images中的路径可能有差异,但从deployment_tools这层目录开始应该都一样)
cd /opt/intel/computer_vision_sdk/deployment_tools/model_optimizer/install_prerequisites
运行脚本
sudo ./install_prerequisites.sh
运行demo验证安装成功
这一步我跳过了,具体操作可以参考Use the Demo Scripts to Verify Your Installation
转换TensorFlow模型
先来关注一下可以转的层:Supported TensorFlow Layers
PS:点名RandomUniform是Not supported。。。什么仇什么怨,不支持别写在表里好不好
其实转的过程很简单,就两小步:
1、进入model_optimizer文件夹
cd /opt/intel/computer_vision_sdk/deployment_tools/model_optimizer
2、使用mo_tf.py脚本将pb文件转为IR文件
python mo_tf.py --input_model <INPUT_MODEL>.pb --output_dir <OUTPUT PATH>
幻想是丰富的,现实是残酷的,如果真这么简单就能成功,那还记录个啥哦(*/ω╲*)
对于大部分模型来说,直接运行mo_tf.py得到的应该都是各种各样的ERROR,下面正文正式开始
使用转化参数
mo_tf.py文件除了--input_model和--output_dir这个两个参数以外,还有一大波:
下面介绍几个比较重要的
Mean and Scale Values
一般来说在训练时我们都会使用归一化的输入,比如从0~255归一化到0~1。还有在使用Image Net等公开数据集的时候,会进行一个去均值的操作。这些都属于简单的数据预处理,乍一看好像和网络没啥关系,但其实影响很大,重点在于预处理部分的代码有没有被写进TensorFlow的拓扑结构里。
如果预处理部分被写进拓扑结构里了,这种主要就是在训练网络时直接读取的原始数据,然后用tf里的函数进行预处理的情况。这种情况下得到的模型,在pb文件里会有预处理相关的node,这些node也会直接转化到xml文件中(前提是OpenVINO支持。。。我在预处理结中使用的tf.map_fn对多图进行处理就一直报错)。
另一种情况是拓扑结构里没有预处理部分,举例就是用numpy对原始数据进行了处理,然后作为tf网络的输入,输入到网络中。由于拓扑结构中没有预处理部分,虽然pb转IR的时候也可以成功,但之后推理的结果肯定是错的。这个时候就需要用到相关参数--scale、 --scale_values,、--mean_values。当mean value和scale value被同时指定时,数据先减去mean value,再除以scale value。
python mo_tf.py --input_model <model_name>.pb --scale_values [59,59,59] --mean_values [177,177,177]
至于怎么看拓扑结构里有没有预处理部分,restore pb文件打印出所有node是一种办法,再直观一点,使用Netron,把pb文件导进去可以直接可视化网络~
这一个参数其实并不影响模型转化的成功与否,只不过没注意的话,转化笑嘻嘻,推理mmp。
接下来的参数会直接影响转化的成败。
Input Shapes
在TensorFlow中, 输入的placeholderr的shape可以被设成None或者-1。这种设置在对输入任意尺寸图片和调整batch size时非常方便。但遗憾的是OpenVINO不接受这么随意的输入。。。
如果在pb文件中,输入没有明确的尺寸的话,需要加入--input_shape参数指定shape,比如[1,128,128,3]。对于batch size不定的情况,再调用mo_tf.py后面加上-b。这两个参数不能同时使用。
python mo_tf.py --input_model <model_name>.pb --input_shape [1,128,128, 3]
python mo_tf.py --input_model <model_name>.pb -b 1
Is_Training
神经网络的输入除了输入数据,一般还会有一个区分train和valid(test)状态的is_training,用来控制batch norm和dropout的状态。这里也有两种情况:
1、train和valid是两份代码,这种情况下,is_training在各自的代码里是True和False的定值,并不会再程序运行中切换,此时的pb文件应该固定的是valid代码中狗的graph,再pb转IR的过程中也无需多加参数;
2、在train的过程中同时进行valid,此时is_training是一个placeholder,会在train时传入True,再valid时传入False,在pb文件中也会存在这个node,此时就需要使用参数--freeze_placeholder_with_value,将is_training(node的名字以自己网络中的为准)的值定为False。
python mo_tf.py --input_model <model_name>.pb --freeze_placeholder_with_value “is_training->False"
Tensorflow模型特有的参数
--tensorflow_use_custom_operations_config
这个参数我没有用到,主要是使用TensorFlow Object Detection API中的模型时会用到,需要传入相应的json配置文件。网上很多在转SSD、Faster RCNN、YOLO等模型发生错误时,使用这个参数导入配置文件后都成功了。
--disable_nhwc_to_nchw
这个参数主要是转换输入维度的,NHWC和NCHW,默认会从NHWC转为NCHW。
实验结果
我自己转换了一个4分类模型,转好后的IR文件存在/opt/intel/computer_vision_sdk/deployment_tools/model_optimizer/model路径下
进入推理引擎文件夹
cd /opt/intel/computer_vision_sdk/deployment_tools/inference_engine/samples/build/intel64/Release
进行推理
./classification_sample -d CPU -i <TEST_IMAGE_PATH> -m <XML_PATH>
在i7-8700KCPU3.70GHz硬件条件下,分类50张图片,
直接使用CPU前传pb文件耗时903.15 ms,使用OpenVINO引推理引擎耗时176.72 ms
总结:加速效果还是明显的,但使用自己的模型转IR文件还是很复杂的,自定义层的转化还需要多多研究~
参考
Intel OpenVINO配置和使用 - James的博客 - CSDN博客
Using the Model Optimizer to Convert TensorFlow* Models | Intel® Software