推理服务 · 内存

量化

8 位和 4 位权重,在真实的 GPT-2 上

模型
GPT-2 small 1.24 亿个权重
fp32
498 MB
int8
124 MB
int4
62 MB + 缩放因子
困惑度
52.9 → 62.6 fp32 → int4 g128

全部步骤

  1. 每个数用更少的位

    模型用 32 位或 16 位浮点训练。用 8 位或 4 位来服务,权重会小 2 到 4 倍,所以模型能放进更少的 GPU,而受限于读取权重的每个解码步也更快。

    每个权重 32 → 16 → 8 → 4 位

  2. 舍入到网格

    最简单的方案 absmax:除以一个缩放因子,让最大的权重落在最大的整数上,舍入,计算时再乘回去。int8 有 255 级,int4 只有 15 级,所以舍入误差大得多。这是 GPT-2 权重中真实的一列。

    q = round(w / s) · s = max|w| / (2^(b−1) − 1)

  3. 一个缩放因子还是多个

    整个矩阵只用一个缩放因子时,它由单个最大的权重决定,这让其他所有权重的网格都很粗。每个输出通道一个缩放因子,或每 128 个权重一组一个,就能跟上局部的范围。真实的 GPT-2,所有线性层都量化后重新运行。

    按张量 · 按通道 · 按 128 个一组

  4. 离群值

    激活比权重更难:少数维度比其余的大得多。在这个真实的 GPT-2 激活中,有一个数是典型大小的 30 倍,只用一个 int4 缩放因子时,大多数值都被舍入为零。LLM.int8 把这些维度保留在 16 位;大多数 4 位推理只量化权重。

    一个很大的值拉伸了整个网格

  5. 对模型的代价

    GPT-2 small 的真实代价。每通道一个缩放因子的 int8 几乎无损;按 128 分组的 int4 代价很小;整个矩阵一个缩放因子的 int4 会把模型弄坏。GPTQ 和 AWQ 等方法更聪明地选择舍入方式,让 4 位模型保持接近全精度。

    段落困惑度 · 下一词元猜测

代码

# absmax, symmetric: one scale per group of weights
q = 2 ** (bits - 1) - 1                          # 127 for int8, 7 for int4
W = W.reshape(out_features, -1, group)            # groups of 128 along the input
scale = W.abs().amax(dim=-1, keepdim=True) / q
codes = torch.round(W / scale).clamp(-q, q).to(torch.int8)
# at inference: dequantize on the fly (weight-only) and multiply in 16-bit
y = x @ (codes * scale).reshape(out_features, -1).T

延伸阅读