关于人工智能:用树莓派4b构建深度学习应用九Yolo篇

9次阅读

共计 7232 个字符,预计需要花费 19 分钟才能阅读完成。

前言

上一篇咱们在树莓派上装置了 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.git
cd 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.sh
python 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.tgz
tar -xvzf l_openvino_toolkit_p_2020.4.287.tgz

2. 装置依赖

pip3 install defusedxml
pip3 install networkx
pip3 install test-generator==0.1.1
# 这里咱们只须要转换 onnx
cd l_openvino_toolkit_p_2020.4.287
sudo ./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.git
cd yolov5
pip3 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.pt
mv 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.onnx
Export 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 软路由,
打造一劳永逸的上网环境,
敬请期待 …


正文完
 0