如何将Yolov5 模型部署到OpenVINO上

简介: OpenVINO是英特尔推出的一款AI工具套件,可以用于快速部署AI应用和解决方案,支持计算机视觉的CNN网络结构超过150余种。它可以兼容多种主流的开源框架如PyTorch,Tensorflow,Keras,mxnet、Caffe和ONNX,并可以将上述开源框架训练好的模型,轻松的通过工具转换到OpenVINO框架上,并支持将预训练模型部署到英特尔的CPU、GPU和VPU上。

1 OpenVINO概述


       根据百度百科等资料,OpenVINO是英特尔推出的一款AI工具套件,可以用于快速部署AI应用和解决方案,支持计算机视觉的CNN网络结构超过150余种。它可以兼容多种主流的开源框架如PyTorch,Tensorflow,Kerasmxnet、Caffe和ONNX,并可以将上述开源框架训练好的模型,轻松的通过工具转换到OpenVINO框架上,并支持将预训练模型部署到英特尔的CPU、GPU和VPU上。

       对于初步想体验的开发者来说,OpenVINO将AI模型部署到英特尔的CPU是非常方面的。OpenVINO套件还包含了图片处理包OpenCV和视频处理工具包Media SDK,用于处理图像视频解码,前处理和推理结果后处理等。一般来说,在做模型推理时,多数情况下需要进行前处理和后处理,前处理包含通道变换,大小变化,取均值和归一化等操作;而后处理需要将目标检测框等特征绘制到图像上,这些操作可以使用OpenVINO和OpenCV完成。

      官网https://docs.openvino.ai/latest/index.html 给出OpenVINO支持的AI框架和硬件示意图:

0.jpg

     另外,我们需要注意,不同的硬件环境,支持的模型以及输入和输出的精度是不同的,下面给出不同硬件支持的模型格式 (https://docs.openvino.ai/latest/openvino_docs_IE_DG_supported_plugins_Supported_Devices.html):

00.jpg

    从上图可知,VPU 目前只支持FP16的模型格式。并在如下的硬件上进行了优化(Optimized for processors):

  • 6th to 12th generation Intel® Core™ processors and Intel® Xeon® processors
  • 3rd generation Intel® Xeon® Scalable processor (formerly code named Cooper Lake)
  • Intel® Xeon® Scalable processor (formerly Skylake and Cascade Lake)
  • Intel Atom® processor with support for Intel® Streaming SIMD Extensions 4.1 (Intel® SSE4.1)
  • Intel Pentium® processor N4200/5, N3350/5, or N3450/5 with Intel® HD Graphics
  • Intel® Iris® Xe MAX Graphics
  • Intel® Neural Compute Stick 2
  • Intel® Vision Accelerator Design with Intel® Movidius™ VPUs


2 Yolov5概述


       Yolov5是 YOLO算法 (You Only Look Once)的第5个版本,YOLO可以说是当前实时对象检测算法中的佼佼者,它由Redmon等人在2016年的一篇论文中命名的,目前广泛应用于多种AI 目标对象检测场景中,可以非常方便的检测出图像中的对象类别,比如人、车、动物等。虽然在某些场景下, yolov4的算法推理精度优于目前的yolov5,但是yolov5的某些新特征却更加具有吸引力。比如,yolov5在检测平均精度降低不多的基础上,具有推理模型文件更小,训练时间和推理速度更短的特点,这样在对精度要求不高的情况下,采用yolov5在模型构建、模型部署等方面将更加方便,而且推理速度更快。

      官网源码地址路径为:  https://github.com/ultralytics/yolov5   ,在官网上也给出了yolov5 (6.0 releases)不同预训练的权重模型(YOLOv5s、YOLOv5m和 YOLOv5n 等)。为了适配 OpenVINO ,这里选择 yolov5 v5.0版本。这里可以从https://github.com/ultralytics/yolov5/releases/tag/v5.0 上下载权重模型文件和源码yolov5-5.0

3 适配环境概述


  •  操作系统 : Windows 10  ( Intel CPU )
  •  Python版本: Python 3.7.7
  • OpenVINO Python Package : openvino 2021.4.2
  •  Yolov : yolov5-5.0
  • netron 5.5.3
  • onnx 1.10.2
  • opencv-python : 4.5.4.60

  关于OpenVINO套件,可以从官网进行下载w_openvino_toolkit_p_2021.4.752.exe。这里安装的路径为:

C:\Program Files (x86)\Intel\openvino_2021.4.752 。其内部目录结构如下所示:

000.jpg

       另外,openvino_toolkit还需要安装其他依赖性(C++环境) ,这里安装了cmake-3.22.1-windows-x86_64.msi 和Visual Studo 2019 with MSBuild,可以通过安装Visual Studio社区版来进行完成,其中需要勾选C++桌面开发环境等组件。具体可以参考OpenVINO官网文档 :

https://docs.openvino.ai/latest/openvino_docs_install_guides_installing_openvino_windows.html。环境搭建完成后,可以执行如下CMD命令,来验证C++环境搭建是否成功:

#临时设置环境变量"C:\Program Files (x86)\Intel\openvino_2021\bin\setupvars.bat"# 切换目录cd C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\model_optimizer\install_prerequisites
# 安装依赖项install_prerequisites.bat
#编译并运行Democd  C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo
demo_security_barrier_camera.bat

正常编译后,可以输出如下界面:

18.jpg

推理过程输出信息如下所示:

0000.jpg


4 Pytorch Yolov权重文件格式转换


      用Visual Studio Code打开yolov5-5.0 目录,并修改models/common.py文件(约39行),将self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 修改为 self.act = nn.LeakyReLU(0.1, inplace=True),示例代码(注意第7行和8行)如下所示:

classConv(nn.Module):
# Standard convolutiondef__init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper(Conv, self).__init__()
self.conv=nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
self.bn=nn.BatchNorm2d(c2)
# self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())self.act=nn.LeakyReLU(0.1, inplace=True)

     修改models/export.py文件(约77行),将 opset_version=12 改成 opset_version=10 ,示意代码如下:

# ONNX exporttry:
# import onnx  移动到 import torch之前,否则window上导出crashprint('\nStarting ONNX export with onnx %s...'%onnx.__version__)
f=opt.weights.replace('.pt', '.onnx')  # filenametorch.onnx.export(model, img, f, verbose=False, opset_version=10, input_names=['images'],
output_names=['classes', 'boxes'] ifyisNoneelse ['output'],
dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'},  # size(1,3,640,640)'output': {0: 'batch', 2: 'y', 3: 'x'}} ifopt.dynamicelseNone)
# Checksonnx_model=onnx.load(f)  # load onnx modelonnx.checker.check_model(onnx_model)  # check onnx model# print(onnx.helper.printable_graph(onnx_model.graph))  # print a human readable modelprint('ONNX export success, saved as %s'%f)
exceptExceptionase:
print('ONNX export failure: %s'%e)

注意:在Windows操作系统上,import onnx 必须要先于 import torch,否则export.py导出onnx会crash掉。

导出onnx模型,可以参考如下代码:

"""Exports a YOLOv5 *.pt model to ONNX and TorchScript formatsUsage:    $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1"""importonnximportargparseimportsysimporttimesys.path.append('./')  # to run '$ python *.py' files in subdirectoriesimporttorchimporttorch.nnasnnimportmodelsfrommodels.experimentalimportattempt_loadfromutils.activationsimportHardswish, SiLUfromutils.generalimportset_logging, check_img_sizefromutils.torch_utilsimportselect_deviceif__name__=='__main__':
parser=argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path')  # from yolov5/models/parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size')  # height, widthparser.add_argument('--batch-size', type=int, default=1, help='batch size')
parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes')
parser.add_argument('--grid', action='store_true', help='export Detect() layer grid')
parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
opt=parser.parse_args()
opt.img_size*=2iflen(opt.img_size) ==1else1# expandprint(opt)
set_logging()
t=time.time()
# Load PyTorch modeldevice=select_device(opt.device)
model=attempt_load(opt.weights, map_location=device)  # load FP32 modellabels=model.names# Checksgs=int(max(model.stride))  # grid size (max stride)opt.img_size= [check_img_size(x, gs) forxinopt.img_size]  # verify img_size are gs-multiples# Inputimg=torch.zeros(opt.batch_size, 3, *opt.img_size).to(device)  # image size(1,3,320,192) iDetection# Update modelfork, minmodel.named_modules():
m._non_persistent_buffers_set=set()  # pytorch 1.6.0 compatibilityifisinstance(m, models.common.Conv):  # assign export-friendly activationsifisinstance(m.act, nn.Hardswish):
m.act=Hardswish()
elifisinstance(m.act, nn.SiLU):
m.act=SiLU()
# elif isinstance(m, models.yolo.Detect):#     m.forward = m.forward_export  # assign forward (optional)model.model[-1].export=notopt.grid# set Detect() layer grid exporty=model(img)  # dry run# ONNX exporttry:
print('\nStarting ONNX export with onnx %s...'%onnx.__version__)
f=opt.weights.replace('.pt', '.onnx')  # filenametorch.onnx.export(model, img, f, verbose=False, opset_version=10, input_names=['images'],
output_names=['classes', 'boxes'] ifyisNoneelse ['output'],
dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'},  # size(1,3,640,640)'output': {0: 'batch', 2: 'y', 3: 'x'}} ifopt.dynamicelseNone)
# Checksonnx_model=onnx.load(f)  # load onnx modelonnx.checker.check_model(onnx_model)  # check onnx model# print(onnx.helper.printable_graph(onnx_model.graph))  # print a human readable modelprint('ONNX export success, saved as %s'%f)
exceptExceptionase:
print('ONNX export failure: %s'%e)
# Finishprint('\nExport complete (%.2fs). Visualize with https://github.com/lutzroeder/netron.'% (time.time() -t))

可以从https://github.com/ultralytics/yolov5/releases/download/v5.0/yolov5s.pt 下载权重文件,并改成yolov5s_v5.pt备用。然后支持如下命令:

#pip install openvino#pip install onnx#pip install netron# yolov5s_v5.pt -->  yolov5s_v5.onnxpython models/export.py  --weights yolov5s_v5.pt  --img-size640

创建view_onnx.py 文件用于onnx模型预览,代码如下所示:

importnetronimportosimportargparsedefparse_opt():
parser=argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default='yolov5s.onnx', help='model.pt path(s)')
opt=parser.parse_args()
returnoptdefmain(opt):
model_path=os.path.join(os.getcwd(),opt.weights)
netron.start(model_path)
if__name__=="__main__":
opt=parse_opt()
main(opt)

支持如下命令启动程序:

pythonview_onnx.py--weights'yolov5s_v5.onnx'# http://localhost:8080/

通过预览界面,找到模型结构上的3个输出节点,并向上找到第一个Conv结构,并记录名称备用,示意界面如下所示:

0001.jpg

我这里记录的是 Conv_243  Conv_246 和 Conv_249 。并执行如下命令:

python'C:\Program Files (x86)\Intel\openvino_2021.4.752\deployment_tools\model_optimizer\mo.py'--input_modelyolov5s_v5.onnx-s255--reverse_input_channels--outputConv_243,Conv_246,Conv_249

输出如下信息:

ModelOptimizerarguments:
Commonparameters:
-PathtotheInputModel:      D:\wangming\yolov5-5.0\yolov5s_v5.onnx-PathforgeneratedIR:        D:\wangming\yolov5-5.0\.
-IRoutputname:       yolov5s_v5-Loglevel:    ERROR-Batch:        Notspecified, inheritedfromthemodel-Inputlayers:         Notspecified, inheritedfromthemodel-Outputlayers:        Conv_243,Conv_246,Conv_249-Inputshapes:         Notspecified, inheritedfromthemodel-Meanvalues:  Notspecified-Scalevalues:         Notspecified-Scalefactor:         255.0-PrecisionofIR:      FP32-Enablefusing:        True-Enablegroupedconvolutionsfusing:   True-Movemeanvaluestopreprocesssection:       None-Reverseinputchannels:       TrueONNXspecificparameters:
-InferenceEnginefoundin:    C:\Users\dev2021\AppData\Local\Programs\Python\Python37\lib\site-packages\openvinoInferenceEngineversion:       2021.4.2-3976-0943ed67223-refs/pull/539/headModelOptimizerversion:        2021.4.2-3974-e2a469a3450-releases/2021/4[ WARNING ] ModelOptimizerandInferenceEngineversionsdonomatch.
[ WARNING ] ConsiderbuildingtheInferenceEnginePythonAPIfromsourcesorreinstallOpenVINO (TM) toolkitusing"pip install openvino==2021.4"[ SUCCESS ] GeneratedIRversion10model.
[ SUCCESS ] XMLfile: D:\wangming\yolov5-5.0\yolov5s_v5.xml[ SUCCESS ] BINfile: D:\wangming\yolov5-5.0\yolov5s_v5.bin[ SUCCESS ] Totalexecutiontime: 16.97seconds.

导出成功则生成yolov5s_v5.binyolov5s_v5.xml文件,且Precision of IR格式为FP32。

5 Yolov5 OpenVINO 示例


      新建一个yolov5_openvino_2021.4.py文件,其核心代码如下所示:

#!/usr/bin/env python""" Copyright (C) 2018-2019 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at      http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License."""from__future__importprint_function, divisionimportloggingimportosimportsysfromargparseimportArgumentParser, SUPPRESSfrommathimportexpasexpfromtimeimporttimeimportnumpyasnpimportcv2fromopenvino.inference_engineimportIENetwork, IECorelogging.basicConfig(format="[ %(levelname)s ] %(message)s", level=logging.INFO, stream=sys.stdout)
log=logging.getLogger()
yolov5_names= [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
'hair drier', 'toothbrush' ]
defbuild_argparser():
parser=ArgumentParser(add_help=False)
args=parser.add_argument_group('Options')
args.add_argument('-h', '--help', action='help', default=SUPPRESS, help='Show this help message and exit.')
args.add_argument("-m", "--model", help="Required. Path to an .xml file with a trained model.",
required=True, type=str)
args.add_argument("-i", "--input", help="Required. Path to an image/video file. (Specify 'cam' to work with ""camera)", required=True, type=str)
args.add_argument("-l", "--cpu_extension",
help="Optional. Required for CPU custom layers. Absolute path to a shared library with ""the kernels implementations.", type=str, default=None)
args.add_argument("-d", "--device",
help="Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is"" acceptable. The sample will look for a suitable plugin for device specified. ""Default value is CPU", default="CPU", type=str)
args.add_argument("--labels", help="Optional. Labels mapping file", default=None, type=str)
args.add_argument("-t", "--prob_threshold", help="Optional. Probability threshold for detections filtering",
default=0.5, type=float)
args.add_argument("-iout", "--iou_threshold", help="Optional. Intersection over union threshold for overlapping ""detections filtering", default=0.4, type=float)
args.add_argument("-ni", "--number_iter", help="Optional. Number of inference iterations", default=1, type=int)
args.add_argument("-pc", "--perf_counts", help="Optional. Report performance counters", default=False,
action="store_true")
args.add_argument("-r", "--raw_output_message", help="Optional. Output inference results raw values showing",
default=False, action="store_true")
args.add_argument("--no_show", help="Optional. Don't show output", action='store_true')
returnparserclassYoloParams:
# ------------------------------------------- Extracting layer parameters ------------------------------------------# Magic numbers are copied from yolo samplesdef__init__(self,  side):
self.num=3#if 'num' not in param else int(param['num'])self.coords=4#if 'coords' not in param else int(param['coords'])self.classes=80#if 'classes' not in param else int(param['classes'])self.side=sideself.anchors= [10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0, 45.0, 59.0, 119.0, 116.0, 90.0, 156.0,
198.0,
373.0, 326.0] #if 'anchors' not in param else [float(a) for a in param['anchors'].split(',')]#self.isYoloV3 = False#if param.get('mask'):#    mask = [int(idx) for idx in param['mask'].split(',')]#    self.num = len(mask)#    maskedAnchors = []#    for idx in mask:#        maskedAnchors += [self.anchors[idx * 2], self.anchors[idx * 2 + 1]]#    self.anchors = maskedAnchors#    self.isYoloV3 = True # Weak way to determine but the only one.deflog_params(self):
params_to_print= {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}
        [log.info("         {:8}: {}".format(param_name, param)) forparam_name, paraminparams_to_print.items()]
defletterbox(img, size=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True):
# Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232shape=img.shape[:2]  # current shape [height, width]w, h=size# Scale ratio (new / old)r=min(h/shape[0], w/shape[1])
ifnotscaleup:  # only scale down, do not scale up (for better test mAP)r=min(r, 1.0)
# Compute paddingratio=r, r# width, height ratiosnew_unpad=int(round(shape[1] *r)), int(round(shape[0] *r))
dw, dh=w-new_unpad[0], h-new_unpad[1]  # wh paddingifauto:  # minimum rectangledw, dh=np.mod(dw, 64), np.mod(dh, 64)  # wh paddingelifscaleFill:  # stretchdw, dh=0.0, 0.0new_unpad= (w, h)
ratio=w/shape[1], h/shape[0]  # width, height ratiosdw/=2# divide padding into 2 sidesdh/=2ifshape[::-1] !=new_unpad:  # resizeimg=cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
top, bottom=int(round(dh-0.1)), int(round(dh+0.1))
left, right=int(round(dw-0.1)), int(round(dw+0.1))
img=cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add bordertop2, bottom2, left2, right2=0, 0, 0, 0ifimg.shape[0] !=h:
top2= (h-img.shape[0])//2bottom2=top2img=cv2.copyMakeBorder(img, top2, bottom2, left2, right2, cv2.BORDER_CONSTANT, value=color)  # add borderelifimg.shape[1] !=w:
left2= (w-img.shape[1])//2right2=left2img=cv2.copyMakeBorder(img, top2, bottom2, left2, right2, cv2.BORDER_CONSTANT, value=color)  # add borderreturnimgdefscale_bbox(x, y, height, width, class_id, confidence, im_h, im_w, resized_im_h=640, resized_im_w=640):
gain=min(resized_im_w/im_w, resized_im_h/im_h)  # gain  = old / newpad= (resized_im_w-im_w*gain) /2, (resized_im_h-im_h*gain) /2# wh paddingx=int((x-pad[0])/gain)
y=int((y-pad[1])/gain)
w=int(width/gain)
h=int(height/gain)
xmin=max(0, int(x-w/2))
ymin=max(0, int(y-h/2))
xmax=min(im_w, int(xmin+w))
ymax=min(im_h, int(ymin+h))
# Method item() used here to convert NumPy types to native types for compatibility with functions, which don't# support Numpy types (e.g., cv2.rectangle doesn't support int64 in color parameter)returndict(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, class_id=class_id.item(), confidence=confidence.item())
defentry_index(side, coord, classes, location, entry):
side_power_2=side**2n=location//side_power_2loc=location%side_power_2returnint(side_power_2* (n* (coord+classes+1) +entry) +loc)
defparse_yolo_region(blob, resized_image_shape, original_im_shape, params, threshold):
# ------------------------------------------ Validating output parameters ------------------------------------------    out_blob_n, out_blob_c, out_blob_h, out_blob_w=blob.shapepredictions=1.0/(1.0+np.exp(-blob)) 
assertout_blob_w==out_blob_h, "Invalid size of output blob. It sould be in NCHW layout and height should " \
"be equal to width. Current height = {}, current width = {}" \
"".format(out_blob_h, out_blob_w)
# ------------------------------------------ Extracting layer parameters -------------------------------------------orig_im_h, orig_im_w=original_im_shaperesized_image_h, resized_image_w=resized_image_shapeobjects=list()
side_square=params.side*params.side# ------------------------------------------- Parsing YOLO Region output -------------------------------------------bbox_size=int(out_blob_c/params.num) #4+1+num_classesforrow, col, ninnp.ndindex(params.side, params.side, params.num):
bbox=predictions[0, n*bbox_size:(n+1)*bbox_size, row, col]
x, y, width, height, object_probability=bbox[:5]
class_probabilities=bbox[5:]
ifobject_probability<threshold:
continuex= (2*x-0.5+col)*(resized_image_w/out_blob_w)
y= (2*y-0.5+row)*(resized_image_h/out_blob_h)
ifint(resized_image_w/out_blob_w) ==8&int(resized_image_h/out_blob_h) ==8: #80x80, idx=0elifint(resized_image_w/out_blob_w) ==16&int(resized_image_h/out_blob_h) ==16: #40x40idx=1elifint(resized_image_w/out_blob_w) ==32&int(resized_image_h/out_blob_h) ==32: # 20x20idx=2width= (2*width)**2*params.anchors[idx*6+2*n]
height= (2*height)**2*params.anchors[idx*6+2*n+1]
class_id=np.argmax(class_probabilities)
confidence=object_probabilityobjects.append(scale_bbox(x=x, y=y, height=height, width=width, class_id=class_id, confidence=confidence,
im_h=orig_im_h, im_w=orig_im_w, resized_im_h=resized_image_h, resized_im_w=resized_image_w))
returnobjectsdefintersection_over_union(box_1, box_2):
width_of_overlap_area=min(box_1['xmax'], box_2['xmax']) -max(box_1['xmin'], box_2['xmin'])
height_of_overlap_area=min(box_1['ymax'], box_2['ymax']) -max(box_1['ymin'], box_2['ymin'])
ifwidth_of_overlap_area<0orheight_of_overlap_area<0:
area_of_overlap=0else:
area_of_overlap=width_of_overlap_area*height_of_overlap_areabox_1_area= (box_1['ymax'] -box_1['ymin']) * (box_1['xmax'] -box_1['xmin'])
box_2_area= (box_2['ymax'] -box_2['ymin']) * (box_2['xmax'] -box_2['xmin'])
area_of_union=box_1_area+box_2_area-area_of_overlapifarea_of_union==0:
return0returnarea_of_overlap/area_of_uniondefmain():
args=build_argparser().parse_args()
# ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------log.info("Creating Inference Engine...")
ie=IECore()
ifargs.cpu_extensionand'CPU'inargs.device:
ie.add_extension(args.cpu_extension, "CPU")
# -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------model=args.modellog.info(f"Loading network:\n\t{model}")
net=ie.read_network(model=model)
# ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------#    if "CPU" in args.device:#        supported_layers = ie.query_network(net, "CPU")#        not_supported_layers = [l for l in net.layers.keys() if l not in supported_layers]#        if len(not_supported_layers) != 0:#            log.error("Following layers are not supported by the plugin for specified device {}:\n {}".#                     format(args.device, ', '.join(not_supported_layers)))#            log.error("Please try to specify cpu extensions library path in sample's command line parameters using -l "#                      "or --cpu_extension command line argument")#            sys.exit(1)assertlen(net.input_info.keys()) ==1, "Sample supports only YOLO V3 based single input topologies"# ---------------------------------------------- 4. Preparing inputs -----------------------------------------------log.info("Preparing inputs")
input_blob=next(iter(net.input_info))
#  Defaulf batch_size is 1net.batch_size=1# Read and pre-process input imagesn, c, h, w=net.input_info[input_blob].input_data.shapeifargs.labels:
withopen(args.labels, 'r') asf:
labels_map= [x.strip() forxinf]
else:
labels_map=Noneinput_stream=0ifargs.input=="cam"elseargs.inputis_async_mode=Truecap=cv2.VideoCapture(input_stream)
number_input_frames=int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
number_input_frames=1ifnumber_input_frames!=-1andnumber_input_frames<0elsenumber_input_frameswait_key_code=1# Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this caseifnumber_input_frames!=1:
ret, frame=cap.read()
is_async_mode=Falseelse:
is_async_mode=Falsewait_key_code=0# ----------------------------------------- 5. Loading model to the plugin -----------------------------------------log.info("Loading model to the plugin")
exec_net=ie.load_network(network=net, num_requests=2, device_name=args.device)
cur_request_id=0next_request_id=1render_time=0parsing_time=0# ----------------------------------------------- 6. Doing inference -----------------------------------------------log.info("Starting inference...")
print("To close the application, press 'CTRL+C' here or switch to the output window and press ESC key")
print("To switch between sync/async modes, press TAB key in the output window")
cur_frame_count=0fps=28whilecap.isOpened():
# Here is the first asynchronous point: in the Async mode, we capture frame to populate the NEXT infer request# in the regular mode, we capture frame to the CURRENT infer requestifis_async_mode:
ret, next_frame=cap.read()
else:
ret, frame=cap.read()
ifnotret:
breakcur_frame_count+=1ifcur_frame_count%fps!=0 :
continueifis_async_mode:
request_id=next_request_idin_frame=letterbox(frame, (w, h))
else:
request_id=cur_request_idin_frame=letterbox(frame, (w, h))
in_frame0=in_frame# resize input_frame to network sizein_frame=in_frame.transpose((2, 0, 1))  # Change data layout from HWC to CHWin_frame=in_frame.reshape((n, c, h, w))
# Start inferencestart_time=time()
exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})
det_time=time() -start_time# Collecting object detection resultsobjects=list()
ifexec_net.requests[cur_request_id].wait(-1) ==0:
output=exec_net.requests[cur_request_id].output_blobsstart_time=time()
forlayer_name, out_blobinoutput.items():
layer_params=YoloParams(side=out_blob.buffer.shape[2])
log.info("Layer {} parameters: ".format(layer_name))
layer_params.log_params()
objects+=parse_yolo_region(out_blob.buffer, in_frame.shape[2:],
#in_frame.shape[2:], layer_params,frame.shape[:-1], layer_params,
args.prob_threshold)
parsing_time=time() -start_time# Filtering overlapping boxes with respect to the --iou_threshold CLI parameterobjects=sorted(objects, key=lambdaobj : obj['confidence'], reverse=True)
foriinrange(len(objects)):
ifobjects[i]['confidence'] ==0:
continueforjinrange(i+1, len(objects)):
ifintersection_over_union(objects[i], objects[j]) >args.iou_threshold:
objects[j]['confidence'] =0# Drawing objects with respect to the --prob_threshold CLI parameterobjects= [objforobjinobjectsifobj['confidence'] >=args.prob_threshold]
iflen(objects) andargs.raw_output_message:
log.info("\nDetected boxes for batch {}:".format(1))
log.info(" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR ")
origin_im_size=frame.shape[:-1]
print(origin_im_size)
forobjinobjects:
# Validation bbox of detected objectifobj['xmax'] >origin_im_size[1] orobj['ymax'] >origin_im_size[0] orobj['xmin'] <0orobj['ymin'] <0:
continue# color = (int(min(obj['class_id'] * 12.5, 255)),#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))color= (0,255,0)
det_label=labels_map[obj['class_id']] iflabels_mapandlen(labels_map) >=obj['class_id'] else \
str(obj['class_id'])
ifargs.raw_output_message:
log.info(
"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} ".format(det_label, obj['confidence'], obj['xmin'],
obj['ymin'], obj['xmax'], obj['ymax'],
color))
cv2.rectangle(frame, (obj['xmin'], obj['ymin']), (obj['xmax'], obj['ymax']), color, 2)
cls_name=yolov5_names[int(det_label)]
cv2.putText(frame,
""+cls_name+' '+str(round(obj['confidence'] *100, 1)) +' %',
                        (obj['xmin'], obj['ymin'] -7), cv2.FONT_HERSHEY_COMPLEX, 0.6, color, 1)
# Draw performance stats over frameinf_time_message="Inference time: N\A for async mode"ifis_async_modeelse \
"Inference time: {:.3f} ms".format(det_time*1e3)
render_time_message="OpenCV rendering time: {:.3f} ms".format(render_time*1e3)
async_mode_message="Async mode is on. Processing request {}".format(cur_request_id) ifis_async_modeelse \
"Async mode is off. Processing request {}".format(cur_request_id)
parsing_message="YOLO parsing time is {:.3f} ms".format(parsing_time*1e3)
cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 255, 0), 1)
cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255, 0, 0), 1)
cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] -20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,
                    (10, 10, 200), 1)
cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255), 1)
start_time=time()
ifnotargs.no_show:
cv2.imshow("DetectionResults", frame)
render_time=time() -start_timeifis_async_mode:
cur_request_id, next_request_id=next_request_id, cur_request_idframe=next_frameifnotargs.no_show:
key=cv2.waitKey(wait_key_code)
# ESC keyifkey==27:
break# Tab keyifkey==9:
exec_net.requests[cur_request_id].wait()
is_async_mode=notis_async_modelog.info("Switched to {} mode".format("async"ifis_async_modeelse"sync"))
cv2.destroyAllWindows()
if__name__=='__main__':
sys.exit(main() or0)

支持如下命令:

pythonyolov5_openvino_2021.4.py-idemo.mp4-myolov5s_v5.xml# 推理单张图片,则需要修改yolov5_openvino_2021.4.py# cur_frame_count += 1  # if cur_frame_count % fps != 0 :#     continuepythonyolov5_openvino_2021.4.py-idata/images/zidane.jpg-myolov5s_v5.xml

输出界面如下所示:

0002.jpg

控制台输出信息如下所示:

[ INFO ] CreatingInferenceEngine...
[ INFO ] Loadingnetwork:
yolov5s_v5.xml[ INFO ] Preparinginputs[ INFO ] Loadingmodeltotheplugin[ INFO ] Startinginference...
Toclosetheapplication, press'CTRL+C'hereorswitchtotheoutputwindowandpressESCkeyToswitchbetweensync/asyncmodes, pressTABkeyintheoutputwindow[ INFO ] LayerConv_243parameters:
[ INFO ]          classes : 80[ INFO ]          num     : 3[ INFO ]          coords  : 4[ INFO ]          anchors : [10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0, 45.0, 59.0, 119.0, 116.0, 90.0, 156.0, 198.0, 373.0, 326.0]
[ INFO ] LayerConv_246parameters:
[ INFO ]          classes : 80[ INFO ]          num     : 3[ INFO ]          coords  : 4[ INFO ]          anchors : [10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0, 45.0, 59.0, 119.0, 116.0, 90.0, 156.0, 198.0, 373.0, 326.0]
[ INFO ] LayerConv_249parameters:
[ INFO ]          classes : 80[ INFO ]          num     : 3[ INFO ]          coords  : 4[ INFO ]          anchors : [10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0, 45.0, 59.0, 119.0, 116.0, 90.0, 156.0, 198.0, 373.0, 326.0]
(720, 1280)

参考如下文档:

https://yuanyuspace.cn/2021/11/01/openvino_yolov5

https://docs.openvino.ai

https://github.com/ultralytics/yolov5/releases

相关文章
|
人工智能 PyTorch 算法框架/工具
AI计算机视觉笔记二:基于YOLOV5的CPU版本部署openvino
本文档详细记录了YOLOv5模型在CPU环境下的部署流程及性能优化方法。首先,通过设置Python虚拟环境并安装PyTorch等依赖库,在CPU环境下成功运行YOLOv5模型的示例程序。随后,介绍了如何将PyTorch模型转换为ONNX格式,并进一步利用OpenVINO工具包进行优化,最终实现模型在CPU上的高效运行。通过OpenVINO的加速,即使是在没有GPU支持的情况下,模型的推理速度也从约20帧每秒提高到了50多帧每秒,显著提升了性能。此文档对希望在资源受限设备上部署高性能计算机视觉模型的研究人员和工程师具有较高的参考价值。
1062 0
|
IDE Android开发 iOS开发
Android VS iOS:哪个操作系统更适合开发者?**
**在移动应用开发领域,Android和iOS是两大主流操作系统,它们各自拥有独特的特点和优势。本文探讨了Android和iOS操作系统在开发者视角下的差异与优劣,分析了它们在开发环境、用户群体、市场前景等方面的比较,帮助开发者选择最适合他们需求的平台。
309 29
|
8月前
|
编解码 算法 计算机视觉
YOLOv11改进策略【Head】| 增加针对 大目标 的检测层 (四个检测头)
YOLOv11改进策略【Head】| 增加针对 大目标 的检测层 (四个检测头)
1222 7
|
机器学习/深度学习 算法 开发工具
【YOLOv8量化】普通CPU上加速推理可达100+FPS
【YOLOv8量化】普通CPU上加速推理可达100+FPS
1841 0
|
10月前
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
245 5
|
11月前
|
机器学习/深度学习 计算机视觉 网络架构
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目DWRSeg是一种高效的实时语义分割网络,通过将多尺度特征提取分为区域残差化和语义残差化两步,提高了特征提取效率。它引入了Dilation-wise Residual (DWR) 和 Simple Inverted Residual (SIR) 模块,优化了不同网络阶段的感受野。在Cityscapes和CamVid数据集上的实验表明,DWRSeg在准确性和推理速度之间取得了最佳平衡,达到了72.7%的mIoU,每秒319.5帧。代码和模型已公开。
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
|
人工智能 自然语言处理 机器人
实战精选 | 5分钟利用 OpenVINO™ 部署 Qwen2.5
本文将以 Qwen2.5-7B-Instruct 为例,介绍如何利用 OpenVINO™ 的 Python API 在本地部署 Qwen2.5 系列模型。
实战精选 | 5分钟利用 OpenVINO™ 部署 Qwen2.5
|
机器学习/深度学习 自然语言处理
YOLOv5改进 | 2023 | CARAFE提高精度的上采样方法(助力细节长点)
YOLOv5改进 | 2023 | CARAFE提高精度的上采样方法(助力细节长点)
562 2
|
PyTorch 算法框架/工具 Python
yolov5的完整部署(适合新人和懒人,一键安装)
这篇文章为新人和希望简化部署过程的用户介绍了如何一键安装和配置YOLOv5环境,包括安装Anaconda、设置镜像源、安装PyCharm、创建虚拟环境、下载YOLOv5项目、安装依赖以及在PyCharm中配置和运行项目。
6480 0
yolov5的完整部署(适合新人和懒人,一键安装)
|
机器学习/深度学习 并行计算 PyTorch
ONNX 优化技巧:加速模型推理
【8月更文第27天】ONNX (Open Neural Network Exchange) 是一个开放格式,用于表示机器学习模型,使模型能够在多种框架之间进行转换。ONNX Runtime (ORT) 是一个高效的推理引擎,旨在加速模型的部署。本文将介绍如何使用 ONNX Runtime 和相关工具来优化模型的推理速度和资源消耗。
6033 4