深度学习的模型量化

一、什么是模型量化

模型量化(Model Quantization) 是一种深度学习模型优化技术,核心是将模型中高精度的浮点数(如 FP32/FP16)参数和激活值,转换为低比特位宽的整数(如 INT8/INT4)或低精度浮点数(如 FP8),以压缩模型体积、加速推理、降低功耗,同时将精度损失控制在可接受范围。

其核心原理是:数值映射。

本质是连续高精度浮点 → 离散低精度整数的线性映射,通过两个关键参数实现:

  • 缩放因子 (Scale, S):控制映射粒度,决定整数间的实际数值间隔
  • 零点 (Zero Point, Z) :确保原始 0 值被精确映射(避免填充 / 偏置误差)

将高精度的浮点数,映射为整数或低精度的浮点数,从而实现压缩模型体积、加速推理、降低功耗的问题,

为什么数值上可扩大,反而能缩小功耗?

一句话先破题

你看到的 **"数值扩大" 只是数学上的计算 **,真正决定功耗的,是硬件里存储和计算用的比特位数(bit 数),位数越少,功耗越低,跟数值本身大小没关系。

从硬件上看:

硬件层面:bit 越少,电路越轻松

  • FP32:32 根线 / 32 个寄存器一起工作
  • INT8:只需要 8 根线 / 8 个寄存器

位数越少:

  • 翻转的晶体管更少
  • 读取的数据量更少
  • 内存带宽压力更小
  • 运算单元更简单、更快

这些全部直接导致功耗降低

二、常见的量化方案

1. 按精度位宽
精度 位宽 存储 典型用途
FP32 32bit 4 字节 训练基准
FP16/BF16 16bit 2 字节 半精度训练 / 推理
INT8 8bit 1 字节 主流部署(W8A8)
INT4 4bit 0.5 字节 大模型极致压缩
1bit (二值) 1bit 1 比特 极端低功耗场景
2. 按映射方式
  • 对称量化 :以 0 为中心对称映射(如 -max ↔ -128max ↔ 127),适合权重(分布对称)
  • 非对称量化 :按实际 min/max 范围映射,带零点偏移,适合激活值(分布偏正)
3. 按实施阶段
  • 训练后量化 (PTQ) :模型训完直接量化,简单快速,但精度损失较大(尤其低位宽)
  • 量化感知训练 (QAT) :训练中模拟量化误差,让权重适应低精度,精度几乎无损,但需重训

三、什么是原始0值?

在模型量化里说的原始 0 值 ,就是:模型里本来是 0 的那个浮点数值,不是你自己随便定义的 0。

1. 它具体指什么?

模型里有很多浮点数,比如:0.00.000123-2.456123.45 ......

其中那个等于 0 的浮点值,就是 "原始 0 值":x=0.0......

2. 为什么要专门提它?

量化是做映射:浮点数 x→整数 Xq​

我们希望:

原来的 0.0,映射后也要是一个整数里的 "0 位置"

不然会出问题:

  • 很多卷积、矩阵乘法里,0 代表 "无信号、无权重"
  • 如果 0 映射歪了,整个计算偏移会很大,精度掉得离谱

3. 用零点(Zero Point)保证原始 0 映射准确

公式里你见过:Xq​=round(Sx​+Z)

原始 0 值 代入:x=0⇒Xq​=Z

所以:

  • 零点 Z 就是:原始浮点 0.0 对应的量化整数
  • 反量化时:x=(Z−Z)×S=0能精确还原回 0.0,没有误差.

四、会不会同时有多个0值?

1. 模型里确实有很多 0

比如:

  • 权重里的 0
  • 激活值经过 ReLU 后变成的 0
  • 残差连接里的 0
  • padding 填充的 0

这些都是原始 0 值,数量成千上万。

2. 量化时它们会变成同一个值

同一个量化层(同一个 scale、同一个 zero point)下:

  • 所有浮点 0.0
  • 都会被映射成 同一个整数 Z

公式再看一眼:Xq​=round(x/S​+Z)当 x=0.0:Xq​=Z不管有多少个 0.0,算出来都是 同一个 Z

3. 会不会出现 "多个零点"?

不会。

标准对称 / 非对称量化里:

  • 一个 tensor / 一个量化组
  • 只有 一个 scale S
  • 只有 一个 zero point Z

所以:

  • 所有原始 0.0 → 统一映射到 Z
  • 反量化时 Z 又统一还原成 0.0

五、量反化是怎么操作的?

1. 反量化公式(通用版)

Xfloat​=(Xquant​−z)×s

  • xquant:量化后的整数(比如 INT8)
  • z:zero point(零点)
  • s:scale(缩放因子)
  • 结果 Xfloat:还原出来的近似浮点数

2. 一步一步看它在干嘛

  1. 先减去零点把整数 "挪回" 以零点为中心的位置xquant​−z

  2. 再乘以 scale把小整数区间放大回原来的浮点区间(...)×s

就这两步。

3. 举个超简单例子

假设:

  • scale s=0.1
  • zero point z=10
  • 量化后整数 Xquant=15

反量化:xfloat​=(15−10)×0.1=0.5

4. 最关键的:原始 0 还原回去还是 0

当量化值刚好是零点时:xfloat​=(10−10)×0.1=0.0

这就是为什么要设计 zero point:保证原来的 0,反量化后一定精确是 0,不会有误差。

六、缩放因子是怎么计算的?

缩放因子 scale,就是用来把「浮点数的真实范围」和「整数的可用范围」对齐的那个比值 。它不是猜的,是根据你这一组数据的最大最小值算出来的

1. scale 到底是干嘛的?

浮点数范围很大,比如:[-2.4, 1.8]

但 INT8 整数只有固定范围:[-128, 127]

我们要做的就是:把 [-2.4, 1.8] 压缩 / 拉伸到 [-128, 127] 这个拉伸倍数 ,就是 scale

2. scale 怎么算?(最常用对称量化)

先找这组数据的最大绝对值max_abs = max(|min|, |max|)

然后除以整数能表示的最大绝对值:scale=max_abs/127

举个例子

浮点数据范围:[-2.4, 1.8]max_abs = 2.4

scale = 2.4 / 127 ≈ 0.0188976

这就是最终的缩放因子。

3. 非对称量化(带零点那种)怎么算 scale?

更通用的公式:

scale=max_float−min_float​/max_int−min_int qaAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

  • max_float, min_float:这组数据的最大、最小浮点值
  • max_int, min_int:整数范围(比如 INT8 就是 127 和 -128)

这样算出来的 scale 能刚好把整个浮点区间塞满整数区间,不浪费精度,也不溢出。

4. 一句话记住

scale = 浮点数据的跨度 ÷ 整数能表示的跨度 它的作用就是:把浮点数 "缩" 到整数能装下的范围里,反量化时再 "放" 回去。

七、多个浮点数值,可能会映射到同一个整数值上吗?

1. 答案:一定会多个浮点 → 同一个整数

举个最容易懂的例子:

假设:

  • 缩放因子 scale = 0.1
  • 零点 zero_point = 0

量化公式(简化):xq​=round(scalex​)

那么:

  • 浮点 0.05 → round(0.05/0.1) = round(0.5) → 0
  • 浮点 0.06 → round(0.6) → 1
  • 浮点 0.14 → round(1.4) → 1

看到没:0.06 和 0.14 两个不同的浮点数,最后都变成了整数 1

这就叫:多个浮点数值,被映射到同一个整数值


2. 本质原因:精度 "变粗" 了

  • FP32:小数点后很多位,非常精细
  • INT8:只有 256 个离散值,很粗糙

就像:

  • 尺子原来刻度到 0.1mm(精细)
  • 现在刻度只到 1cm(粗糙)

0.3cm、0.5cm、0.7cm 都会被当成 0cm 或 1cm多个值挤到同一个格子里,就重合了。


3. 这会带来什么?

这就是量化的精度损失

  • 原本不同的数值,量化后变得一样
  • 模型细节信息丢失
  • 但换来模型更小、更快、更省电

八、好,我们现在完整走一遍流程

场景设定

假设我们有一小段浮点数值 (模拟模型里的权重或激活值):[-1.2, -0.5, 0.0, 0.3, 1.0]

我们要把它量化成 INT8 。INT8 的整数范围是:[-128, 127]


第 1 步:计算浮点的 min 和 max

浮点数据:[-1.2, -0.5, 0.0, 0.3, 1.0]

  • min_float = -1.2
  • max_float = 1.0

第 2 步:计算缩放因子 scale

公式(非对称量化):scale=max_float−min_float​/max_int−min_int

代入:

  • max_float - min_float = 1.0 - (-1.2) = 2.2
  • max_int - min_int = 127 - (-128) = 255

scale=2552.2​≈0.008627


第 3 步:计算零点 zero_point

公式:zero_point=round(min_float​/−scale+min_int)

代入:min_float​/−scale=−(−1.2​/0.008627)≈139.1

zero_point=round(139.1−128)=round(11.1)=11

所以:

  • scale ≈ 0.008627
  • zero_point = 11

第 4 步:量化(浮点 → INT8 整数)

公式:Xq​=round(x/scale​+zero_point)

我们逐个算:

  1. x = -1.2 −1.2/0.008627​+11≈−139.1+11=−128.1→−128

  2. x = -0.5 −0.5​/0.008627+11≈−57.96+11=−46.96→−47

  3. x = 0.0 0/0.008627+11=11→11👉 原始 0 精确映射到 zero_point

  4. x = 0.3 0.3​/0.008627+11≈34.77+11=45.77→46

  5. x = 1.0 1.0​/0.008627+11≈115.9+11=126.9→127

量化结果(整数): [-128, -47, 11, 46, 127]


第 5 步:反量化(整数 → 近似浮点)

公式:Xfloat​=(Xq​−zero_point)×scale

逐个还原:

  1. -128 (−128−11)×0.008627=−139×0.008627≈−1.199

  2. -47 (−47−11)×0.008627=−58×0.008627≈−0.500

  3. 11 (11−11)×0.008627=0 👉 0 完美还原

  4. 46 (46−11)×0.008627=35×0.008627≈0.302

  5. 127 (127−11)×0.008627=116×0.008627≈1.001

反量化结果: [-1.199, -0.500, 0.0, 0.302, 1.001]


最终对比

原始浮点:[-1.2, -0.5, 0.0, 0.3, 1.0]反量化结果:[-1.199, -0.5, 0.0, 0.302, 1.001]

可以看到:

  • 几乎一样
  • 有一点点微小误差(这就是量化误差)
  • 0 永远精确还原

用一句话总结整个流程

  1. 看浮点最大最小
  2. 算出 scale 把区间缩放到 INT8
  3. 算出 zero_point 保证 0 不偏移
  4. 浮点 ÷ scale + zero_point → 整数
  5. 推理完再 (整数 − zero_point) × scale → 还原浮点

这就是模型量化的完整数学过程

相关推荐
KuAI_KST2 小时前
医美抖音AI客服推荐,低成本撬动本地医美获客增长
人工智能
翼龙云_cloud2 小时前
阿里云代理商:部署OpenClaw高效办公六式 智能打理日常任务
人工智能·阿里云·云计算·openclaw
云烟成雨TD2 小时前
Spring AI 1.x 系列【24】结构化输出 API
java·人工智能·spring
武汉庞小锋2 小时前
opencode使用各大模型小结
人工智能
拾光向日葵2 小时前
南京林业大学2026年硕士研究生跨门类调剂政策详解
大数据·人工智能·物联网
LSQ的测试日记2 小时前
深度学习_YOLO,卡尔曼滤波和
人工智能·深度学习·yolo
枫叶林FYL2 小时前
【自然语言处理 NLP】前沿架构与多模态 状态空间模型(Mamba/SSM)深度实现
人工智能·机器学习
Westward-sun.3 小时前
OpenCV 实战:SIFT 指纹特征匹配与可视化(补充版)
人工智能·opencv·计算机视觉
财经资讯数据_灵砚智能3 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年4月7日
大数据·人工智能·python·信息可视化·语言模型·自然语言处理·ai编程