maixcam离线训练YOLO模型的格式转换问题(py/onnx转cvimodel)
前言:
使用maixcam部署YOLO模型需要使用其专属的mud文件和cvimodel文件。
最简单的方案是使用maixcam官方的在线训练平台maixhub( https://maixhub.com )训练模型,但是由于maixhub平台只能训练最基础的图像检测模型,并且限制3000张照片,以及仅限于训练yolov5模型的限制,在一些复杂情况需要增加照片数量或者更改模型(如yolov8,yolo11)时,就需要模型转换,格式转换的步骤比较繁琐且坑点较多,官方文档写的也有些不太好操作,这边我以我自己离线训练的YOLOv8关键点检测模型经验为例,讲讲格式转换流程
参考文档
https://wiki.sipeed.com/maixpy/doc/zh/vision/customize_model_yolov8.html
https://blog.csdn.net/iiuvv/article/details/145952611?spm=1001.2014.3001.5502
导出ONNX文件
在自己电脑上训练好的初始文件一般是pt格式,我们需要转换成onnx格式
在你训练模型的文件夹下新建一个转换的代码文件,列如export_onnx.py
from ultralytics import YOLO
import sys
print(sys.path)
net_name = sys.argv[1] # yolov8n.pt yolov8n-pose.pt # https://docs.ultralytics.com/models/yolov8/#supported-tasks-and-modes
input_width = int(sys.argv[2])
input_height = int(sys.argv[3])
# Load a model
model = YOLO(net_name) # load an official model
# model = YOLO("path/to/best.pt") # load a custom model
# Predict with the model
results = model("https://ultralytics.com/images/bus.jpg") # predict on an image
path = model.export(format="onnx", imgsz=[input_height, input_width], dynamic=False, simplify=True, opset=17) # export the model to ONNX format
print(path)
然后执行python export_onnx.py yolov8n.pt 320 320 就能导出 onnx 模型了,这里重新指定了输入分辨率,模型训练的时候用的640x640,我们重新指定了分辨率方便提升运行速度,尽量使用长宽相等的分辨率,不然后面容易出现一些问题
这样就得到了.onnx文件
模型转换为cvimodel
1.下载docker
到docker官网( https://www.docker.com/ )下载
2.拉取镜像
命令行输入
docker pull sophgo/tpuc_dev:latest
如果镜像拉取失败,可以使用网络代理,或者使用国内源
3.运行容器
提前在本机新建一个文件夹用来了存放所需数据,我这里直接放在了D盘

docker run --privileged --name tpu-env -v /d/maix_data:/home/$USER/data -it sophgo/tpuc_dev
这就起了一个容器,名叫tpu-env,并且把本机的/d/maix_data目录挂载到了容器的~/data,这样就实现了文件共享

4. 安装 tpu-mlir
先到github下载 whl 文件,放到/d/maix_data目录下。
在容器中执行命令安装
pip install tpu_mlir-1.15-py3-none-any.whl # 这里就是下载文件的名字
注意这里的名字要与你本地文件夹里的whl文件名一一对应!!!
否则会出现类似ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: '/home/data/tpumlir-1.25-py3-none-any.whl'的报错
在容器内直接输入model_transform.py回车执行会有打印帮助信息就算是安装成功了
5.编写转换脚本
转换模型主要就两个命令,model_transform.py 和 model_deploy.py,主要麻烦的是参数,所以我们写一个脚本convert_yolov5_to_cvimodel.sh存下来方便修改。
#!/bin/bash
set -e
net_name=yolov5s
input_w=640
input_h=640
# mean: 0, 0, 0
# std: 255, 255, 255
# mean
# 1/std
# mean: 0, 0, 0
# scale: 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
mkdir -p workspace
cd workspace
# convert to mlir
model_transform.py \
--model_name ${net_name} \
--model_def ../${net_name}.onnx \
--input_shapes [[1,3,${input_h},${input_w}]] \
--mean "0,0,0" \
--scale "0.00392156862745098,0.00392156862745098,0.00392156862745098" \
--keep_aspect_ratio \
--pixel_format rgb \
--channel_format nchw \
--output_names "/model.24/m.0/Conv_output_0,/model.24/m.1/Conv_output_0,/model.24/m.2/Conv_output_0" \
--test_input ../test.jpg \
--test_result ${net_name}_top_outputs.npz \
--tolerance 0.99,0.99 \
--mlir ${net_name}.mlir
# export bf16 model
# not use --quant_input, use float32 for easy coding
model_deploy.py \
--mlir ${net_name}.mlir \
--quantize BF16 \
--processor cv181x \
--test_input ${net_name}_in_f32.npz \
--test_reference ${net_name}_top_outputs.npz \
--model ${net_name}_bf16.cvimodel
echo "calibrate for int8 model"
# export int8 model
run_calibration.py ${net_name}.mlir \
--dataset ../images \
--input_num 200 \
-o ${net_name}_cali_table
echo "convert to int8 model"
# export int8 model
# add --quant_input, use int8 for faster processing in maix.nn.NN.forward_image
model_deploy.py \
--mlir ${net_name}.mlir \
--quantize INT8 \
--quant_input \
--calibration_table ${net_name}_cali_table \
--processor cv181x \
--test_input ${net_name}_in_f32.npz \
--test_reference ${net_name}_top_outputs.npz \
--tolerance 0.9,0.6 \
--model ${net_name}_int8.cvimodel
可以看到,这里有几个比较重要的参数:
-
net_name 就是onnx模型名,需要与你的.onnx文件保持一致
-
input_w,input_h onnx的尺寸数据,注意与之前导出onnx时保持一致,否则会转换失败!!!
-
output_names就是模型输出节点的输出名。需要查询官方文档,比如我用的是YOLOv8的关键点检测,在maixcam上运行,就按照如图选择
![image.png]()
注意多个节点之间用英文逗号,连接!!! -
mean, scale就是训练时使用的预处理方法,比如YOLOv5官方代码的预处理是把图像 RGB 3个通道分别-mean再除以std,并且默认mean
为0,std为255,即将图像的值归一,这里scale就是1/std。你的模型需要根据实际的预处理方法修改。一般不用修改。 -
test_input就是转换时用来测试的图像,这里是../test.jpg,所以实际模型转换时我们需要在此脚本所在同目录放一张test.jpg的图,你的模型根据你的实际情况替换图像。 -
tolerance就是量化前后允许的误差,如果转换模型时报错提示值小于设置的这个值,说明转出来的模型可能相比 onnx 模型误差较大,如果你能够容忍,可以适当调小这个阈值让模型转换通过,不过大多数时候都是因为模型结构导致的,需要优化模型,以及仔细看后处理,把能去除的后处理去除了。 -
quantize即量化的数据类型,在 MaixCAM 上我们一般用 INT8 模型,这里我们虽然也顺便转换了一个 BF16 模型,BF16 模型的好处时精度高,不过运行速率比较慢,能转成 INT8 就推荐先用 INT8,实在不能转换的或者精度要求高速度要求不高的再考虑 BF16。 -
dataset表示用来量化的数据集,也是放在转换脚本同目录下,比如这里是images文件夹,里面放数据即可,对于 YOLOv5 来说就是图片,从 coco 数据集中复制一部分典型场景的图片过来即可。 用--input_num可以指定实际使用图片的数量(小于等于 images 目录下实际的图片)。在本地自己建的maix_data文件夹目录中新建一个文件夹存放200张训练时用的照片。
6.确定文件是否齐全

images是存放图片的数据集
convert_yolov8_to_cvimodel.sh是转换脚本
rect.onnx是待转换的模型文件
test.jpg是测试图片
tpu_mlir-1.25-py3-none-any.whl是前面安装的库文件
7.执行转换脚本,得到cvimodel
在docker中执行写好的转换脚本
chmod +x convert_yolov8_to_cvimodel.sh && ./convert_yolov8_to_cvimodel.sh
执行结束,在生成的文件夹中找到所需的cvimodel


编写mud文件
MUD(模型统一描述文件, model universal description file)是 MaixPy 支持的一种模型描述文件,用来统一不同平台的模型文件,方便 MaixPy 代码跨平台,本身是一个 ini格式的文本文件,可以使用文本编辑器编辑。
一般 MUD 文件会伴随一个或者多个实际的模型文件,比如对于 MaixCAM, 实际的模型文件是.cvimodel格式, MUD 文件则是对它做了一些描述说明
根据你的模型情况修改mud文件
[basic]
type = cvimodel
model = yolov5s.cvimodel
[extra]
model_type = yolov5
#type = pose #对于其他类型的模型,比如关键点检测,语义分割什么的,要记得加这一句type = xxx
input_type = rgb
mean = 0, 0, 0
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
labels = 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
model 改成自己的模型名
model_type 改成自己的YOLO版本
对于其他特殊类型的模型,比如关键点检测,语义分割等,记得加上type !!! (我一开始就是因为没有加这个type导致关键点一直出不来,可恶)
上面这个是YOLOv5的一个示例模版,要根据自己的模型情况进行参数更改,列如我的是YOLOv8的关键点检测,这是我的mud文件
[basic]
type = cvimodel
model = rect_int8.cvimodel
[extra]
model_type = yolov8
type = pose
input_type = rgb
mean = 0, 0, 0
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
labels = rect
有了mud文件和cvimodel文件,就可以在maixcam里部署模型并调用了

浙公网安备 33010602011771号