在 CPU 上用 C++ 调用 ONNX 模型进行推理,并希望对模型进行 INT8 量化以提升性能。


✅ 简短回答:

ONNX 本身不包含 INT8 量化能力,但你可以通过 ONNX Runtime(ONNX Runtime with quantization tools)对 ONNX 模型进行后训练量化(PTQ),生成 INT8 的 ONNX 模型,然后在 C++ 中用 ONNX Runtime CPU 执行它。

也就是说:可以做 INT8 量化,但不是在 yolo export 阶段完成,而是在导出 ONNX 后,用 ONNX Runtime 的量化工具进行。


🔧 具体步骤如下:

第一步:导出标准 ONNX 模型(你已经完成)
yolo export model=best31n.pt format=onnx imgsz=320 simplify=True opset=12 nms=False

⚠️ 注意:不要开启 nms=True,因为 ONNX Runtime 的量化工具不支持带自定义 NMS 算子的模型(NMS 通常是非标准 ONNX 算子)。建议在后处理阶段用 C++ 实现 NMS。

第二步:准备校准数据集

你需要一个代表实际输入分布的小数据集(比如 100~500 张图像),用于 INT8 校准。这些图像应:

  • 尺寸为 320x320
  • 归一化方式与训练一致(通常为 img / 255.0
  • 保存为 .npy 或通过脚本加载为 numpy 数组
第三步:使用 ONNX Runtime 的量化工具进行 INT8 量化

安装 ONNX Runtime(含量化工具):

pip install onnxruntime onnx onnxruntime-extensions

创建量化脚本 quantize_onnx.py

import onnx
from onnxruntime.quantization import quantize_static, QuantType, CalibrationDataReader

class YoloCalibrationDataReader(CalibrationDataReader):
    def __init__(self, data_loader):
        self.data_loader = iter(data_loader)
        self.enum_data = None

    def get_next(self):
        if self.enum_data is None:
            self.enum_data = next(self.data_loader, None)
        if self.enum_data is not None:
            data = self.enum_data
            self.enum_data = None
            # 假设 data 是 (1, 3, 320, 320) numpy array
            return {"images": data}  # 注意:输入节点名需匹配你的 ONNX 模型
        return None

# 示例:加载你的校准数据(这里简化为随机数据)
import numpy as np
calibration_data = [np.random.rand(1, 3, 320, 320).astype(np.float32) for _ in range(100)]

data_reader = YoloCalibrationDataReader(calibration_data)

quantize_static(
    model_input="best31n.onnx",
    model_output="best31n_int8.onnx",
    calibration_data_reader=data_reader,
    quant_format=QuantFormat.QDQ,  # 或 QuantFormat.QOperator(更紧凑但兼容性略差)
    activation_type=QuantType.QUInt8,
    weight_type=QuantType.QUInt8,
    op_types_to_quantize=['Conv', 'MatMul'],  # 可选
    per_channel=False,
    reduce_range=False
)
print("INT8 quantization finished.")

🔍 关键点

  • 你需要知道 ONNX 模型的输入节点名(用 Netron 打开 .onnx 文件查看,通常是 "images""input")。
  • quantize_static 使用 静态校准(PTQ),适合 CPU 推理。
  • 输出的 best31n_int8.onnx 是标准 ONNX 模型,包含 QuantizeLinear / DequantizeLinear 节点。
第四步:C++ 中使用 ONNX Runtime 推理 INT8 模型

ONNX Runtime 的 C++ API 完全支持量化模型(CPU 执行):

示例伪代码:

Ort::Env env;
Ort::Session session(env, L"best31n_int8.onnx", session_options);
// 输入数据:float32(0~1),ONNX Runtime 自动处理量化
auto output = session.Run(...);

✅ ONNX Runtime 会在 CPU 上自动将 FP32 输入转为 INT8(通过 QuantizeLinear),执行量化算子,再转回 FP32 输出(或保留 INT8,取决于模型结构)。


⚠️ 注意事项

  1. 不要在 yolo export 时加 int8=True → 对 ONNX 无效。
  2. 避免 nms=True → 自定义 NMS 会破坏量化兼容性。
  3. 校准数据质量影响精度 → 使用真实场景图像。
  4. INT8 量化可能轻微掉点 → 需验证 mAP 是否可接受。
  5. 性能提升依赖 CPU 指令集 → 支持 AVX2/AVX-512 的 CPU 效果更好。

✅ 总结

步骤 操作
1 yolo export format=onnx 导出标准模型(无 NMS)
2 准备校准数据(320x320 图像,numpy 格式)
3 onnxruntime.quantization.quantize_static 生成 INT8 ONNX
4 C++ 用 ONNX Runtime 加载 int8.onnx 模型推理

这样你就能在 CPU + C++ + ONNX 环境下实现 INT8 量化加速

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐