OpenVINO2020+NCS2代运行TensorFlow模型

东拼西凑做CV 专栏收录该内容
1 篇文章 0 订阅

背景

  从GitHub上找了个Yolov3的TensorFlow实现1,自己标注数据集,训练出结果后,跑起来实在是太慢了,800+ms一张图片,毫无实用性。最终应用场景又不可能整个工作站、2080ti什么的,头疼。无意间发现了OpenVINO和神经计算棒二代,听说能加速?那就试试咯

分析

  无非就三步嘛
  1、安装OpenVINO,配置好环境
  2、把TensorFlow模型转换成xml+bin文件
  3、调用api,输入数据得出结果

行动

一、安装OpenVINO

  不得不说官方文档2的确是最好的教程,比网上绝大多数帖子博客(包括我的哈哈哈)都要详细,建议先看。英文可以翻译,词汇不算复杂。也有中文文档,安装部分写得不错

1、win10

  这是win10安装教程,概括一下就是要安装以下软件:

  • OpenVINO
  • VS2019/2017/2015及Build Tools
  • CMake
  • Python3.6.5+

  其中VS及生成工具安装可能不大好找,这里贴出微软官方下载链接,没需求的话安装2015就行了。
  建议先安装好其他三项再安装OpenVINO,会出现这样的界面,不然会提醒你还有什么没安装。
OpenVINO全部安装成功
  建议默认安装路径,省事。2020版本貌似不用自定义选择组件安装了。

2、树莓派

  这是树莓派安装教程,相较于win10来说,它不转换模型,只有推理引擎。需要安装以下软件:

  • OpenVINO
  • CMake
  • Python3.6.5+

  OpenVINO的安装包只有20来M,安装起来非常快,还包含了OpenCV,不用编译!

3、设置环境变量

  win10平台是一个bat文件,打开cmd运行即可,然后在这个命令行窗口进行转换推理等操作
  树莓派里是一个sh文件,操作同上。可以执行以下命令,意思是在.bashrc里加入source /opt/intel/openvino/bin/setupvars.sh这么一句,每次打开终端都会运行设置环境变量的指令。

echo "source /opt/intel/openvino/bin/setupvars.sh" >> ~/.bashrc

4、挂载USB

  win10平台不用管,Linux和树莓派上需要设置USB规则,具体看官方教程,敲几句命令的事。

5、验证demo

   设置完环境变量后,win10里是执行一个bat,它会下载xml+bin文件,这就是OpenVINO的模型文件,然后调用Build Tools和CMake生成一个exe文件,再去执行。树莓派类似。
  说明:如果安装在了其他路径下,可能要去demo bat或者sh文件里修改对应的路径。

6、总结

   win10:

安装CMake
安装VS及BuildTools
安装Python
安装OpenVINO
设置环境变量
下一步

   树莓派:

安装CMake
安装Python
安装OpenVINO
设置环境变量
设置USB规则
下一步

  验证不是必须的,想要直接使用可以跳过,但不建议

二、转换模型

  如上一番折腾后,我们的硬件平台就有了OpenVINO环境,可以继续干活了。
  由于OpenVINO使用的是xml+bin文件,所以需要对其他框架的模型文件进行转换。

1、下载所需文件

  这是官方文档,安装所用框架对应的文件即可,不用全部下载。win10 TensorFlow如下:

cd "C:\Program Files (x86)\IntelSWTools\openvino_2020.1.033\deployment_tools\model_optimizer\install_prerequisites"
install_prerequisites_tf.bat

  双引号是因为Program Files (x86)间有空格和特殊字符。openvino_2020.1.033是我的版本,根据实际情况修改。

2、转换模型

  这是官方文档,先把checkpoint文件转为pb文件,官方文档往上划一下就有,Freezing Custom Models in Python*。把pb文件转换为xml+bin如下:

cd "C:\Program Files (x86)\IntelSWTools\openvino_2020.1.033\deployment_tools\model_optimizer"
python mo_tf.py --input_model yolov3_coco.pb --input_shape [1,416,416,3]

  说明:python还是python3看你的配置;–input_model后面跟要转换的pb文件的路径;–input_shape跟输入参数的形状,我的加了这个才转换成功。这是转化成fp32精度的,如果要给树莓派用,需要转化成fp16精度的,加上--data_type FP16

3、总结

  下载好转换所需文件,再把pb文件或者其他模型文件转换成xml+bin,这样我们就有了推理的基础。到这里,即便没有TensorFlow等深度学习库也是完全可以的,不依赖它们了,只要有OpenVINO环境和xml+bin文件就能实现CNN推理。

三、推理模型

  终于到了这一步,调用api嘛,因为不会C++,所以说说Python的方法

1、OpenVINO

#! /usr/bin/env python
# coding=utf-8

import cv2
import numpy as np
import utils3 as utils
from openvino.inference_engine import IENetwork, IEPlugin # 导入openvino库

num_classes     = 80
input_size      = 416

# 搭建网络,调用IENetwork,返回net对象,参数为xml和bin文件的路径
model_xml_CPU = r'yolov3_coco.xml'
model_bin_CPU = r'yolov3_coco.bin'
net = IENetwork(model=model_xml_CPU, weights=model_bin_CPU)

# 定义输入输出
input_blob = next(iter(net.inputs)) # 迭代器
out_blob   = next(iter(net.outputs))
print(input_blob, out_blob)
n, c, h, w = net.inputs[input_blob].shape
print(n,c,h,w)

# 加载设备,调用IEPlugin,返回设备对象,参数为设备名,如CPU、GPU、MYRIAD
plugin = IEPlugin(device='CPU')
# 加载网络,调用设备对象的load方法,返回执行器,参数为网络
exec_net = plugin.load(network=net) 
print('load ok!')

# 获取图像
img_path = r'market.jpg'
original_image = cv2.imread(img_path)

# 图像处理,从(416, 416, 3)到(1, 3, 416, 416)
original_image_size = original_image.shape[:2]
image_data = utils.image_preporcess(np.copy(original_image), [input_size, input_size])
image_data = image_data[np.newaxis, ...]
# from (1, 416, 416, 3) to (1, 416, 416, 3)
op_img_data = np.rollaxis(image_data, 3, 1)

# 推理模型,调用执行器的infer方法,返回模型输出,输入为格式化图像
outputs = exec_net.infer(inputs={input_blob: op_img_data}) 

# from (1, 6, 52, 52, 3) to (1, 52, 52, 3, 6)
pred_sbbox = np.rollaxis(outputs['pred_sbbox/concat_2'], 1, 5)
pred_mbbox = np.rollaxis(outputs['pred_mbbox/concat_2'], 1, 5)
pred_lbbox = np.rollaxis(outputs['pred_lbbox/concat_2'], 1, 5)

pred_bbox = np.concatenate([np.reshape(pred_sbbox, (-1, 5 + num_classes)),
                            np.reshape(pred_mbbox, (-1, 5 + num_classes)),
                            np.reshape(pred_lbbox, (-1, 5 + num_classes))], axis=0)

bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.3)
bboxes = utils.nms(bboxes, 0.45, method='nms')
image = utils.draw_bbox(original_image, bboxes)

cv2.imshow('Result', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
  这是使用CPU进行推理,如果要用神经棒二代,需要加载fp16精度的模型,并且把device换成MYRIAD
  总结起来就4步,用IENetwork搭建网络,用IEPlugin加载设备,用设备的load方法加载网络,用执行器的infer方法进行推理。2019R3版本还有一个添加CPU扩展的步骤,2020版貌似合并了,不用添加CPU扩展了,撒花~
  utils3.py3里放着一些常用函数,会在文末附上链接。

2、OpenCV

  模型输出没搞懂,放一个例程,可以看出也是网络模型,设备,输入,推理的路子。

import cv2 as cv

# Load the model 
net = cv.dnn.readNet('face-detection.xml', 'face-detection.bin') 

# Specify target device 
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)

# Read an image 
frame = cv.imread('face.jpg')

# Prepare input blob and perform an inference 
blob = cv.dnn.blobFromImage(frame, size=(416, 416), ddepth=cv.CV_8U) 

net.setInput(blob) 

out = net.forward()

# Draw detected faces on the frame 
for detection in out.reshape(-1, 7): 
    confidence = float(detection[2]) 
    xmin = int(detection[3] * frame.shape[1]) 
    ymin = int(detection[4] * frame.shape[0]) 
    xmax = int(detection[5] * frame.shape[1]) 
    ymax = int(detection[6] * frame.shape[0])
    if confidence > 0.5:
        cv.rectangle(frame, (xmin, ymin), (xmax, ymax), color=(0, 255, 0))

# Save the frame to an image file 
cv.imwrite('out.png', frame)


在这里插入图片描述

3、bat启动

  每次启动都要打开cmd,设置环境变量,python xxx.py,巨麻烦,所以写个bat,一键启动!~

cd /d "C:\Program Files (x86)\IntelSWTools\openvino\bin"
call setupvars.bat
cd /d F:\TF_YOLOv3\Blog
python blog_openvino.py
pause

  cd 要加上/d,不然不报错,当然也成功不了。pause是为了出错时能看到打印的错误信息,不调试可以去掉。

四、遇到的问题

  快要写吐了。。。。continue,也是踩了不少的坑啊

1、历史遗留的坑

pi@raspberrypi:~/Desktop $ python3 yolov3_coco.py 
Traceback (most recent call last):
  File "yolov3_coco.py", line 11, in <module>
    out = net.forward()
cv2.error: OpenCV(4.1.2-openvino) /home/jenkins/workspace/OpenCV/OpenVINO/build/opencv/modules/dnn/src/op_inf_engine.cpp:704: 
	error: (-215:Assertion failed) Failed to initialize Inference Engine backend: 
	AssertionFailed: newDims[newPerm[i]] == 1 in function 'initPlugin'

  newDims[newPerm[i]] == 1,在官方论坛看到同样的报错,说是5D模型,这……??? 然后,把2019R3换成了2020,就解决了,不报错了。。。可能是转换的时候有问题吧,还没弄明白。

2、维度需要重组

  贴出的OpenVINO代码里,# from (1, 416, 416, 3) to (1, 416, 416, 3)就是对输入维度的重组,可以在官方文档里找到说明——

–input_shape INPUT_SHAPE
… For example, [N,C,H,W] is used for Caffe* models and [N,H,W,C] for TensorFlow* models. Model Optimizer performs necessary transformations to convert the shape to the layout required by Inference Engine (N,C,H,W). …

  最坑爹的是输出维度的重组,如下图
在这里插入图片描述
  前面又是安装又是转换的折腾了那么久,你就给我看这个??差点崩溃,开始反思,难道是模型转换的锅?还是推理又出错了?不然为什么置信度能有上万的数?这也太迷了吧。
  把outputs和TensorFlow跑的结果打印出来,好像,有几个数前五位对得上?

[[[[[3.70791960e+00 3.62859917e+00 7.69530010e+00 1.76488304e+01
1.38096511e-02 5.07005513e-01]
[4.27160788e+00 4.52064657e+00 2.25704193e+01 4.32643967e+01
1.55485570e-02 6.79710686e-01]
[4.34192467e+00 3.24738264e+00 4.82099113e+01 4.42287598e+01
1.73972249e-02 9.03145492e-01]]

[[[[[3.70792055e+00, 4.27160835e+00, 4.34192514e+00],
[1.17772388e+01, 1.23407335e+01, 1.20422506e+01],
[2.00990105e+01, 2.03807487e+01, 2.03778057e+01],
…,
[3.96122070e+02, 3.96281281e+02, 3.95539856e+02],
[4.03839752e+02, 4.04300812e+02, 4.03584259e+02],
[4.11999878e+02, 4.11900787e+02, 4.11700836e+02]],

  又随便试了几个数字,都能找到!也就是说,又是维度乱了。。。一时间也看不出来怎么乱了,试特定的数字吧,看看a[0][1][2][3][4]对应什么b的什么就行了,然后发现没用,因为——

with tf.Session(graph=graph) as sess:
    pred_sbbox, pred_mbbox, pred_lbbox = sess.run(
        [return_tensors[1], return_tensors[2], return_tensors[3]],
                feed_dict={ return_tensors[0]: image_data})

  是在下输了!那就重组维度吧,打印出两个维度一看,openvino:(1, 6, 52, 52, 3),TensorFlow:(1, ?, ?, 3, 6),应该是52,52。这好办,用numpy的rollaxis把第1维滚动到最后一维就行。

3、速度还是不够

  好不容易跑通了,都快差点忘记自己要干什么了,对,看看速度——

DeviceCPUCPUCPUGPUPi
EnvironmentTensorflowOpenVINOOpenVINO+NCSOpenVINOOpenVINO+NCS
Average(ms)623471371229487
Up11.301.632.681.25

  这。。。。远远达不到实时的要求啊,虽然速度有提升,但这也太少了吧。看来得找其他办法了——

  • 1、继续优化模型,openvino的能力感觉远远没有发挥出来
  • 2、更换模型,比如yolov3 tiny
  • 3、换更强劲的设备
  • 4、使用C++来写代码,参考文章
  • 5、视频检测的思路
  • 6、优化代码,牺牲空间换取提速

回顾

  整理了这么久,也写了快一天的博客,收获还是很大的。

  1. 一次很棒的经历,从一个想法开始,找教程,找博客,然后安装软件,转化模型,使用OpenVINO,建立起了一个流程,锻炼了自己的能力。某些观点也得到了强化,比如先啃啃官方文档,写得确实很明白,比如不急着搜索error,先打印输出看看。同时也积累了一些代码和模型文件,可以用在别的场景,转移起来很快。
  2. OpenVINO开始入门了,之前都是看别人的代码,这扣一点那扣一点,拼出一个能用的程序。今天写完blog后整理出了四步走的说法,这才是我自己的东西,心里踏实很多。
  3. 意外地发现我的笔记本也有GPU,而且比CPU快好多!!!给代码打注释的时候突然想到既然写了GPU也应该验证一下,居然真的能调用,认真的回报啊哈哈哈
  4. Markdown语法,接触到了甘特图,写流程还是蛮不错的,参考文档,用起来也简单。表格,一想到要写那么多| —就头疼,搜了一下Markdown表格在线生成,还真的有,TableConvert Online,好用!
  5. Python的Numpy,维度滚动和维度交换,不用先生成一个张量再填充了~OpenCV记住了怎么显示图片,cv2.imshow('Result', image)还不够,会一闪而过,得加上cv2.waitKey(0),永远等待按键。

附录


  1. YunYang1994 tensorflow-yolov3 ↩︎

  2. OpenVINO™ toolkit Documentation ↩︎

  3. utils3文件,提取码p2y8 ↩︎

  • 4
    点赞
  • 9
    评论
  • 13
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值