Model Quantization
模型量化会使用 INT8 等较低精度存储权重和激活值,以缩小模型并加快推理速度。了解其工作原理,以及 PTQ 与 QAT 的区别。
模型量化会将神经网络的权重(通常还包括激活值)从 32 位浮点数 (FP32) 转换为较低精度的格式,例如 16 位浮点数 (FP16)、8 位整数 (INT8) 或 4 位整数。这样,每个数值占用和传输的位数都更少,而且大多数处理器上的整数运算速度更快、能耗更低。INT8 模型的大小只有原始 FP32 模型的四分之一,这使目标检测模型能够在手机、摄像头和其他边缘 AI设备上实时运行,也让大型语言模型 (LLM)能够装入单块 GPU。
量化的工作原理#
量化会将一个实数范围映射到有限的整数级别。在常见的仿射方案中,每个浮点数 x 都会存储为整数 q = round(x / scale) + zero_point,并按 x ≈ (q - zero_point) × scale 还原。缩放因子决定各级别之间的步长,零点则确保浮点数 0 能映射到精确的整数。INT8 有 256 个级别,因此必须仔细选择范围:范围过宽会将级别浪费在从未出现的数值上,范围过窄则会截断离群值。权重是预先已知的,因此其范围可直接从训练好的模型中获取,通常按每个输出通道分别计算。激活值取决于输入,因此需要在校准期间,将少量有代表性的图像或文本样本输入模型,以测量其范围。
import numpy as np
rng = np.random.default_rng(0)
weights = rng.normal(0, 0.05, size=1000).astype(np.float32)
# Affine INT8 quantization maps the observed float range onto 256 integer levels
scale = (weights.max() - weights.min()) / 255
zero_point = np.round(-128 - weights.min() / scale)
q = np.clip(np.round(weights / scale + zero_point), -128, 127).astype(np.int8)
# Dequantize to measure the rounding error the model has to tolerate
restored = (q.astype(np.float32) - zero_point) * scale
print(f"Size: {weights.nbytes} -> {q.nbytes} bytes")
print(f"Max error: {np.abs(weights - restored).max():.5f} (half a step: {scale / 2:.5f})")它会输出 Size: 4000 -> 1000 bytes,最大误差为 0.00068,相当于半个量化步长。权重缩小到原来的四分之一,而且任何数值相对原始值的变化都不超过半个步长。
训练后量化与量化感知训练#
- 训练后量化 (PTQ):转换已训练好的模型,并使用少量校准样本设定激活值范围。整个过程只需几分钟,除了这些样本以外不需要训练数据。动态量化是 PTQ 的一种变体,它会在推理时即时计算激活值范围;仅权重量化则让激活值保持浮点格式。
- 量化感知训练 (QAT):在训练或微调期间,通过在前向传播中对数值进行舍入来模拟量化,使权重学会适应舍入。它可以弥补 PTQ 导致的大部分准确率损失,但需要额外训练。
团队通常会先尝试 PTQ,只有当准确率下降过多时才改用其他方法:
LLM 还有自己的量化方法。GPTQ和 AWQ 等仅权重 4 位方案会压缩数十亿个参数,同时让激活值保持 16 位;GGUF格式用于存储可在本地推理的量化模型;新款 GPU 则能原生使用 FP8等低精度浮点格式进行计算。
量化与相关技术的区别#
- 混合精度:一种训练技术,大多数运算以 FP16 或 BF16 执行,同时将权重的主副本保留为 FP32,从而加快训练。量化针对推理,精度降低得更多,通常会降到整数。
- 模型剪枝:移除权重或整个通道,以减少运算次数。它通常与量化结合使用;量化则能降低每次剩余运算的成本。
- 知识蒸馏:训练小型学生模型模仿大型教师模型。学生模型通常会在之后进行量化,以便部署。
实际应用中的量化#
加速效果取决于硬件支持:INT8 模型只有在具有 INT8 内核的处理器上才会运行得更快,例如使用 TensorRT的 NVIDIA GPU、使用 OpenVINO的 Intel CPU,以及手机中的神经处理单元 (NPU)。Ultralytics YOLO26会在导出时使用 quantize=8应用 PTQ,并通过 data数据集中的图像进行校准;而 model.train(quantize=8)则会使用 QAT 对检查点进行微调。下面的示例将模型导出为 INT8 格式,以便在 LiteRT(Google 面向 Android 和嵌入式设备的运行时)中使用:
from ultralytics import YOLO
# 加载预训练的 YOLO26 nano 模型
model = YOLO("yolo26n.pt")
# INT8 训练后量化;使用 coco8.yaml 中的图像校准激活值范围
model.export(format="litert", quantize=8, data="coco8.yaml")在 COCO上使用 TensorRT测得,INT8 PTQ 只会将 YOLO26n 的 mAP50-95从 0.403 降至 0.393,但对 YOLO26s 的影响更大,分数从 0.479 降至 0.441;使用 QAT 后,YOLO26s 的分数回升至 0.471。










