当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异怎样在批处理代码中减少额外分配

ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异怎样在批处理代码中减少额外分配

来源:17golang原创 2026-11-10 02:45:41 0浏览 收藏

比较 ONNX Runtime 动态量化和静态量化时,不能只看模型文件变小了多少。两者最关键的区别是激活值的 scale 与 zero_point 何时得到:动态量化在每次前向计算时处理,静态量化在离线校准阶段提前写入模型。前者省掉了校准数据准备,后者减少了推理时的计算开销。要比较部署差异,应固定同一份 FP32 模型、输入分布、执行后端和批处理方式,再同时观察延迟、吞吐、内存与任务精度。

简单判断:Transformer 或 RNN 可以先试动态量化;CNN 和有稳定校准集的服务通常更适合静态量化。最终选择仍要以目标硬件上的实测和精度预算为准。

官方参考地址:https://onnxruntime.ai/docs/performance/model-optimizations/quantization.html

触发信号:两种量化结果不能直接横比

动态量化会根据当前前向输入在线计算激活量化参数,因此每个批次可能承担额外的参数计算成本;静态量化先用校准数据运行模型,把激活参数作为常量保存,推理时直接使用。权重的量化方式、模型预处理、执行提供者和线程配置如果不一致,最后的差异就不能归因于“动态”或“静态”。

比较时先固定四件事:原始模型文件、输入预处理、batch 形状和 Execution Provider。模型还必须使用 opset 10 或更高版本。ONNX Runtime 官方文档说明,量化工具主要处理 8 位线性量化,并提供 quantize_dynamic() 与 quantize_static() 两类 Python API。

FP32 模型经过预处理后进入动态量化或静态量化,最终交给 ONNX Runtime 推理的静态结构说明图
图1:动态量化与静态量化在模型、量化参数和推理边界上的关系说明图,不是截图或运行证据。

快速判断:先锁定模型、输入和执行后端

先把输入组织成可重复读取的批次。静态量化需要校准集,但校准集不应被当成训练集:它的任务是覆盖线上常见的激活范围,而不是更新模型参数。校准样本应尽量使用与线上一致的预处理、长度分布和类别比例;如果样本过窄,静态量化的激活范围可能不代表真实流量。

from pathlib import Path
import numpy as np
import onnxruntime as ort

# 量化脚本只创建一次会话,避免在每个批次里重复加载模型。
model_path = Path("model.onnx")
session = ort.InferenceSession(
    str(model_path),
    providers=["CPUExecutionProvider"],  # 对照实验中固定执行后端
)
input_name = session.get_inputs()[0].name

def calibration_reader(samples, batch_size=8):
    # 固定批大小,保证动态量化和静态量化使用相同输入形状。
    for start in range(0, len(samples), batch_size):
        batch = np.asarray(samples[start:start + batch_size], dtype=np.float32)
        yield {input_name: batch}

# 生产代码中将 samples 替换为脱敏后的真实分布样本。
for feed in calibration_reader(samples):
    _ = session.run(None, feed)  # 这里只示意校准输入的形状与读取方式

上面的读取器只展示批次边界,不代表已经在本机运行。真正生成静态模型时,需要把同样的读取逻辑接到 CalibrationDataReader,并确保校准输入与部署输入的 dtype、布局和维度约定一致。

处理步骤:分别生成动态模型和静态模型

动态量化的最小路径不需要校准数据,适合先快速得到一个对照模型。静态量化则需要校准读取器,并选择 MinMax、Entropy 或 Percentile 等校准方法。两份输出文件应使用不同路径,避免后续测试时把模型文件混淆。

from onnxruntime.quantization import (
    CalibrationDataReader,
    QuantType,
    QuantFormat,
    quantize_dynamic,
    quantize_static,
)

fp32_path = "model.onnx"
dynamic_path = "model.dynamic.int8.onnx"
static_path = "model.static.int8.onnx"

# 动态量化在推理时计算激活参数,先生成独立的对照文件。
quantize_dynamic(
    model_input=fp32_path,
    model_output=dynamic_path,
    weight_type=QuantType.QInt8,
)

class Reader(CalibrationDataReader):
    def __init__(self, batches):
        self._batches = iter(batches)

    def get_next(self):
        # 读完返回 None,量化器才能结束校准读取。
        return next(self._batches, None)

# batches 必须来自与线上一致的预处理,不能用动态生成的随机数据代替。
reader = Reader(calibration_batches)
quantize_static(
    model_input=fp32_path,
    model_output=static_path,
    calibration_data_reader=reader,
    quant_format=QuantFormat.QDQ,
    activation_type=QuantType.QUInt8,
    weight_type=QuantType.QInt8,
)

静态模型的好处是推理阶段不必为每个输入重新估计激活参数,但代价是需要维护校准数据和校准过程。若量化后精度下降,应先比较浮点模型与量化模型的权重、激活差异,再决定更换校准方法、调整量化范围或排除特定张量;不要直接把一次低分归咎于 batch 大小。

处理步骤:让批处理循环复用资源

公平比较性能时,量化方法之外的 Python 分配也要控制住。常见浪费包括每个 batch 重建 InferenceSession、反复创建输入字典、把列表多次转换成数组,以及为了记录结果复制整块输出。可复用的最小结构是:会话只创建一次,输入数组按固定形状复用,输出只保留当前比较需要的字段。

import numpy as np
import onnxruntime as ort

def run_batches(model_path, batches, input_name):
    # 会话和输入容器都放在循环外,避免每次推理重复分配。
    session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
    reusable_input = {input_name: None}
    latency_records = []

    for batch in batches:
        # 只在形状变化时重新生成数组;固定 batch 时可直接复用缓冲区。
        reusable_input[input_name] = np.asarray(batch, dtype=np.float32)
        outputs = session.run(None, reusable_input)
        # 只提取评估所需结果,避免长期保存整个输出对象。
        latency_records.append(outputs[0].shape)

    return latency_records

# 动态模型和静态模型应分别调用同一个函数,保持循环结构一致。
dynamic_shapes = run_batches("model.dynamic.int8.onnx", batches, "input")
static_shapes = run_batches("model.static.int8.onnx", batches, "input")

如果输入来自固定大小的 NumPy 缓冲区,可以在循环外分配目标数组,再用切片或 np.copyto 更新内容;如果最后一个批次大小不同,则应单独处理尾批,不能为了复用而错误填充数据。这里的“减少额外分配”是减少测试噪声和垃圾回收压力,不等于保证所有 Execution Provider 都会原地复用底层内存。

DataReader、校准批次、输入缓冲区、量化会话、输出缓冲区和比较指标之间的静态关系说明图
图2:批处理输入、会话复用、输出对象和比较指标的结构说明图,不是截图或运行证据。

告警确认:不要只用一次耗时决定部署方案

建议为浮点、动态量化、静态量化三份模型建立同一份测试表。先预热,再记录稳定批次的 p50/p95 延迟、吞吐、峰值内存和分配行为;同时用固定评估集计算任务指标。对于分类模型,至少记录准确率或 F1;对于生成或检测模型,则使用该任务原本的质量指标。示例表格只定义口径,不填入未经运行得到的数字。

维度动态量化静态量化比较时的注意点
激活参数每次前向在线计算校准后离线固定在线开销与校准代表性要分开看
数据准备不要求校准集需要校准读取器和样本样本分布会影响精度
适用倾向Transformer、RNN 可优先试CNN 或激活范围稳定时可优先试模型结构不是绝对规则
部署成本流程简单,推理有额外计算流程多一步,推理更可预测必须在目标硬件实测

硬件也会改变结论。官方文档指出,支持 VNNI、Tensor Core INT8 或 Arm 点积指令的平台更可能从量化中获得收益;老硬件可能因为缺少高效指令和量化/反量化开销而变慢。若静态和动态都达不到精度目标,可以回到原框架做量化感知训练,再转换为 ONNX。

回滚路径与复盘:按模型、硬件和数据做选择

如果目标是快速得到一个可部署的 INT8 对照,先用动态量化;如果服务有稳定的线上样本、对推理时延更敏感,且愿意维护校准流程,静态量化更值得投入。两者都应保持相同的模型预处理和批处理循环,避免把输入转换、会话创建或输出拷贝的成本混进量化方法本身。

常见追问:为什么量化后模型变小,却没有变快?

模型体积减少只说明存储或内存压力可能下降,实际速度还取决于执行后端是否有高效 INT8 内核、算子是否被支持,以及量化和反量化开销是否超过计算收益。

常见追问:静态量化一定比动态量化精度低吗?

不一定。静态量化依赖校准集覆盖真实激活范围;校准集合适时可以获得稳定结果,集合不合适时才更容易出现明显精度损失。应使用同一评估集比较,而不是凭方法名称判断。

常见追问:怎样避免批处理测试被分配抖动干扰?

让 InferenceSession 在循环外创建,固定 batch 形状,复用输入容器,预热后再记录多批结果,并把尾批单独统计。这样能减少 Python 层噪声,但仍需结合目标执行提供者的内存行为分析。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异为什么结果为空或不符合预期ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异为什么结果为空或不符合预期
上一篇
ONNX Runtime 量化怎样比较动态量化与静态量化的部署差异为什么结果为空或不符合预期
Hugging Face Datasets streaming大数据集怎样流式读取而不一次载入内存怎样完成一个可复用的最小示例
下一篇
Hugging Face Datasets streaming大数据集怎样流式读取而不一次载入内存怎样完成一个可复用的最小示例
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    965次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    966次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1077次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1056次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    888次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码