本文是「GPT 训练分步学习路径」的一篇番外,不依赖任何具体项目,只讲清楚一件事:模型量化到底是什么、用来做什么、又是怎么做的。看完你应该能听懂别人口中的「量化到 8bit / 4bit」「INT8 推理」「GPTQ / AWQ」到底在说什么。
目录
- 一句话先说清
- 量化在量什么:从浮点到整数
- 为什么要量化:省空间、提速度
- 核心原理:scale 与零点
- 8bit、4bit 是什么意思
- 三种主流量化方式
- 动态量化:最省事的入门做法
- 代价与取舍:精度掉了多少
- 核心结论速览
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 | ✅ 还能开更长上下文 |
所以量化的两大收益:
- 省内存/显存:模型体积直接按比例缩小,能跑在更小的设备上(甚至手机、浏览器)。
- 提速度:整数运算比浮点运算快,且搬运更少的数据意味着更少的内存带宽压力——推理往往是「内存带宽瓶颈」,量化后加速明显。
4. 核心原理:scale 与零点
量化不是简单「四舍五入砍掉小数」,而是把一批浮点数的动态范围,等比例映射到整数格子上。
以最常见的对称量化为例(映射到 INT8 的 -127~127):
1 | scale = 这批数里绝对值最大值 / 127 |
举个具体例子:一组权重范围是 [-0.8, 0.8],那么
1 | scale = 0.8 / 127 ≈ 0.0063 |
可以看到,只要额外记住一个 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 | import torch |
几个要点:
- 为什么只量
Linear:Transformer 里参数的绝大部分都在全连接层(注意力的 QKV 投影、前馈网络、输出层)。量它们收益最大,而 Norm、Embedding 这些占比小、且对精度更敏感,通常不动。 - 「动态」体现在哪:权重在保存时就转成了 INT8,但激活值是每次推理时才根据当前数据实时算 scale 并量化——所以不需要提前喂校准数据,最省事,代价是比静态量化稍慢一点。
- 主要面向 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 是大模型端侧的进阶操作,而动态量化则是你入门时最容易上手的第一步。