Files
AI-tianyan/docs/CONVERSION_GUIDE.md
master ee9be85292 fix: ACL bytes_to_ptr GC bug + 添加 NPU 模型转换指南
python/infer_server.py:
- 修复 acl.util.bytes_to_ptr() 后 bytes 被 GC 回收导致全零输出的 bug
- 保持 bytes 引用直到 memcpy 完成
- 正确解析 FP16 模型输出 (half precision -> float32)

docs/CONVERSION_GUIDE.md:
- 完整的 YOLOv8 ONNX->OM 转换流程文档
- ATC 转换参数详解及低内存设备配置
- 已知问题排查表 (OOM/全零输出/算子不支持)
- 其他 YOLOv8 尺寸模型参考

start.sh: 一键启动脚本
2026-05-06 23:30:49 +08:00

4.6 KiB
Raw Blame History

昇腾 NPU 模型转换指南

硬件: Atlas 200I DK2 / 昇腾 310B4 | CANN 6.2.RC2 | YOLOv8n


方案概要

YOLOv8n.pt → YOLOv8n.onnx → yolov8n.om (ACL原生推理)
步骤 工具 耗时 资源需求
1. 下载权重 ultralytics ~1min
2. 导出 ONNX ultralytics ~85s 需安装 onnx/onnxslim
3. ATC 转换 OM CANN atc ~16min 3GB RAM + swap, 单核编译

环境要求

Ubuntu 22.04 aarch64
Python 3.9+ (miniconda)
CANN 6.2.RC2 (已安装于 /usr/local/Ascend/ascend-toolkit/latest)
Go 1.22+ (编译 edge-agent)

详细步骤

第 1 步:安装依赖

# Python 依赖
pip3 install "numpy>=1.24.0,<2.0.0"
pip3 install ultralytics opencv-python-headless

# Go (系统源版本太低, 需手动安装)
wget https://go.dev/dl/go1.22.5.linux-arm64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.5.linux-arm64.tar.gz
rm go1.22.5.linux-arm64.tar.gz
export PATH=/usr/local/go/bin:$PATH

# 验证
python3 -c "import ultralytics; print('OK')"
go version  # 应输出 go1.22.5

第 2 步:导出 ONNX

cd /path/to/AI-tianyan

python3 -c "
from ultralytics import YOLO
model = YOLO('yolov8n.pt')  # 或自定义模型路径
model.export(format='onnx', imgsz=640, dynamic=False, opset=11, simplify=True)
"

输出:yolov8n.onnx (约 13MB)

注意事项:

  • dynamic=False静态输入尺寸ATC 转换必须
  • opset=11CANN 6.2 最稳定的 ONNX opset 版本
  • simplify=True:使用 onnxslim 简化模型图

第 3 步ATC 转换 OM关键步骤

# 设置环境变量3GB RAM 设备必须)
export TBE_IMPL_MODE=AI_CORE      # 使用 AI Core 模式
export TE_PARALLEL_COMPILER=1     # 单线程编译,避免内存溢出

# 执行转换
atc \
  --model=yolov8n.onnx \
  --framework=5 \                 # 5 = ONNX
  --output=yolov8n \
  --soc_version=Ascend310B4 \     # 昇腾 310B4
  --input_format=NCHW \
  --input_shape="images:1,3,640,640" \
  --output_type=FP16              # FP16 更快,精度够用

# 约 16 分钟后得到 yolov8n.om (约 7.1MB)

常见失败原因:

错误 原因 解决
EOFError / 进程崩溃 TBE 多线程编译 OOM 设置 TE_PARALLEL_COMPILER=1
输出全零 bytes_to_ptr() 后 bytes 被 GC 保持 bytes 引用见 infer_server.py
算子不支持 ONNX opset 版本过高 改用 opset=11

第 4 步:部署模型

# 复制模型到指定位置
cp yolov8n.om /opt/tianyan-edge/model/model.om

# 更新类别文件COCO 80 类)
cp model/names.txt /opt/tianyan-edge/model/names.txt

# 启动服务
cd /opt/tianyan-edge
python3 python/infer_server.py        # 推理服务
./bin/edge-agent -config config/edge.yaml  # 主控 Agent

其他模型

模型 导出命令 输出尺寸
yolov8s YOLO('yolov8s.pt').export(...) 22.5MB onnx → 11MB om
yolov8m YOLO('yolov8m.pt').export(...) 51.9MB onnx → 25MB om
yolov8l YOLO('yolov8l.pt').export(...) 88.3MB onnx → 43MB om
yolov8n YOLO('yolov8n.pt').export(...) 12.3MB onnx → 7.1MB om

注意: 大模型转换需要更多内存,建议 8GB+ RAM。


YOLOv10 注意事项

如果用 YOLOv10需要

  1. pip install ultralytics yolov10
  2. 导出:YOLOv10('yolov10n.pt').export(format='onnx', ...)
  3. 修改 OUTPUT_FORMAT=nms_free (YOLOv10 输出格式不同)
  4. ATC 命令完全相同

已知 Bug 修复

ACL bytes_to_ptr 提前 GC 问题

问题描述: acl.util.bytes_to_ptr(blob.tobytes()) 返回的指针, 由于 blob.tobytes() 创建的临时 bytes 对象被 Python GC 回收, 导致后续 acl.rt.memcpy 读到全零数据。

修复方案(见 python/infer_server.py

# 错误写法 - bytes 临时对象会被 GC
host_addr = acl.util.bytes_to_ptr(blob.tobytes())
acl.rt.memcpy(in_buf, in_sz, host_addr, in_sz, ...)  # 读到空数据

# 正确写法 - 保持引用
host_bytes = blob.tobytes()           # 保持引用
host_addr = acl.util.bytes_to_ptr(host_bytes)
acl.rt.memcpy(in_buf, in_sz, host_addr, in_sz, ...)  # 数据正确

FP16 输出解析

ATC 转换时指定 --output_type=FP16 后,模型输出为 half precision。 需要按半精度读取并转为 float32

host_bytes = host.tobytes()
acl.rt.memcpy(acl.util.bytes_to_ptr(host_bytes), sz, out_buf, sz, ...)
host_from_bytes = np.frombuffer(host_bytes, dtype=np.uint8)
out_fp16 = host_from_bytes.view(np.float16)
output = out_fp16.astype(np.float32).reshape(shape)