使用OpenVINO部署并行的人体关键点检测模型

1 OpenVINO工具包 简介

OpenVINO™工具包可快速部​​署模拟人类视觉的应用程序和解决方案。该工具包基于卷积神经网络(CNN),可在英特尔®硬件上扩展计算机视觉(CV)工作负载,从而最大限度地提高性能。

OpenVINO™工具包包括以下组件:

  • Deep Learning Deployment Toolkit (DLDT)
  • Open Model Zoo
  • Post-Training Optimization tool
  • Deep Learning Workbench
  • Deep Learning Streamer (DL Streamer)
  • OpenCV
  • Drivers and runtimes for OpenCL™ version 2.1
  • Intel® Media SDK

我们主要使用的是第一个组件:Deep Learning Deployment Toolkit (DLDT)——深度学习部署工具包。
深度学习部署工具包主要用于深度学习模型在推理方面的部署和优化,其主要包含两个部分:

  • 深度学习模型优化器:
    一种跨平台的命令行工具,用于导入模型并为通过推理引擎进行最佳执行做准备。Model Optimizer导入,转换和优化模型,这些模型在流行的框架(例如Caffe *,TensorFlow *,MXNet *,Kaldi *和ONNX *)中进行了培训。
  • 深度学习推理引擎:
    统一的API,可在许多硬件类型上进行高性能推理,包括以下各项:
    • 英特尔®CPU
    • 英特尔®集成显卡
    • 英特尔®神经计算棒2
    • 带有英特尔®Movidius™视觉处理单元(VPU)的英特尔 ®视觉加速器设计

参考: OpneVINO官方网站

2 OpenVINO 推理引擎的介绍

2.1 使用模型优化器转化为IR文件

在使用OpenVINO的推理引擎之前,必须使用OpenVINO的模型优化器(Model Optimizer)将深度学习模型文件转化为中间表示(IR)文件(即.bin文件和.xml文件)。具体可以参考:模型优化器开发人员指南.
可以用模型优化器将Tensorflow,MXNet,Kaldi,ONNX模型转化为IR文件。

2.2 使用推理引擎进行推理

使用模型优化器将原始模型转化为IR文件后,便可以使用OpenVINO的推理引擎对深度模型进行推理。
推理引擎是一组C ++库,提供了公共API,可在将模型部署在CPU,GPU,VPU或FPGA等硬件设备上进行推理。尽管推理引擎主要使用C++进行构建,但是也提供了相关的python api。
使用推理引擎的流程如下:

  • 1 创建推理引擎核心对象
  • 2 读取中间表示
  • 3 编译和加载网络到设备
  • 4 设置置输入数据
  • 5 执行推理
  • 6 获取输出

在操作系统为Windows 10的环境下,我们按照上述步骤使用python api来构造推理引擎:

import os
import numpy as np
#调用推理引擎相关模块
from openvino.inference_engine import IENetwork, IECore

#创建推理引擎类
class InferenceEngineOpenVINO:
    #输入IR文件中.xml文件的路径,以及推理设备
    def __init__(self, net_model_xml_path, device):
        self.device = device
        net_model_bin_path = os.path.splitext(net_model_xml_path)[0] + '.bin'
        #1 创建推理引擎核心对象
        self.ie = IECore()
        #2 读取中间表示文件(.xml,.bin文件)
        self.net = IENetwork(model=net_model_xml_path, weights=net_model_bin_path)
        
        required_input_key = {'data'}
        #检验网络的输入和输出是否与设定一致(根据自己网络的情况而定)
        assert required_input_key == set(self.net.inputs.keys()), \
            'Demo supports only topologies with the following input key: {}'.format(', '.join(required_input_key))
        required_output_keys = {'Conv_229', 'Add_151', 'Add_153'}
        assert required_output_keys.issubset(self.net.outputs.keys()), \
            'Demo supports only topologies with the following output keys: {}'.format(', '.join(required_output_keys))
        #3 将网络加载到特定的设备
        self.exec_net = self.ie.load_network(network=self.net, num_requests=1, device_name=device)
	#定义推理方法
    def infer(self, img):
    	# 4 设置输入数据,根据网络输入的格式对输入图片进行缩放
        input_layer = next(iter(self.net.inputs))
        n, c, h, w = self.net.inputs[input_layer].shape
        if h != img.shape[0] or w != img.shape[1]:
            self.net.reshape({input_layer: (n, c, img.shape[0], img.shape[1])})
            self.exec_net = self.ie.load_network(network=self.net, num_requests=1, device_name=self.device)
        img = np.transpose(img, (2, 0, 1))[None, ]
		# 5 使用指定设备进行推理
        inference_result = self.exec_net.infer(inputs={'data': img})
		# 6 返回推理结果
        return inference_result

推理引擎构造完成后,我们可以在主函数调用InferenceEngineOpenVINO类来使用推理引擎,得到推理结果

#调用InferenceEngineOpenVINO类
from modules.inference_engine_openvino import InferenceEngineOpenVINO
#实例化对象
net = InferenceEngineOpenVINO(model, device)
#使用推理引擎得到推理结果
inference_result = net.infer(img)

3 OpenVINO 查看推理引擎可用设备

当我们使用需要使用不同设备进行推理的时候,需要查看可执行的设备,特别是当有多个相同的设备的时候,需要加入设备编号进行区别。
同样我们可以使用python api中 Inference_engine 模块中 IECore类的available_devices方法得到当前可用于OpenVINO推理的硬件设备。
本实验所使用的计算机的CPU为:Intel® Core™ i7-8750H,核显为:Intel® UHD Graphics 630。 此外,如图所示,还插入了两枚Intel第二代神经计算棒(NCS2)。
在这里插入图片描述
运行下列代码:

from openvino.inference_engine import IECore

ie=IECore().available_devices
print(ie)

得到结果:

[E:] [BSL] found 0 ioexpander device
['CPU', 'GNA', 'GPU', 'MYRIAD.2.2-ma2480', 'MYRIAD.2.3-ma2480']

可以看到,检测到了5个设备,包括CPU,GNA,GPU,两个 NCS2 。检测到的两个NCS2 分别具有不同的编号:2.2 和 2.3。
下面我们将讨论运行同时使用推理引擎进行多个推理的情况。

4 单线程运行推理引擎

4.1 使用Intel 集成GPU 单线程运行

我们将使用OpenVINO同时运行两个 人体关键点检测模型。首先我们先看一下运行单个模型在集成GPU的推理的时间。将影片《功夫》的视频片段作为测试对象,测试视频的分辨率为1024×432。可以看到其FPS可以达到25.7。而根据输出显示,GPU推理时间约为0.025s, 推理、计算坐标和渲染所用的总时间约为: 0.043s。
在这里插入图片描述
接下来,我们以循序结构串行运行两个关键点检测模型,检测对象不变。可以看到FPS变为10.8FPS,减小到原来的一半左右。推理总时间为:0.050s ,推理、计算坐标和渲染所用的总时间约为: 0.096s。因为串行运行使得前一个模型必须运行完以后再进行后一个模型推理,因此推理时间进行了累加,使得速度变慢。
在这里插入图片描述

4.2 使用Intel 第二代神经计算棒(NCS 2)单线程运行

首先我们先看一下运行单个模型在NCS 2的推理的时间。可以看到其FPS可以达到8.0。而根据输出显示,GPU推理时间约为0.115s, 推理、计算坐标和渲染所用的总时间约为: 0.135s。
在这里插入图片描述
同样我们使用NCS 2 串行运行两个人体关键点检测模型。由于是串行运行,因此我们只使用一个神经计算棒,运行结果如下所示。推理时间为0.23s左右,总时长为0.27s左右。NCS 2的推理时间和总时间增加为原来的两倍。对比GPU,推理时间延长,而计算坐标,渲染等工作由cpu执行,因此差别不大。

在这里插入图片描述

5 多线程运行推理引擎

5.1 使用Intel 集成GPU 多线程运行

我们使用调用python的threading模块,将运行两个模型的代码分别写入fun1和fun2,定义两个线程分别执行,即可完成推理引擎的多线程运行。

import threading
def fun1():
	'''
	'''
def fun2():
	'''
	'''
threads = []
threads.append(threading.Thread(target=fun1))
threads.append(threading.Thread(target=fun2))
if __name__ == '__main__':
    for t in threads:
        t.start()

运行结果如下:
在这里插入图片描述
运行的FPS约为11.5,相较于串行的结果仅有少许提升。为此,我们查看推理用时和所用的总时长。结果如下

当前线程的名字是:  Thread-1
推理时间:  0.025995254516601562 总时间: 0.0967397689819336
当前线程的名字是:  Thread-2
vpu2 推理时间:  0.02593088150024414 总时间: 0.07882571220397949


我们发现,每个线程的推理时间与之前运行的单个模型的推理时间相差不大,但是总时间却大大增加。说明在一个线程中,推理完成后并没有立刻执行下面的代码,而是等待其它线程运行,因此造成总时间的延长。
究其原因,主要是python多线程是伪多线程,主要是受限于GIL的存在。GIL(Global Interpreter Lock 全局解释器锁),这是目前占统治地位的python解释器CPython中为了保证数据安全所实现的一种锁。不管进程中有多少线程,只有拿到了GIL锁的线程才可以在CPU上运行,即时是多核处理器。对一个进程而言,不管有多少线程,任一时刻,只会有一个线程在执行。对于CPU密集型的线程,其效率不仅仅不高,反而有可能比较低。

5.2 使用Intel 第二代神经计算棒(NCS 2)多线程运行

由于使用神经计算棒进行并行测试,我们使用两根计算棒分别进行运行两个模型。分别将推理引擎的device设置如下。

from modules.inference_engine_openvino import InferenceEngineOpenVINO
net1 = InferenceEngineOpenVINO(model,device='MYRIAD.2.2-ma2480' )
net2 = InferenceEngineOpenVINO(model,device='MYRIAD.2.3-ma2480' )

测试结果如下所示。FPS达到了4.8左右,相较于串行运行性能有所提升,但是仍未达到单个模型运行的性能,原因同上。
在这里插入图片描述

6 使用OpenVINO的异步推理方法

为了提高多个模型的运行速度,克服python 的伪多线程带来的困难,使用推理引擎中异步推理的python api,之前运行的推理引擎使用的都是 ExecutableNetwork 类中的 infer() 方法,infer()方法为阻塞执行,即当前 infer() 语句运行完毕后,才执行下一条语句。因此使用infer()方法执行两个模型的推理是串行的,只有上一个模型运行完毕后,下一个模型才能运行,造成时间的浪费。
根据 Intel 曹慧燕老师的指导,我采用推理引擎的异步推理方法来异步运行两个模型。根据官网的 python api指南,将 ExecutableNetwork 类中的 infer() 方法替换为start_async()方法。重新构造推理引擎如下:

import os
import numpy as np
from openvino.inference_engine import IENetwork, IECore


class InferenceEngineOpenVINO:
    def __init__(self, net_model_xml_path, device):
        self.device = device
        net_model_bin_path = os.path.splitext(net_model_xml_path)[0] + '.bin'
        self.net = IENetwork(model=net_model_xml_path, weights=net_model_bin_path)

        required_input_key = {'data'}
        assert required_input_key == set(self.net.inputs.keys()), \
            'Demo supports only topologies with the following input key: {}'.format(', '.join(required_input_key))
        required_output_keys = {'Conv_229', 'Add_151', 'Add_153'}
        assert required_output_keys.issubset(self.net.outputs.keys()), \
            'Demo supports only topologies with the following output keys: {}'.format(', '.join(required_output_keys))

        self.ie = IECore()
        self.exec_net1 = self.ie.load_network(network=self.net, num_requests=1, device_name='MYRIAD.2.2-ma2480')
        self.exec_net2 = self.ie.load_network(network=self.net, num_requests=1, device_name='MYRIAD.2.3-ma2480')

    def infer(self, img1,img2, request_id):
        input_layer = next(iter(self.net.inputs))
        n, c, h, w = self.net.inputs[input_layer].shape
        if h != img1.shape[0] or w != img1.shape[1]:
            self.net.reshape({input_layer: (n, c, img1.shape[0], img1.shape[1])})
            self.exec_net1 = self.ie.load_network(network=self.net, num_requests=1, device_name='MYRIAD.2.2-ma2480')
        img1 = np.transpose(img1, (2, 0, 1))[None, ]

        if h != img2.shape[0] or w != img2.shape[1]:
            self.net.reshape({input_layer: (n, c, img2.shape[0], img2.shape[1])})
            self.exec_net2 = self.ie.load_network(network=self.net, num_requests=1, device_name='MYRIAD.2.3-ma2480')
        img2 = np.transpose(img2, (2, 0, 1))[None, ]

        infer_request_handle1 = self.exec_net1.start_async(request_id=request_id, inputs={'data': img1})

        infer_request_handle2 = self.exec_net2.start_async(request_id=request_id, inputs={'data': img2})
        infer_status1 = infer_request_handle1.wait()
        infer_status2 = infer_request_handle2.wait()
        inference_result11 = infer_request_handle1.outputs['Conv_229']
        inference_result21 = infer_request_handle1.outputs['Add_151']
        inference_result31 = infer_request_handle1.outputs['Add_153']
        inference_result12 = infer_request_handle2.outputs['Conv_229']
        inference_result22 = infer_request_handle2.outputs['Add_151']
        inference_result32 = infer_request_handle2.outputs['Add_153']

        inference_result_1 = (inference_result11[0],
                            inference_result21[0], inference_result31[0])
        inference_result_2 = (inference_result12[0],
                            inference_result22[0], inference_result32[0])

        return inference_result_1,inference_result_2

重新运行程序,得到在两根神经计算帮的结果如下:
在这里插入图片描述
可以看到FPS达到了6.3左右。相较于之前单线程、多线程有了充分的提高。之所以小于之前单个模型的8 FPS,主要是由于异步运行要设置一个略高于推理时间的等待时间,防止程序在一次运行未完成时多次调用设备。除了推理以外,后续的关键点计算和渲染也的时间也是需要双倍的,因此其FPS略小于单个模型运行时间。

OpenVINO计算机视觉—实例实战

11-02
手把手讲授如何搭建成功OpenVINO框架,并且使用预训练模型快速开发超分辨率、道路分割、汽车识别、人脸识别、人体姿态和行人车辆分析。得益于OpenVINO框架的强大能力,这些例子都能够基于CPU达到实时帧率。 课程的亮点在于在调通Demo的基础上更进一步:一是在讲Demo的时候,对相关领域问题进行分析(比如介绍什么是超分辨率,有什么作用)、预训练模型的来龙去脉(来自那篇论文,用什么训练的)、如何去查看不同模型的输入输出参数、如何编写对应的接口参数进行详细讲解;二是基本上对所有的代码进行重构,也就是能够让例子独立出来,并且给出了带有较详细注释的代码;三是注重实际运用,将Demo进一步和实时视频处理框架融合,形成能够独立运行的程序,方便模型落地部署;四是重难点突出、注重总结归纳,对OpenVINO基本框架,特别是能够提高视频处理速度的异步机制和能够直接部署解决实际问题的骨骼模型着重讲解,帮助学习理解;五是整个课程准备精细,每一课都避免千篇一律,前一课有对后一课的预告,后一课有对前一课的难点回顾,避免学习过程中出现突兀;六是在适当的时候拓展衍生,不仅讲OpenVINO解决图像处理问题,而且还补充图像处理的软硬选择、如何在手机上开发图像处理程序等内容,帮助拓展视野,增强对行业现状的了解。 基本提纲: 1、课程综述、环境配置 2、OpenVINO范例-超分辨率(super_resolution_demo) 3、OpenVINO范例-道路分割(segmentation_demo) 4、OpenVINO范例-汽车识别(security_barrier_camera_demo) 5、OpenVINO范例-人脸识别(interactive_face_detection_demo) 6、OpenVINO范例-人体姿态分析(human_pose_estimation_demo) 7、OpenVINO范例-行人车辆分析(pedestrian_tracker_demo) 8、NCS和GOMFCTEMPLATE 9、课程小结,资源分享
©️2020 CSDN 皮肤主题: 1024 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值