☰
ONNX_day3
2026/9/29 3:30:54 网站建设 项目流程

可以。我们继续你前面的学习路线:

Step 1:PyTorch → ONNX → ONNX Runtime
Step 2:ONNX → ONNX Runtime → Linux/x86
Step 3:ONNX → INT8 Quantization

而且你的目标不是单纯"把模型变小",而是理解:

FP32 ONNX → Calibration → INT8 ONNX → INT8 inference → 后续 Linux/x86 / MCU

ONNX Runtime 官方目前支持Dynamic Quantization和Static Quantization;对于我们这种后面希望理解 TinyML/Embedded INT8 的场景,我建议这一步直接学习Static INT8 Quantization。静态量化会用 calibration dataset 预先计算 activation 的 scale/zero-point。

1. 先明确我们这一阶段的目标

最终目录类似:

onnx_int8/
├── model.onnx
├── model_preprocessed.onnx
├── model_int8.onnx
├── calibrate.py
└── test_int8.py

整个流程:

这里最重要的是:

INT8 量化不是简单地把 FP32 数字转换成 int8。

而是建立一个映射:

ONNX Runtime 官方也是采用这种 scale/zero-point 的线性量化方式。

2. 为什么这一步对你后面的 STM32 很重要?

你之前已经做过:

Keras ↓ TFLite ↓ Full Integer INT8 ↓ TFLite Micro ↓ STM32F303RE

现在我们换一条工业界非常重要的路线:

PyTorch ↓ ONNX ↓ ONNX Runtime ↓ INT8 ↓ Linux/x86

于是你可以直接比较:

技术模型Runtime
TFLite.tfliteTFLite
TFLite Micro.tfliteTFLM
ONNX.onnxONNX Runtime
ONNX INT8.onnxONNX Runtime
ONNX INT8 → Embedded.onnx

/转换后格式
取决于目标平台

这正好把你之前学的TFLM和现在的ONNX Runtime联系起来。

3. 第一步:确认 ONNX Runtime 环境

在你的 Mac 上进入之前的 ONNX 项目:

cd ~/learn/onnx/onnx_int8

如果你已经建立 .venv:
source .venv/bin/activate

检查:
python --version

然后:
python -m pip install -U onnx onnxruntime numpy

官方 CPU Python package 就是:
pip install onnxruntime

检查:
python -c “import onnxruntime as ort; print(ort._version_)”

再检查:
python -c “import onnx; print(onnx._version_)”

4. 第二步:先看看我们的 FP32 ONNX

假设 Step 1 最终生成:
model.onnx

执行:
ls -lh model.onnx

然后:测试
inspect_onnx.py

importonnx model=onnx.load("model.onnx")print("IR version:",model.ir_version)print("Opset:")foropsetinmodel.opset_import:print(" ",opset.domain,opset.version)print("\\nInputs:")forxinmodel.graph.input:print(x.name)print("\\nOutputs:")forxinmodel.graph.output:print(x.name)

python inspect_onnx.py

特别注意:

Opset >= 10

ONNX Runtime 当前量化工具要求模型至少是opset(Operator Set)10。

5. 第三步:为什么不能直接 quantize?

这是这一步最重要的概念。

假设模型:

input ↓ Conv ↓ ReLU ↓ Conv ↓ output

我们知道:

input = \[-1.2,-0.5,0.1,0.8,1.3\]

但是中间 activation:

Conv1 output Conv2 output...

我们不知道它们的真实范围。

例如:

Activation A: min =-2.37 max = 3.82

那么 calibration 就是:

输入大量真实数据 ↓ 运行 FP32 model ↓ 观察 activation ↓ 统计 min/max ↓ 计算 scale ↓ 计算 zero_point

所以:

Calibration dataset 是 Static INT8 Quantization 的核心。

ONNX Runtime 的 static quantization 正是先用 calibration data 运行模型,再计算 activation 的量化参数。

6. 第四步:准备 calibration dataset

这里一定不要随便生成完全随机的数据。

例如你的模型是:

input shape = [1]

如果原始训练数据是:

x = np.linspace(0, 2*np.pi, 1000)

那么 calibration data 应该来自类似的数据分布:

calibration_data = \[\[0.0\],\[0.01\],\[0.02\],...\[6.28\]\]

而不是:

np.random.randn(...)

因为 calibration 的作用就是告诉量化器:

“真实世界的数据进入这个模型以后,大概会产生什么样的 activation 范围?”

7. 第五步:创建 CalibrationDataReader

建立:

calibrate.py

先写一个最小版本:

importnumpyasnpimportonnxruntimeasortfromonnxruntime.quantizationimportCalibrationDataReaderclassMyCalibrationDataReader(CalibrationDataReader):def\__init_\_(self,input_name):self.input_name=input_name self.data=\[np.array(\[\[0.0\]\],dtype=np.float32),np.array(\[\[0.5\]\],dtype=np.float32),np.array(\[\[1.0\]\],dtype=np.float32),np.array(\[\[1.5\]\],dtype=np.float32),np.array(\[\[2.0\]\],dtype=np.float32),np.array(\[\[2.5\]\],dtype=np.float32),np.array(\[\[3.0\]\],dtype=np.float32),\]self.iterator=iter(self.data)defget_next(self):try:data=next(self.iterator)return{self.input_name:data}exceptStopIteration:returnNonesession=ort.InferenceSession("model.onnx",providers=\["CPUExecutionProvider"\])input_name=session.get_inputs()\[0\].nameprint("Input name:",input_name)print("Input shape:",session.get_inputs()\[0\].shape)print("Input type:",session.get_inputs()\[0\].type)先运行: ```powershell python calibrate.py

你应该看到类似:

Input name: input Input shape: \[1,1\]Inputtype: tensor(float)

8. 第六步:真正执行 INT8 Quantization

然后继续在 calibrate.py 中加入:

fromonnxruntime.quantizationimport(quantize_static,QuantType,QuantFormat,CalibrationMethod,)

然后:

reader=MyCalibrationDataReader(input_name)quantize_static(model_input="model.onnx",model_output="model_int8.onnx",calibration_data_reader=reader,quant_format=QuantFormat.QDQ,activation_type=QuantType.QInt8,weight_type=QuantType.QInt8,calibrate_method=CalibrationMethod.MinMax,)

完整结构就是:

importnumpyasnpimportonnxruntimeasortfromonnxruntime.quantizationimport(CalibrationDataReader,quantize_static,QuantType,QuantFormat,CalibrationMethod,)classMyCalibrationDataReader(CalibrationDataReader):def\__init_\_(self,input_name):self.input_name=input_name self.data=\[{"input":np.array(\[\[0.1,0.2,0.3,0.4\]\],dtype=np.float32)},{"input":np.array(\[\[0.2,0.3,0.4,0.5\]\],dtype=np.float32)},{"input":np.array(\[\[0.3,0.4,0.5,0.6\]\],dtype=np.float32)}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询