JiaXin‘s Blog

Back

记录MaixCAM2将YOLO11模型转换

前言#

前几天买了一个maixcan2,作为今年电赛的使用,本文记录使用maixcam2跑yolo的过程,仅供参考,以官方教程为主。

有开源在maixhub上:具体可以看


一、烧录镜像#

这个下面是官方的要求,可见yolo模型和镜像的版本相关,具体烧录可以看这里MaixCAM MaixPy 升级和烧录系统,我这次烧录的是4.12.5。

MaixPy 默认提供了 YOLOv5 , YOLOv8 , YOLO11 , YOLO26 模型,可以直接使用:
YOLOv8 需要 MaixPy >= 4.3.0。
YOLO11 需要 MaixPy >= 4.7.0。
YOLO26 需要 MaixPy >= 4.12.5。
plaintext

步骤1:ONNX 导出#

电脑上训练的模型后的模型是best.pt不能直接给 MaixCAM2 使用,硬件性能有限,需要将模型进行INT8量化以减少计算量,并且转换为 MaixCAM2 支持的模型格式MUD。

MUD是 MaixPy 支持的一种模型描述文件,用来统一不同平台的模型文件,方便 MaixPy 代码跨平台,本身是一个 ini格式的文本文件,可以使用文本编辑器编辑。

方法一:完整 ONNX 导出#

这个代码是简单的转换,读者可以自行修改参数。笔者开始用的是这个方法,后来发现需要裁剪节点,读者可以看下面的方法二。我用的是方法1,后面在转换脚本那里裁剪。

from ultralytics import YOLO

model = YOLO('runs/detect/train9/weights/best.pt')

model.export(
    format='onnx',
    imgsz=640,        # 和训练时一致
    opset=12,         # OpenCV 兼容性最好的 opset 版本
    simplify=True     # 简化模型,推理更快
)
python

方法二:ONNX 裁剪节点#

这里是从官方贴过来的,自行跳转,核心就是用 extract_onnx.py 提取节点:

import onnx
import sys

input_path = sys.argv[1]
output_path = sys.argv[2]
input_names_str = sys.argv[3]
output_names_str = sys.argv[4]
input_names = []
for s in input_names_str.split(","):
    input_names.append(s.strip())
output_names = []
for s in output_names_str.split(","):
    output_names.append(s.strip())
onnx.utils.extract_model(input_path, output_path, input_names, output_names)
python

用法:python extract_onnx.py $model_path $onnx_extracted $input_names $output_names

或者直接一行命令:

python -c "import onnx,sys; onnx.utils.extract_model(sys.argv[1], sys.argv[2], [s.strip() for s in sys.argv[3].split(',')], [s.strip() for s in sys.argv[4].split(',')])" yolo11n.onnx export.onnx "images" "/model.23/Concat_output_0,/model.23/Concat_1_output_0,/model.23/Concat_2_output_0"
bash

其中 yolo11n.onnxexport.onnx"images""/model.23/Concat_output_0,..." 依次替换成你自己的 $model_path$onnx_extracted$input_names$output_names

此时得到的 export.onnx 就是裁剪后的新 ONNX 文件,可以继续下一步了。


步骤2:把用到的文件cp到 ubuntu20#

校准图片还需要 ≥200 张训练样本(.jpg/.png),记得cp过去,我传是测试集val。

另外就是转好的best.onnx镜像也cp过去,一共两个

步骤3:安装模型转换环境#

这里我选用的是ubuntu20上根据官方教程使用pulsar2 Docker 镜像,用的是虚拟机,读者自行判断选择。

下载 pulsar2 Docker 镜像#

下载地址modelscope

滑到下面选择最新的版本,我选这个的是6.0.我虚拟机没啥内存选择安装ax_pulsar2_6.0_lite.tar.gz有1G多,后面补了几个包才能转,读者有内存推荐安装ax_pulsar2_6.0.tar.gz更好。

我缺的包一条命令补上:

pip install onnx onnxsim -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
bash

Docker 环境搭建#

# 首次加载镜像
sudo docker load -i /home/uu20/下载/ax_pulsar2_6.0_lite.tar.gz
sudo docker images | grep pulsar2

# 启动容器(取名,去掉 --rm 保留环境)
cd /home/uu20/桌面/yolo/yolo11
sudo docker run -it --net host --name yolo_build -v ./:/data pulsar2:6.0-lite
bash

⚠️ 注意: 我用完不小心就把容器删除了。第一次没加 --name,也没去掉 --rm。退出容器后环境全丢——装的 onnxsim 没了,中间产物也没了。

解决: 去掉 --rm,加 --name yolo_build 命名。下次用 docker start -ai yolo_build 回来,环境完好:

sudo docker start -ai yolo_build
cd /data && bash build_yolo11.sh best
bash

步骤4:ONNX → axmodel 转换#

进入容器后:

cd /data

# 首次安装依赖(仅一次)
pip install onnx onnxsim -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

# 一键转换(约 15-20 分钟)
bash build_yolo11.sh best
bash

build_yolo11.sh best 做了五件事:

步骤说明产物耗时
Step 0restructure_onnx.py 重构:6 Conv → 3 per-scale 4D Concattmp1/best_restructured.onnx< 1 min
Step 1extract_onnx.py 提取输出节点tmp1/best_extracted.onnx< 1 min
Step 2onnxsim 简化tmp1/best.onnx< 1 min
Step 3打包校准图片tmp_images/images.tar< 1 min
Step 4pulsar2 build NPU1 (vnpu)out/best_vnpu.axmodel~8 min
Step 5pulsar2 build NPU2 (npu)out/best_npu.axmodel~8 min

转换成功标志:

========================================
转换完成! 输出文件在 out/ 目录:
  out/best_npu.axmodel
  out/best_vnpu.axmodel
========================================
plaintext

6 个输出余弦相似度均 > 0.999 表示 INT8 量化精度接近无损。

脚本代码 build_yolo11.sh

⚠️ 注意: MaixPy YOLO11 解码器需要 3 个 4D Concat 输出(每个尺度合并 bbox+cls),但 ultralytics 导出的 Concat 是跨尺度全局合并的 3D 输出。

解决: restructure_onnx.py 在编译前将 6 个 Conv 输出按尺度合并为 3 个 4D Concat(per_scale_concat_0/1/2,axis=1,输出 [N, 96, H, W]),再送入 pulsar2。


步骤5:mud 配置文件#

一共需要三个文件yolo11n.mud, yolo11n_npu.axmodel和yolo11n_vnpu.axmodel

可以看到, 指定了模型类别为axmodel, 模型路径为相对mud文件的路径下的*.axmodel文件;

字段说明:

字段说明
type = axmodelMaixCAM2 模型格式
model_type = yolo11MaixPy YOLO11 解码器
model_npu全 NPU 算力模型
model_vnpuAI-ISP 模式下半算力模型
labels32 个类名,逗号分隔,顺序必须和训练一致
mean / scale预处理参数(1/255 ≈ 0.00392,已在模型中集成)

步骤6:部署到 MaixCAM2#

scp out/best_npu.axmodel root@maixcam2:/root/
scp out/best_vnpu.axmodel root@maixcam2:/root/
scp best.mud root@maixcam2:/root/
bash

或用 ADB / U 盘。


步骤7:MaixPy 运行#

main.py

就可以成功运行了


快速命令速查#


写在最后#

虽然跑通了一个教程,但是要明白跑通过程中每一步都知道为什么

接下来的可以做:

  • 替换 MaixCAM2 内置模型——用自己的 32 类模型跑实时检测,对比内置模型的精度和速度
  • 量化感知训练(QAT)——pulsar2 的 INT8 量化余弦相似度 > 0.999 已经很好,但如果某些类别精度掉得厉害,QAT 是下一道防线
  • 模型剪枝 + 知识蒸馏——YOLO11 在 640×480 上跑 NPU 够用,但如果要上更高分辨率或更低延迟,需要更小的 backbone

完成#

参考#

记录MaixCAM2将YOLO11模型转换
https://jiaxin404.top/tech/maix_yolo/
Author 嘉心糖
Published at 2026年7月15日
Comment seems to stuck. Try to refresh?✨