前言
上一篇咱们在树莓派上装置了OpenVINO的环境,并跑了几个官网demo,作为关键点的模型转换工作,以各个版本的yolo实现为例,在这篇做一下实现。
指标检测是人工智能利用比拟成熟的畛域,不仅要可能辨认出图片的指标,还要定位其地位,在主动驾驶方面会是一个根底的场景。个别分为两大类别,一类是two-stage的,基于R-CNN,Fast R-CNN, Faster R-CNN等等,学生成待选框(Region Proposal),再进行分类获取类别,回归获取地位;另一类就是Yolo,SSD这种one-stage算法,间接用CNN网络获取指标和地位。
相对来说,R-CNN系的精度更高,但速度慢,Yolo系的则速度快,准确率低些。在很多CV畛域里,只有保障分类的准确率,检测速度比定位精度重要的多,而one-stage的模型部署有着人造的劣势,极大的加重算力无限的边缘设施的计算压力。
Yolo则是指标检测类优化速度的代表,而转换为Openvino后,速度还能更进一步。这篇次要介绍两种支流框架 Tensorflow 和 Pytorch 的模型转换到 Openvino的办法。
首先,Tensorflow 模型的转化流程是,先将权重文件.weight 转换成动态图 .pb文件,再转化成 IR 模型的 .bin 和 .xml,最初部署到神经棒运行。咱们先来跑一个yolov4-tiny的利用来体验一下。
Yolov4 利用
1. 下载源码
git clone https://github.com/TNTWEN/OpenVINO-YOLOV4.gitcd OpenVINO-YOLOV4
2. 将 weight --> pb
下载 yolov4.weight 和 yolov4-tiny.weight 放入该目录下
python convert_weights_pb.py --class_names cfg/coco.names --weights_file yolov4-tiny.weights --data_format NHWC --tiny
目录下有输入 frozen_darknet_yolov4_model.pb 就转化胜利了。
Tip:其中必须指定数据格式为NHWC,以匹配 intel NCS2 上对应的格局。
Tip:如遇到有 ‘cloud’ 导入谬误的信息,那是因为编译 TF 时开启了 --nogcp 标记,导致 tensorflow/contrib/cloud 没有被退出 pip 的安装包。这里只有将 init 里的两行代码正文掉即可修复这个bug了。其中必须指定数据格式为NHWC,所以这里须要 reverse_input_channels 翻转一下对应的输出通道。
/home/pi/my_envs/tensorflow/lib/python3.7/site-packages/tensorflow/contrib/__init__.py
3. 初始化openvino环境
要在Windows 或 linux主机上做转换,须要装置 OpenVINO 开发工具套件。
"C:\Program Files (x86)\IntelSWTools\openvino\bin\setupvars.bat"
4. 将 pb --> ir
切换到 OpenVINO-YOLOV4 目录下,将 pb 文件 转化为 xml 和 bin 文件。
python "C:\Program Files (x86)\IntelSWTools\openvino_2020.4.287\deployment_tools\model_optimizer\mo.py" --input_model frozen_darknet_yolov4_model.pb --transformations_config yolo_v4_tiny.json --batch 1 --reverse_input_channels
Tip:转换 IR 模型前肯定要留神 op 算子的兼容性,以及对应平台的数据精度。 以下这个页面能够查问到具体信息,很多模型转化失败是因为还没有失去反对。
https://docs.openvinotoolkit.org/latest/openvino_docs_IE_DG_supported_plugins_Supported_Devices.html
5. 运行模型
在树莓派上运行模型,FPS 稳固在 6-7 帧左右
source ~/my_envs/tensorflow/bin/activate/opt/intel/openvino/bin/setupvars.shpython object_detection_demo_yolov4_async.py -i cam -m frozen_darknet_yolov4_model.xml -d MYRIAD
Yolov5 利用
Yolov5 次要引入了马赛克加强,自适应锚框,这些新个性,构造上与 Yolov4 的差别不大,不过v5的开源版本是 pytorch 的,绝对 darknet 来说更容易转化到各个平台上部署些。
工作流:
另一种支流框架 Pytorch 若要用 openvino 做优化的话,那其转换流程为,先将 pytorch 的模型文件 .pt,转化为 onnx 格局,而后再转化成 IR 模型,即可部署到神经棒上了。
接下来咱们用最新版的 Yolov5 来跑一下这个过程。
1. 在 Ubuntu 上装置 OpenVINO 开发工具
下载安装包 2020年4月的 linux 版本
cd ~/Downloads/wget http://registrationcenter-download.intel.com/akdlm/irc_nas/16803/l_openvino_toolkit_p_2020.4.287.tgztar -xvzf l_openvino_toolkit_p_2020.4.287.tgz
2. 装置依赖
pip3 install defusedxmlpip3 install networkxpip3 install test-generator==0.1.1# 这里咱们只须要转换 onnxcd l_openvino_toolkit_p_2020.4.287sudo ./install_prerequisites_onnx.sh
3. 建设虚拟环境
Python>=3.8,PyTorch==1.5.1,ONNX>=1.7。
conda activate openvino # 进入ubuntu 的虚拟环境git clone https://github.com/ultralytics/yolov5.gitcd yolov5pip3 install -r requirements.txt onnx# 降版本pip install torch==1.5.1 torchvision==0.6.1
4. 导出在 pytorch 上训练好的 yolov5 模型
先下载 yolov5s.pt(或者训练自有数据集的yolov5模型),放入目录下
wget https://github.com/ultralytics/yolov5/releases/download/v2.0/yolov5s.ptmv yolov5s.pt yolov5s_2.0.pt
Tip:
要下载 v2.0 with nn.LeakyReLU(0.1) 的版本,因为 3.0 的 nn.Hardswish 还没有被反对。
5. 批改激活函数
因为onnx和openvino 还不反对 Hardswitch,要将 Hardswish 激活函数改成 Relu 或者 Leaky Relu。
# yolov5/models/common.py# Line 26 in 5e0b90d# self.act = nn.Hardswish() if act else nn.Identity()self.act = nn.Relu() if act else nn.Identity()
6. 批改 yolo.py
# yolov5/models/yolo.py# Lines 49 to 53 in 5e0b90d# y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i] # xy # y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh # z.append(y.view(bs, -1, self.no)) # # return x if self.training else (torch.cat(z, 1), x)
批改输入层重叠,不蕴含输出层
c=(y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i] # xy d=(y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh e=y[..., 4:] f=torch.cat((c,d,e),4) z.append(f.view(bs, -1, self.no)) return x if self.training else torch.cat(z, 1)
7. 批改 export.py
# yolov5/models/export.py# Line 31 in 5e0b90d# model.model[-1].export = True # set Detect() layer export=True model.model[-1].export = False
因为版本为10的 opset 能反对 resize 算子,要批改 opset 版本号。
# yolov5/models/export.py# Lines 51 to 52 in 5e0b90d# torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], torch.onnx.export(model, img, f, verbose=False, opset_version=10, input_names=['images'], output_names=['classes', 'boxes'] if y is None else ['output'])
Tip:
务必确保 torch==1.15.1,torchvision==0.6.1,onnx==1.7,opset=10。激活函数为 Relu,并批改了网络推理层。
8. 将 pt --> onnx
export PYTHONPATH="$PWD" python models/export.py --weights yolov5s_2.0.pt --img 640 --batch 1
显示导出为 onnx 和 torchscript 文件即可。
ONNX export success, saved as ./yolov5s.onnxExport complete. Visualize with https://github.com/lutzroeder/netron.
9. 将 onnx --> ir
python3 /opt/intel/openvino_2020.4.287/deployment_tools/model_optimizer/mo.py --input_model yolov5s_2.0.onnx --output_dir ./out --input_shape [1,3,640,640]
顺利的话,就能在 out 目录下生成 yolov5s 的 IR 模型了,接着将文件传输到树莓派上。
Tip:
这里要匹配 yolov5s 的 input shape 为 [ 1, 3, 640, 640 ]。
10. 批改参数匹配训练模型
git clone https://github.com/linhaoqi027/yolov5_openvino_sdk.git
批改推理设施和输出 shape
# device = 'CPU'# input_h, input_w, input_c, input_n = (480, 480, 3, 1)device = 'MYRIAD'input_h, input_w, input_c, input_n = (640, 640, 3, 1)
批改类别信息
# label_id_map = {# 0: "fire",# }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']label_id_map = {index: item for index, item in enumerate(names)}
批改多类别输入
for idx, proposal in enumerate(data): if proposal[4] > 0: print(proposal) confidence = proposal[4] xmin = np.int(iw * (proposal[0] / 640)) ymin = np.int(ih * (proposal[1] / 640)) xmax = np.int(iw * (proposal[2] / 640)) ymax = np.int(ih * (proposal[3] / 640)) idx = int(proposal[5]) #if label not in label_id_map: # log.warning(f'{label} does not in {label_id_map}') # continue detect_objs.append({ 'name': label_id_map[idx], 'xmin': int(xmin), 'ymin': int(ymin), 'xmax': int(xmax), 'ymax': int(ymax), 'confidence': float(confidence) })
11. 推理输入
if __name__ == '__main__': # Test API img = cv2.imread('../inference/images/bus.jpg') predictor = init() import time t = time.time() n = 10 for i in range(n): result = process_image(predictor, img) print("均匀推理工夫",(time.time()-t)/n) print("FPS", 1/((time.time()-t)/n)) # log.info(result) for obj in json.loads(result)['objects']: print(obj)
python inference.py
yolov5s 的 FPS 才 2 帧左右,相比 yolov4-tiny 来说速度不算快,input shape 640 比 yolov4 的416大了不少,次要耗时集中在神经棒的推理之中,需消耗 377ms,还是蛮可观的。
另外,转换后的 IR 模型在 CPU 上和 MYRIAD 上推理的置信度差别也很高,看来 yolov5 还有很大的优化空间。
要谋求极致的检测速度,还有几个方向能够尝试:
- 多个神经棒分布式推理;
- 应用多线程推理;
- 采纳异步形式刷新屏幕;
- 选用更小的模型;
- 推理代码由 Python 改为 C++
特地是最近优图开源了一个yolo-fastest版本,backbone为EfficientNet-lite 使得训练的模型权重才1.2M,yolo-fastest-xl 也才3.3M,十分的玲珑。
这个 MobileNet SSD 居然在树莓派4 + 5个 NCS2 上跑到了 FPS 40以上,Amazing!!!
这篇次要介绍了 Tensorflow 和 Pytorch 两种支流框架的转换到 OpenVINO模型的形式。
- .weight --> .pb --> .xml .bin
- .pt --> onnx --> .xml .bin
其实还有更多AI框架,大抵也是通过 pb,onnx,ir,这类两头模型来互相转化,比方利用于 TensorRT,Tensorflow Lite 等等。
个别只有理解,输入输出层的构造,每种模型对应的权重和网络结构文件,留神op算子的反对,就能用框架提供的 pipeline 来做转换了。
最初的伎俩,就是重写网络拓扑,用相似 load_weight 的办法来导入权重,再 save 到指标框架中了。
代码下载
本期相干文件材料,可在公众号后盾回复:“rpi09”,获取下载链接。
下一篇预报
咱们将介绍树莓派上的代理软件,
部署Openwrt软路由,
打造一劳永逸的上网环境,
敬请期待...