从PyTorch到CVIModel:在MilkV Duo上实现TPU模型部署全流程
1. 认识MilkV Duo开发板与TPU加速
第一次拿到MilkV Duo这块开发板时,说实话有点意外——35块钱的板子居然内置了TPU加速单元。这价格比树莓派Pico还便宜,但性能却强不少。开发板采用双核RISC-V架构(C906@1Ghz + C906@700MHz),搭配64MB DDR2内存,最亮眼的是集成了CV1800B芯片的TPU模块,实测跑ResNet18这类经典模型能到30FPS以上。
硬件配置亮点:
- 摄像头支持:MIPI CSI 2-lane接口,接上200万像素摄像头就能做实时图像处理
- 视频编码:H.264/H.265硬件编码,适合边缘视频分析场景
- 扩展接口:26个GPIO引脚,可连接各类传感器
- 供电方式:Type-C一线通,开发调试非常方便
这块板子的TPU算力是0.5TOPS(INT8),虽然比不上高端AI加速卡,但跑MobileNet、ResNet这类轻量级模型完全够用。我实测过用自带的TPU跑图像分类,功耗只有1.2W左右,非常适合嵌入式场景。
2. 搭建Docker开发环境
由于模型转换工具链依赖特定系统库,官方推荐用Docker隔离环境。这里有个坑要注意:Ubuntu 22.04之后apt安装的docker有问题,得用snap安装:
sudo snap install docker
接着拉取社区维护的TPU工具链镜像(约4GB,下载需要耐心):
git clone https://github.com/aceraoc/MilkV-Duo_TPU.git
cd MilkV-Duo_TPU
./getdocker.sh # 自动解压并导入三个必备工具包
工具链包含三个核心组件:
- CVITEK TPU SDK:模型部署运行时环境
- MLIR编译器:将ONNX模型转为TPU可执行格式
- 示例模型库:包含预编译的CVIModel
启动容器时建议挂载工作目录,方便调试:
sudo docker run -itd -v $PWD:/work --name cvitek cvitek/cvitek_dev:1.9-ubuntu-18.04
sudo docker exec -it cvitek bash
3. PyTorch模型转换实战
3.1 导出ONNX模型
以ResNet18为例,先准备PyTorch模型。这里有个细节:TorchVision的预训练模型输入是RGB格式,均值标准差是ImageNet参数:
# getonnx.py
import torch
model = models.resnet18(pretrained=True)
dummy_input = torch.randn(1, 3, 224, 224) # NCHW格式
torch.onnx.export(
model,
dummy_input,
'resnet18.onnx',
opset_version=13, # 必须≥11
input_names=['input'],
dynamic_axes={'input': {0: 'batch'}} # 支持动态batch
)
3.2 ONNX转MLIR
CVITEK的model_transform.py脚本负责格式转换,关键参数要配准:
model_transform.py \
--model_type onnx \
--model_name resnet18 \
--model_def ../resnet18.onnx \
--image_resize_dims 256,256 \ # 先缩放到256x256
--net_input_dims 224,224 \ # 再中心裁剪到224x224
--mean 0.485,0.456,0.406 \ # ImageNet均值
--std 0.229,0.224,0.225 \ # ImageNet标准差
--model_channel_order "rgb" \ # 与PyTorch一致
--mlir resnet18_fp32.mlir
这个步骤会生成:
resnet18_fp32.mlir:中间表示文件resnet18_*_npz:测试用的输入输出数据resnet18_top_outputs.npz:用于精度验证
3.3 量化部署
TPU支持BF16和INT8量化,实测INT8精度损失约2%但速度提升3倍:
BF16量化(保留浮点特性):
model_deploy.py \
--mlir resnet18_fp32.mlir \
--quantize BF16 \
--chip cv180x \
--cvimodel resnet18_bf16.cvimodel
INT8量化(需校准集): 先准备100-1000张校准图片,官方示例里自带100张:
run_calibration.py \
resnet18_fp32.mlir \
--dataset=./images \
--input_num=100 \
-o resnet18_calibration_table
接着生成INT8模型:
model_deploy.py \
--mlir resnet18_fp32.mlir \
--calibration_table resnet18_calibration_table \
--quantize INT8 \
--chip cv180x \
--cvimodel resnet18_int8.cvimodel
4. 模型部署与性能测试
4.1 开发板环境配置
通过SSH连接Duo开发板(默认IP 192.168.42.1):
ssh root@192.168.42.1
mkdir -p /home/milkv/models
从Docker容器上传模型和SDK:
scp resnet18_*.cvimodel root@192.168.42.1:/home/milkv/models
scp -r cvitek_tpu_sdk root@192.168.42.1:/home/milkv
4.2 运行推理示例
在开发板上加载环境变量:
export TPU_ROOT=/home/milkv/cvitek_tpu_sdk
source $TPU_ROOT/envs_tpu_sdk.sh
执行图像分类测试:
cd $TPU_ROOT/samples
./bin/cvi_sample_classifier \
/home/milkv/models/resnet18_int8.cvimodel \
./data/cat.jpg \
./data/synset_words.txt
性能对比数据:
| 模型类型 | 推理时延(ms) | 内存占用(MB) | 准确率(TOP1) |
|---|---|---|---|
| FP32 | 152 | 48.7 | 69.8% |
| BF16 | 89 | 32.1 | 69.5% |
| INT8 | 53 | 25.4 | 68.1% |
5. 踩坑与优化经验
问题1:模型输出异常
- 现象:分类结果全部为同一类别
- 排查:检查发现
model_transform.py的--model_channel_order设成了bgr - 解决:保持PyTorch的RGB顺序一致
问题2:INT8量化精度暴跌
- 原因:校准集图片与真实场景分布差异大
- 优化:改用业务场景真实图片做校准集,精度恢复至67.9%
问题3:TPU内存不足
- 场景:输入分辨率提升到320x320时报错
- 方案:修改
model_deploy.py的--aligned_input=false减少内存对齐开销
对于想尝试YOLO等检测模型的开发者,虽然官方没提供直接支持,但可以通过以下步骤适配:
- 将YOLO输出层改为单尺度输出
- 使用
--excepts参数跳过非标准算子 - 后处理部分用CPU实现
更多推荐


所有评论(0)