端侧部署YOLOv5模型
- Ai
- 2天前
- 38热度
- 0评论
导出 ONNX模型
python export.py --weights runs/train/exp2/weights/
NPU不支持动态输入,使用onnxim工具进行转换为固定输入,先安装onnxsim工具。
pip install onnxsim -i https://pypi.doubanio.com/simple/
接着进行转换
python -m onnxsim runs/train/exp2/weights/best.onnx yolov5s-sim.onnx --input-shape 1,3,640,640
模型裁剪
在实际端侧中,NPU端量化的后处理运算不适合使用uint8量化,一般使用float的混合量化,但这样相对麻烦,本文示例将后处理放在CPU测进行,所以我们需要把下图中的后处理部分裁剪掉。
import onnx
onnx.utils.extract_model('./yolov5s-mask.onnx', './yolov5s-mask-rt.onnx', ['images'], ['/model.24/Reshape_output_0','/model.24/Reshape_8_output_0','/model.24/Reshape_16_output_0'])
使用上面的python可以进行裁剪,输入为[images],输出为3个节点,下面是最后一个节点的示例截图。实际要根据模型文件进行调整。
python extrat-mask.py
接着使用上面的命令,就输出了裁剪后的模型yolov5s-mask-rt.onnx。
如果原生的模型没有将后处理裁剪,输入输出如下:
输出的tensor[1,25200,85],其中25200=3x(20x20+40x40+80x80),即3个特征图一共25200个先验框。
原生模型使用裁剪后使用netron.app打开得到输入输出如下:
YOLOv5模型参数含义详细解释如下:
- 模型名称: 表示模型或图结构的名称,此处为从主图结构中提取的名称。
- 输入参数:float32[1,3,640,640],表示输入张量的数据类型和维度。1表示一次处理的样本,3为通道数,输入的高宽均为640,此前YOLOv3是416。
- 输出参数:有3个输出张量。
-- /model.24/Reshape_output_0:表示8倍降采样率,输出为float32[1,3,85,80,80],网格划分为80x80,每个网格有3给先验框,每个先验框预测包含85个元素(坐标4、置信度1、类别80)。
-- /model.24/Reshape_8_output_0:float32[1,3,85,40,40],网格尺寸为40x40。
-- /model.24/Reshape_16_output_0:float32[1,3,85,20,20],网格尺寸为20x20。 - 模型参数数量:parameter参数为7225908,表示模型中参数的总数,这是模型复杂度和计算资源需求的重要指标。
再来看看此次针对口罩微调后裁剪后的模型输入输出,使用netron.app打开得到输入输出如下:
上图可以看到,网格划分、先验框数量是一样的,不一样的是预测的元素为8(坐标4,置信度1,类别3)。
创建端侧转换环境
sudo docker images
sudo docker run --ipc=host -itd -v /home/xxx/ai/docker_data:/workspace --name laumy_npu_v1.8.x ubuntu-npu:v1.8.11 /bin/bash
sudo docker ps -a
sudo docker exec -it 55f9cd9eb15e /bin/bash
在进行端侧部署前,需要准备量化环境,这里直接使用的是docker环境。
模型转换
创建目录
|-- data
| |-- maksssksksss0.png
| |-- maksssksksss1.png
| |-- maksssksksss10.png
| |-- maksssksksss11.png
| |-- maksssksksss12.png
| |-- maksssksksss13.png
| |-- maksssksksss14.png
| |-- maksssksksss15.png
| |-- maksssksksss16.png
| |-- maksssksksss17.png
| |-- maksssksksss18.png
| |-- maksssksksss19.png
| |-- maksssksksss2.png
| |-- maksssksksss3.png
| |-- maksssksksss4.png
| |-- maksssksksss5.png
| |-- maksssksksss6.png
| |-- maksssksksss7.png
| |-- maksssksksss8.png
| `-- maksssksksss9.png
|-- dataset.txt
`-- yolov5s-mask-rt.onnx
准备数据量化的数据data、数据配置dataset.txt(内容如下)、裁剪的模型yolov5s-mask-rt.onnx。
./data/maksssksksss0.png
./data/maksssksksss1.png
./data/maksssksksss2.png
./data/maksssksksss3.png
./data/maksssksksss4.png
./data/maksssksksss5.png
./data/maksssksksss6.png
./data/maksssksksss7.png
./data/maksssksksss8.png
./data/maksssksksss9.png
./data/maksssksksss10.png
./data/maksssksksss11.png
./data/maksssksksss12.png
./data/maksssksksss13.png
./data/maksssksksss14.png
./data/maksssksksss15.png
./data/maksssksksss16.png
./data/maksssksksss17.png
./data/maksssksksss18.png
./data/maksssksksss19.png
模型导入
pegasus import onnx --model yolov5s-mask-rt.onnx --output-data yolov5s-mask-rt.data --output-model yolov5s-mask-rt.json
模型导入将输出yolov5s-mask-rt.json和yolov5s-mask-rt.data文件。前者为后期量化需要的网络结构文件,后者为模型网络权重文件。
前后处理配置文件yml
生成前处理配置文件
pegasus generate inputmeta --model yolov5s-mask-rt.json --input-meta-output yolov5s-mask-rt_inputmeta.yml
生成后处理配置文件,因为后处理是在cpu上处理并且我们已经裁剪掉了onn模型的后处理,可以不生成。
pegasus generate postprocess-file --model yolov5s-mask-rt.json --postprocess-file-output yolov5s-mask-rt_postprocess_file.yml
上面根据模型网络结构文件yolov5s-mask-rt.json转化生成后续量化需要的前处理和后处理描述文件,格式为yml格式。
input_meta:
databases:
- path: dataset.txt #表示模型量化需要的数据描述文件
type: TEXT
ports:
- lid: images_205 #表示输入节点名称。
category: image
dtype: float32
sparse: false
tensor_name:
layout: nchw #输入数据的排列格式,n表示batch,c表示channel,h表示高,w表示宽
shape: #模型输入的形状
- 1 #输入数据的batch,如果后面量化的batch参数不为1,需要改这里。
- 3
- 640
- 640
fitting: scale
preprocess:
reverse_channel: true
mean:
- 0
- 0
- 0
scale: #3通道的缩放值,yolov5s需要改为0.00392157
- 1.0
- 1.0
- 1.0
preproc_node_params:
add_preproc_node: false #是否添加预处理节点,用于格式转化和裁剪,这里要改为true
preproc_type: IMAGE_RGB #预处理输入的格式
preproc_image_size:
- 640
- 640
preproc_crop:
enable_preproc_crop: false
crop_rect:
- 0
- 0
- 640
- 640
preproc_perm:
- 0
- 1
- 2
- 3
redirect_to_output: false
对于模型的输入yml,需要将scale修改为0.00392157,同时默认使用cpu预处理图像,所以add_preproc_node设置为true。
量化
pegasus quantize --model yolov5s-mask-rt.json --model-data yolov5s-mask-rt.data --device CPU --iterations=12 --with-input-meta yolov5s-mask-rt_inputmeta.yml --rebuild --model-quantize yolov5s-mask-rt.quantize --quantizer asymmetric_affine --qtype uint8
下面是量化模型的参数解析:
- model: 模型的网络结构文件
- model-data:模型需要的权重文件
- with-input-meta:模型需要前处理配置文件
- model-quantize: 输出的模型文件
- iterations: 模型量化使用的数据量,设置1(默认)使用dataset第一条数据。若设置20,会先遍历dataset.txt中的20行数据。
- qtype:量化数据类型,有int8,uint8,int16等。
- batch_size: 量化多少轮,如果不为1,需要改输入的yml文件shape,先用默认。
量化后,会生成量化文件yolov5s-mask-rt.quantize。
推理
pegasus inference --model yolov5s-mask-rt.json --model-data yolov5s-mask-rt.data --dtype quantized --model-quantize yolov5s-mask-rt.quantize --device CPU --with-input-meta yolov5s-mask-rt_inputmeta.yml --postprocess-file yolov5s-mask-rt_postprocess_file.yml
模型推理是为了验证量化后的模型效果,这步可省略。
导出模型
pegasus export ovxlib --model yolov5s-mask-rt.json --model-data yolov5s-mask-rt.data --dtype quantized --model-quantize yolov5s-mask-rt.quantize --save-fused-graph --target-ide-project 'linux64' --with-input-meta yolov5s-mask-rt_inputmeta.yml --output-path ovxilb/yolov5s-mask-rt/yolov5s-simprj --pack-nbg-unify --postprocess-file yolov5s-mask-rt_postprocess_file.yml --optimize "VIP9000PICO_PID0XEE" --viv-sdk ${VIV_SDK}
模型导出,最终会生成ovxilb/yolov5s-mask-rt_nbg_unify/network_binary.nb
端侧部署
修改端侧后处理的分类名和数量配置文件。
改完之后,执行./build_linux.sh -t \
./yolov5 -b network_binary.nb -i mask-test.jpeg
model_file=network_binary.nb, input=mask-test.jpeg, loop_count=1, malloc_mbyte=10
input 0 dim 3 640 640 1, data_format=2, quant_format=0, name=input[0], none-quant
output 0 dim 80 80 8 3, data_format=0, name=uid_20000_sub_uid_1_out_0, none-quant
output 1 dim 40 40 8 3, data_format=0, name=uid_20001_sub_uid_1_out_0, none-quant
output 2 dim 20 20 8 3, data_format=0, name=uid_20002_sub_uid_1_out_0, none-quant
nbg name=network_binary.nb, size: 7196096.
create network 0: 35626 us.
prepare network: 38972 us.
buffer ptr: 0xb6996000, buffer size: 1228800
feed input cost: 94526 us.
network: 0, loop count: 1
run time for this network 0: 119081 us.
detection num: 1
1: 94
draw objects time : 154 ms
destory npu finished.
~NpuUint.
参考: