模型量化入门——用更少的比特装下同一个模型(大模型番外)

本文是「GPT 训练分步学习路径」的一篇番外,不依赖任何具体项目,只讲清楚一件事:模型量化到底是什么、用来做什么、又是怎么做的。看完你应该能听懂别人口中的「量化到 8bit / 4bit」「INT8 推理」「GPTQ / AWQ」到底在说什么。


目录

  1. 一句话先说清
  2. 量化在量什么:从浮点到整数
  3. 为什么要量化:省空间、提速度
  4. 核心原理:scale 与零点
  5. 8bit、4bit 是什么意思
  6. 三种主流量化方式
  7. 动态量化:最省事的入门做法
  8. 代价与取舍:精度掉了多少
  9. 核心结论速览

1. 一句话先说清

量化(Quantization)= 把模型里的高精度浮点数,用更少比特的整数来近似表示,从而让模型更小、更快,代价是损失一点点精度。

打个比方:原本你用「1.2384759 米」来记身高(32 位浮点,精确但占地方),量化后改成「1.24 米」甚至「124 厘米」(整数,省事但略糙)。模型里成百上千万个数字都这么处理,累积起来省下的空间和算力就很可观了。


2. 量化在量什么:从浮点到整数

神经网络里被量化的对象主要有两类:

  • 权重(weights):训练好后固定不变的参数,是量化的主要目标。
  • 激活值(activations):前向计算时每一层产生的中间结果,随输入变化。

它们平时用什么精度存?

精度 每个数占用 说明
FP32(单精度浮点) 32 bit 训练时的默认精度,最准
FP16 / BF16(半精度) 16 bit 训练/推理常用,省一半
INT8(8 位整数) 8 bit 部署最常用的量化目标
INT4(4 位整数) 4 bit 大模型端侧部署,压得更狠

量化做的事,就是把上面这些 FP32 的权重,映射成 INT8 或 INT4 的整数


3. 为什么要量化:省空间、提速度

一个 70 亿参数(7B)的模型,如果每个参数用 FP32 存:

1
7,000,000,000 × 4 字节 ≈ 28 GB

普通消费级显卡(如 24GB 的 4090)根本装不下。而量化后:

精度 7B 模型大小 能否塞进 24GB 显卡
FP32 ~28 GB
FP16 ~14 GB 勉强
INT8 ~7 GB ✅ 轻松
INT4 ~3.5 GB ✅ 还能开更长上下文

所以量化的两大收益:

  1. 省内存/显存:模型体积直接按比例缩小,能跑在更小的设备上(甚至手机、浏览器)。
  2. 提速度:整数运算比浮点运算快,且搬运更少的数据意味着更少的内存带宽压力——推理往往是「内存带宽瓶颈」,量化后加速明显。

4. 核心原理:scale 与零点

量化不是简单「四舍五入砍掉小数」,而是把一批浮点数的动态范围,等比例映射到整数格子上

以最常见的对称量化为例(映射到 INT8 的 -127~127):

1
2
3
4
scale = 这批数里绝对值最大值 / 127

量化: q = round(x / scale) # 浮点 x → 整数 q
反量化:x' = q × scale # 整数 q → 浮点近似 x'

举个具体例子:一组权重范围是 [-0.8, 0.8],那么

1
2
3
scale = 0.8 / 127 ≈ 0.0063
权重 0.5 → round(0.5 / 0.0063) = round(79.4) = 79 (存成整数 79)
读回来 → 79 × 0.0063 ≈ 0.4977 (近似原来的 0.5)

可以看到,只要额外记住一个 scale,就能在整数和浮点之间来回换算。误差就来自那次 round 取整(0.5 → 0.4977)。

如果数据分布不对称(比如激活值经过 ReLU 后全是正数),还会引入一个零点(zero-point)做偏移,这叫非对称量化。原理一样,只是多一个平移量:

1
q = round(x / scale) + zero_point

关键洞察:量化的精髓不是「变笨」,而是「用 scale(+zero_point)这把尺子,把连续的浮点世界,投影到离散的整数格子上」。格子越少(比特越低),投影越粗糙。


5. 8bit、4bit 是什么意思

「量化到 8bit / 4bit」里的数字,就是量化后每个权重用几个比特表示,也就决定了整数格子有多少格:

比特数 整数范围 格子数 通俗理解
8 bit -128 ~ 127 256 格 精度损失小,最常用
4 bit -8 ~ 7 16 格 压缩狠,需专门算法保精度
2 bit / 1 bit 极少 4 格 / 2 格 极端压缩,精度损失大,研究居多

比特越少,模型越小越快,但每个数能表达的「档位」也越少,误差越大。所以:

  • INT8:通用做法,多数模型精度几乎无感损失,PyTorch / TensorRT 等原生支持。
  • INT4:属于「进阶量化」,直接暴力量到 4bit 会明显掉点,所以出现了 GPTQ、AWQ、bitsandbytes(nf4) 等专门算法——它们通过分组量化、按重要性保护关键权重、用校准数据补偿误差等手段,把 4bit 的精度损失压到可接受范围。这也是为什么大模型端侧部署常说「用 GPTQ 量到 4bit」。

6. 三种主流量化方式

按「什么时候确定量化参数」来分,主要有三类:

方式 何时量化 要不要校准数据 要不要重训 特点
动态量化 (Dynamic) 权重提前量化;激活值推理时临时量化 不要 不要 最简单,适合入门和 CPU 推理
静态量化 (Static / PTQ) 权重和激活值都提前量化 要(喂少量样本统计范围) 不要 更快,需一次校准流程
量化感知训练 (QAT) 训练时就模拟量化误差 精度最好,但成本最高

三者的取舍很直白:

  • 想省事、不想动训练 → 动态量化
  • 想更快、能接受跑一次校准 → 静态量化
  • 精度要求苛刻、愿意重新训练 → QAT

其中 PTQ(Post-Training Quantization,训练后量化)是静态和动态的统称——都在训练完成之后做,不碰训练过程。


7. 动态量化:最省事的入门做法

动态量化是门槛最低的一种,主流框架一行代码就能用。以 PyTorch 为例:

1
2
3
4
5
6
7
import torch

quantized_model = torch.quantization.quantize_dynamic(
model, # 原始 FP32 模型
{torch.nn.Linear}, # 只量化 Linear 层(参数大头)
dtype=torch.qint8, # 量化到 INT8
)

几个要点:

  1. 为什么只量 Linear:Transformer 里参数的绝大部分都在全连接层(注意力的 QKV 投影、前馈网络、输出层)。量它们收益最大,而 Norm、Embedding 这些占比小、且对精度更敏感,通常不动。
  2. 「动态」体现在哪:权重在保存时就转成了 INT8,但激活值是每次推理时才根据当前数据实时算 scale 并量化——所以不需要提前喂校准数据,最省事,代价是比静态量化稍慢一点。
  3. 主要面向 CPU 推理:动态量化的加速在 CPU 上最明显;GPU 通常走 FP16/静态量化路线。

用起来就是这么朴素:加载一个「量化过的模型」,然后照常 forward / 生成,框架内部自动帮你在整数和浮点之间换算。


8. 代价与取舍:精度掉了多少

量化不是免费午餐,核心代价是精度损失(那次 round 取整带来的误差)。经验上:

量化目标 典型精度损失 建议
FP16 几乎无 放心用
INT8 很小,多数任务无感 部署首选
INT4(配 GPTQ/AWQ) 小到中等 大模型端侧值得
INT4(暴力量化) 明显 不推荐
≤2bit 较大 多为研究

几条实用经验:

  • 模型越大,越抗量化:大模型冗余多,量化后精度损失相对更小——这也是「大模型才特别爱量化」的原因之一。
  • 小模型量化收益有限:一个几 MB 的小模型,本来就装得下、跑得快,量化省下的空间和时间都不多,更多是「练手 / 演示技术」的意义。
  • 别对 Norm、Embedding 乱下手:这些层对精度敏感,量化它们容易崩,通常保留高精度。

9. 核心结论速览

问题 一句话回答
量化是什么 把高精度浮点权重用更少比特的整数近似表示
靠什么还原 一个 scale(+ 可选 zero_point)做整数↔浮点换算
量化能得到什么 模型更小(省显存)、推理更快(少搬数据)
8bit / 4bit 指什么 量化后每个权重占几个比特,越少越小越快也越糙
有哪几种做法 动态量化、静态量化(PTQ)、量化感知训练(QAT)
最省事的做法 动态量化,一行 quantize_dynamic,无需校准/重训
INT4 为什么难 格子太少,需 GPTQ/AWQ 等算法保精度
主要代价 取整带来的精度损失,模型越大越不明显

一句话收尾:量化的本质,是拿一把叫 scale 的尺子,把连续的浮点世界投影到离散的整数格子上——用可控的精度损失,换来实打实的体积缩小和速度提升。8bit 是通用甜点区,4bit 是大模型端侧的进阶操作,而动态量化则是你入门时最容易上手的第一步。