端侧神经网络量化(二):训练后量化(PTQ)

1. 什么是 PTQ

训练后量化(Post-Training Quantization,PTQ)是一种无需重新训练的量化方法:拿到一个已训练好的 FP32 模型,借助少量无标签校准数据,在几分钟内将其转换为 INT8 推理模型。

PTQ 的工作流:

复制代码
预训练 FP32 模型 → 插入量化观察器 → 校准数据集前向传播 → 统计每一层的值域 → 计算量化参数 → 转换为 INT8 推理图

PTQ 的核心假设是:校准数据的统计分布能代表真实推理时的数据分布。这也是 PTQ 精度能否达标的关键------校准数据的代表性决定了量化的天花板。


2. 权重量化校准

权重在推理时是静态的,因此可以在离线阶段精确量化。常见的校准方法有三种:

2.1 Min-Max 量化

最简单的方式:直接取权重的 min 和 max 作为量化范围。

复制代码
import torch
​
def minmax_quantize(weight, n_bits=8):
    qmin, qmax = -2**(n_bits-1), 2**(n_bits-1) - 1
    w_min, w_max = weight.min(), weight.max()
    scale = (w_max - w_min) / (qmax - qmin)
    zero_point = qmin - torch.round(w_min / scale)
    q_weight = torch.clamp(
        torch.round(weight / scale) + zero_point, qmin, qmax
    )
    return q_weight.type(torch.int8), scale, zero_point

Min-Max 的缺陷是极端值会撑大 scale,导致内部密集区域的量化精度不足。权重的长尾分布越严重,这个问题越突出。

2.2 MSE 校准

w_min, w_max 上搜索最优截断阈值,以最小化量化前后的均方误差。对所有权重值排序后,按百分位逐步收缩边界,选取 MSE 最小的点。

复制代码
def mse_calibrate(weight, n_bits=8):
    qmin, qmax = -2**(n_bits-1), 2**(n_bits-1) - 1
    best_mse, best_scale = float("inf"), None
    # 在 99.0% 到 99.999% 之间搜索最优截断边界
    for pct in [99.0, 99.5, 99.9, 99.99, 99.999]:
        v = torch.abs(weight).flatten().sort().values
        threshold = v[int(len(v) * pct / 100)]
        scale = threshold / qmax
        q = torch.clamp(torch.round(weight / scale), qmin, qmax)
        dq = q * scale
        mse = torch.mean((weight - dq) ** 2)
        if mse < best_mse:
            best_mse, best_scale = mse, scale
    return best_scale

MSE 校准在 ImageNet 分类模型上通常比 min-max 提升 0.5--1% Top-1 精度。

2.3 KL 散度校准

把原始分布和量化后分布看作两个概率分布,最小化它们之间的 KL 散度。将数据分箱(如 2048 bins),在直方图上搜索最优截断点,使截断后量化分布的 KL 散度最小。这是 NVIDIA TensorRT 默认的 INT8 校准算法。


3. 激活值校准

激活值随输入变化,无法像权重一样离线精确量化。PTQ 的做法是:跑一批校准数据,统计每层激活值的 min/max 或分布直方图,据此计算 scale 和 zero_point。

3.1 移动平均统计

逐 batch 更新 min 和 max 的滑动平均:

复制代码
class MovingAverageObserver:
    def __init__(self):
        self.min_val = float("inf")
        self.max_val = float("-inf")
​
    def update(self, x):
        self.min_val = min(self.min_val, x.min().item())
        self.max_val = max(self.max_val, x.max().item())

PyTorch 的 MovingAverageMinMaxObserver 在此基础上加入了动量衰减,使早期 batch 的极端值不会主导最终统计量。

3.2 百分位截断

不取激活值的绝对 min/max,而是按百分位截断------例如取 0.1%, 99.9% 区间内的值作为量化范围。这样可以剔除个别极端激活值对 scale 的破坏。

复制代码
def percentile_range(x, lower=0.1, upper=99.9):
    flat = x.flatten().sort().values
    low = flat[int(len(flat) * lower / 100)]
    high = flat[int(len(flat) * upper / 100)]
    return low, high

3.3 直方图观测器

PyTorch 的 HistogramObserver 将激活值分箱(如 2048 bins),在校准结束后按 KL 散度或 MSE 最小化选择截断点。这是精度最高的方式,但需要在校准期间存储直方图,内存开销略大。


4. 离群值问题

一个权重张量中 99.9% 的值落在 -0.5, 0.5,但个别值高达 ±5。若取全量 min/max:

  • scale = 5/127 ≈ 0.039

  • 量化精度(最小可区分差值)= 0.039

  • 原本 -0.5, 0.5 内只有约 26 个离散刻度可用

实际上内部 99.9% 的值被压缩到了极少的离散点上,信息几乎完全丢失。

解决方案:

  • 对权重使用 per-channel 量化,缩小每个 channel 内部的值域差异

  • 对激活值使用百分位截断,牺牲极端值保核心区域精度

  • 对于 LLM 中的异常输入通道(outlier features),混合精度保留 FP16


5. PyTorch FX PTQ 实战

复制代码
import torch
from torch.ao.quantization import get_default_qconfig_mapping
from torch.ao.quantization.quantize_fx import prepare_fx, convert_fx
​
# 1. 加载预训练模型
model = torch.hub.load("pytorch/vision", "resnet50", pretrained=True).eval()
​
# 2. 配置量化参数(per-channel 权重量化 + per-tensor 激活值量化)
qconfig_mapping = get_default_qconfig_mapping("x86")
​
# 3. 准备:在图中插入 FakeQuantize 观察器节点
example_input = torch.randn(1, 3, 224, 224)
model_prepared = prepare_fx(model, qconfig_mapping, example_input)
​
# 4. 校准:跑若干张校准图片
with torch.no_grad():
    for image, _ in calib_loader:
        model_prepared(image)
​
# 5. 转换:FakeQuantize 变为量化-反量化节点
model_quantized = convert_fx(model_prepared)

PTQ 全流程通常在 5--10 分钟内完成,校准数据 100--500 张即可。


6. PTQ 的适用边界

PTQ 适合的场景:

  • 卷积网络(ResNet、MobileNet、EfficientNet):INT8 精度损失通常 < 1%

  • 校准数据容易获取(从训练集或生产日志采样即可)

  • 部署周期紧张,无法承担重新训练成本

PTQ 不适合的场景:

  • 极低位宽(≤ 4-bit):误差累积太大,必须 QAT

  • 模型层数极深或结构特殊(如某些 NLP 模型):误差在深层放大严重

  • 校准数据与真实推理数据分布差异大:统计估计失效

7. 小结

PTQ 是量化工程化的第一选择------成本低、速度快、在大多数视觉模型上精度可接受。当 PTQ 精度不达标时,下一步是引入训练信号来补偿量化误差,即下一篇要讨论的量化感知训练(QAT)。

相关推荐
2603_9663027518 分钟前
2026企业AI办公工具选型全指南
人工智能
Henry-SAP20 分钟前
AI芯片与具身智能双突破
人工智能·云原生·sap·erp
Leo.yuan21 分钟前
Kafka数据实时入仓的两种路径:Kafka Connect vs FineDataLink
大数据·人工智能
海盗123421 分钟前
微软技术日报·2026-08-28——微软正式将 Microsoft 365 Roadmap 重命名为 **AI at Work
人工智能·microsoft
玹外之音22 分钟前
Codex CLI 非交互模式:把 AI 接入你的 CI/CD 流水线
人工智能·ci/cd·交互
u13013024 分钟前
AI 日报(2026年8月28日)
人工智能
向上的车轮24 分钟前
DeepSeek Harness:用 Creator 模式开发自定义插件,从 0 到可调用
人工智能·deepseekharness
老郑聊AI业财智造24 分钟前
从“思考-行动”到“知行合一”:ReActAgent的架构原理与工程实践全景剖析
人工智能·架构·系统架构·软件工程·软件构建
l12586526 分钟前
# LangGraph Tool Calling Agent 深度实战:从零构建 ReAct 循环与工具调用链
人工智能·python·自然语言处理·langchain·agent