第4章 LLM 4-bit 量化实战:LLM 4-bit 量化到底意味着什么?

第4章 LLM 4-bit 量化实战:LLM 4-bit 量化到底意味着什么?

本章目录:

第一:

为什么 LLM 需要量化?

因为模型参数越来越大,FP16/BF16 权重会占用大量显存和存储空间。

第二:

量化到底做了什么?

本质上是:

C o n t i n u o u s   V a l u e → D i s c r e t e   V a l u e \boxed{ Continuous\ Value \rightarrow Discrete\ Value } Continuous ValueDiscrete Value

并通过: x q = r o u n d ( x / s ) x_q=round(x/s) xq=round(x/s) 将高精度浮点数映射到低比特整数表示。

第3章进一步学习了 PTQ:

P o s t   T r a i n i n g   Q u a n t i z a t i o n \boxed{ Post\ Training\ Quantization } Post Training Quantization

即模型训练完成以后再进行量化。

那么一个自然的问题出现了:

到底什么叫“4-bit 量化”?

例如我们经常看到:

Llama 7B 4-bit
Qwen 7B 4-bit
GPTQ 4-bit
AWQ 4-bit
GGUF Q4

这里的:

4 − b i t \boxed{4-bit} 4bit

到底意味着什么?

为什么从: F P 16 FP16 FP16 降低到:

I N T 4 INT4 INT4

以后,模型可以一下子变得这么小?

为什么 4-bit 只有: 2 4 = 16 2^4=16 24=16 种状态,却还能保存一个拥有几十亿参数的大语言模型?

更重要的是:

为什么量化到如此低的精度以后,模型还能够正常工作?

本章就从这些最基础的问题开始,一步一步把:

4 − b i t \boxed{4-bit} 4bit

真正讲明白。


4.1 4-bit 让模型“小这么多”的原理

先从一个最简单的问题开始:

一个参数到底需要多少空间?

假设一个模型有: N N N 个参数。

如果每个参数使用: b b b 个 bit。

那么仅仅从理论上看,权重存储空间就是: M e m o r y = N × b 8 Memory=N\times\frac{b}{8} Memory=N×8b 也就是:

M e m o r y ∝ B i t W i d t h \boxed{ Memory\propto BitWidth } MemoryBitWidth

这就是量化能够显著压缩模型的根本原因。


4.1.1 FP32

FP32: 32 b i t = 4 B y t e 32bit=4Byte 32bit=4Byte 如果有:

7 B 7B 7B

参数: 7 × 10 9 × 4 7\times10^9\times4 7×109×4 约等于:

28 G B 28GB 28GB

所以:

7 B   F P 32 ≈ 28 G B \boxed{ 7B\ FP32\approx28GB } 7B FP3228GB

仅仅是权重。


4.1.2 FP16

FP16: 16 b i t = 2 B y t e 16bit=2Byte 16bit=2Byte 于是:

7 B × 2 B y t e ≈ 14 G B 7B\times2Byte \approx14GB 7B×2Byte14GB

所以:

7 B   F P 16 ≈ 14 G B \boxed{ 7B\ FP16\approx14GB } 7B FP1614GB

这也是为什么很多 7B 模型使用 FP16 加载以后,显存压力会明显增加。


4.1.3 INT8

INT8: 8 b i t = 1 B y t e 8bit=1Byte 8bit=1Byte 那么:

7 B × 1 B y t e ≈ 7 G B 7B\times1Byte \approx7GB 7B×1Byte7GB

也就是:

7 B   I N T 8 ≈ 7 G B \boxed{ 7B\ INT8\approx7GB } 7B INT87GB

和 FP16 相比: 14 G B → 7 G B 14GB\rightarrow7GB 14GB7GB 理论上直接减少一半。


4.1.4 INT4

再进一步: 4 b i t = 0.5 B y t e 4bit=0.5Byte 4bit=0.5Byte 因此:

7 B × 0.5 B y t e ≈ 3.5 G B 7B\times0.5Byte \approx3.5GB 7B×0.5Byte3.5GB

所以:

7 B   I N T 4 ≈ 3.5 G B \boxed{ 7B\ INT4\approx3.5GB } 7B INT43.5GB

这就是 4-bit 最直观的价值。


4.1.5 FP16 → INT8 → INT4

现在把它们放在一起:

数据类型每参数占用7B 权重理论大小
FP324 Byte≈28 GB
FP162 Byte≈14 GB
INT81 Byte≈7 GB
INT40.5 Byte≈3.5 GB

因此: F P 16 → I N T 8 FP16\rightarrow INT8 FP16INT8 理论上:

M e m o r y ÷ 2 Memory\div2 Memory÷2

而: F P 16 → I N T 4 FP16\rightarrow INT4 FP16INT4 理论上:

M e m o r y ÷ 4 Memory\div4 Memory÷4

这就是为什么 4-bit 量化会如此受到关注。


4.1.6 但是 3.5GB ≠ 实际运行显存

如果: 7 B   I N T 4 ≈ 3.5 G B 7B\ INT4\approx3.5GB 7B INT43.5GB 并不意味着:

“运行这个模型只需要 3.5GB 显存。”

因为运行模型时还需要: K V C a c h e KVCache KVCache 以及:

A c t i v a t i o n Activation Activation

和: R u n t i m e   B u f f e r Runtime\ Buffer Runtime Buffer 所以更准确地写:

$$
\boxed{
M_{total}

M_{weight}
+
M_{KV}
+
M_{activation}
+
M_{buffer}
}
$$

因此:

M o d e l S i z e ≠ R u n t i m e M e m o r y ModelSize \neq RuntimeMemory ModelSize=RuntimeMemory

这一点在后面的实际部署章节中会越来越重要。


4.1.7 13B 模型呢?

同样计算。

FP16

13 B × 2 B y t e ≈ 26 G B 13B\times2Byte \approx26GB 13B×2Byte26GB

INT8

13 B × 1 B y t e ≈ 13 G B 13B\times1Byte \approx13GB 13B×1Byte13GB

INT4

13 B × 0.5 B y t e ≈ 6.5 G B 13B\times0.5Byte \approx6.5GB 13B×0.5Byte6.5GB

所以:

模型FP16INT8INT4
7B≈14 GB≈7 GB≈3.5 GB
13B≈26 GB≈13 GB≈6.5 GB

注意:

这里仍然只是权重理论值。


4.1.8 70B 模型呢?

这时候差别会更加明显。

FP16

70 B × 2 B y t e ≈ 140 G B 70B\times2Byte \approx140GB 70B×2Byte140GB

INT8

70 B × 1 B y t e ≈ 70 G B 70B\times1Byte \approx70GB 70B×1Byte70GB

INT4

70 B × 0.5 B y t e ≈ 35 G B 70B\times0.5Byte \approx35GB 70B×0.5Byte35GB

因此:

模型FP16INT8INT4
70B≈140 GB≈70 GB≈35 GB

这就出现一个非常有意义的结果:

一个 FP16 需要大约 140GB 权重存储的模型,理论上使用 4-bit 后可以降到大约 35GB。

也就是说:

140 G B → 35 G B \boxed{ 140GB\rightarrow35GB } 140GB35GB

这就是低比特量化对大模型部署最大的吸引力之一。


4.1.9 4-bit 真的是“模型缩小 4 倍”吗?

如果比较: F P 16 FP16 FP16 和:

I N T 4 INT4 INT4

理论上: 16 4 = 4 \frac{16}{4}=4 416=4 所以可以说:

权重存储理论上缩小约 4 倍。

但实际文件一般不会恰好: 4.00 × 4.00\times 4.00× 因为还需要保存:

Scale
Zero Point
Group Metadata
Tensor Metadata
Alignment

等等辅助信息。

所以实际结果通常是:

接近 4 倍,而不是严格 4 倍 \boxed{ 接近4倍,而不是严格4倍 } 接近4倍,而不是严格4


4.2 INT4 的基本表示

现在进入本章第二个核心问题:

4-bit 到底能表示多少个数?

答案: 2 4 = 16 2^4=16 24=16 也就是说:

4 b i t = 16   s t a t e s \boxed{ 4bit=16\ states } 4bit=16 states


4.2.1 只有 16 个状态的由来

一个 bit 只有:

0
1

所以: 2 1 = 2 2^1=2 21=2 两个 bit:

2 2 = 4 2^2=4 22=4

三个 bit: 2 3 = 8 2^3=8 23=8 四个 bit:

2 4 = 16 2^4=16 24=16

因此:

4 b i t → 16   p o s s i b l e   c o d e s \boxed{ 4bit\rightarrow16\ possible\ codes } 4bit16 possible codes


4.2.2 如果是无符号 INT4

一种简单的理解是: 0 ∼ 15 0\sim15 015 一共:

16 16 16

个状态。

例如:

0
1
2
3
...
15

4.2.3 如果是有符号 INT4

如果采用有符号表示,可以理解成一个有限的正负整数范围。

例如常见的对称量化思路可以把量化结果映射到一个以零附近为中心的离散区间。

重点不是记住某一个具体端点,而是理解:

原始浮点数的连续空间,被压缩成了很少的离散等级。


4.2.4 连续空间 → 16 个量化点

假设原来的权重范围: [ − 1 , 1 ] [-1,1] [1,1] 现在只有 16 个等级。

那么我们可以想象:

-1.0 ───────────────────────── +1.0

     ↓ 量化

●──●──●──●──●──●──●──●──●──●──●──●──●──●──●──●

原来:

任意浮点值都可以出现。

现在:

只能选择附近的某一个离散点。


4.2.5 量化到底损失了什么?

假设: x = 0.73 x=0.73 x=0.73 经过 4-bit 量化以后,可能只能表示成:

0.67 0.67 0.67

或者: 0.73 → 0.75 0.73\rightarrow0.75 0.730.75 于是产生:

E r r o r = x − x ^ Error=x-\hat x Error=xx^

例如: E r r o r = 0.73 − 0.75 = − 0.02 Error=0.73-0.75=-0.02 Error=0.730.75=0.02 这就是:

Q u a n t i z a t i o n   E r r o r \boxed{ Quantization\ Error } Quantization Error


4.2.6 Scale 的作用

我们在第2章已经学习过: x q = r o u n d ( x / s ) x_q=round(x/s) xq=round(x/s) 其中:

s s s

就是 Scale。

再通过: x ^ = s x q \hat x=sx_q x^=sxq 恢复到浮点空间。

所以:

FP Value

除以 Scale

Round

INT4

乘以 Scale

Approximate FP Value

完整写成:

x → x q → x ^ x \rightarrow x_q \rightarrow \hat x xxqx^


4.2.7 不能直接把 0.73 变成一个 4-bit 数

因为: 0.73 0.73 0.73 本身是一个连续浮点数。

而 INT4 只能表示: 16 16 16 个离散状态。

所以必须建立一个映射:

C o n t i n u o u s   R a n g e → 16   d i s c r e t e   l e v e l s \boxed{ Continuous\ Range \rightarrow 16\ discrete\ levels } Continuous Range16 discrete levels

Scale 就是这个映射中的关键参数。


4.2.8 一个简单的 4-bit 例子

假设: x ∈ [ − 1 , 1 ] x\in[-1,1] x[1,1] 把它划分成 16 个离散等级。

可以粗略想象:

-1.00
-0.87
-0.73
-0.60
-0.47
...
 0.47
 0.60
 0.73
 0.87
 1.00

真实量化器的具体离散点会根据:

  • 对称/非对称
  • Scale
  • Zero Point
  • Quantization Scheme

而不同。

但基本思想不变:

把连续空间切成有限数量的格子。


4.2.9 这就产生了一个重要问题

如果所有参数都使用:

同一个 Scale

会怎么样?

假设整个 Layer 中:

99% 参数
范围:[-0.5, 0.5]

1% 参数
范围:[-20, 20]

如果 Scale 为了覆盖: [ − 20 , 20 ] [-20,20] [20,20] 那么大量普通参数就会被压缩得非常粗糙。

因此:

不是所有权重都应该简单地共用一个 Scale。


4.2.10 Group Size

这就是:

G r o u p − w i s e   Q u a n t i z a t i o n \boxed{ Group-wise\ Quantization } Groupwise Quantization

的思想。

例如:

1000 个权重

不要:

1000 个权重

1 个 Scale

而是:

1000 个权重

分成若干 Group

每个 Group 一个 Scale

例如:

Group 1 → Scale 1
Group 2 → Scale 2
Group 3 → Scale 3
...

4.2.11 Group Size 越小通常越灵活的原因

假设:

Group Size = 128

那么: 128 128 128 个权重共享一个 Scale。

如果:

Group Size = 32

那么: 32 32 32 个权重共享一个 Scale。

显然: 32 32 32 个数值的分布更容易接近。

所以:

S m a l l e r   G r o u p → M o r e   L o c a l   S c a l e s → U s u a l l y   L e s s   Q u a n t i z a t i o n   E r r o r \boxed{ Smaller\ Group \rightarrow More\ Local\ Scales \rightarrow Usually\ Less\ Quantization\ Error } Smaller GroupMore Local ScalesUsually Less Quantization Error

但是代价是: M o r e   M e t a d a t a More\ Metadata More Metadata 也就是:

更好的精度可能换来更多额外存储和实现复杂度。


4.2.12 Group Size 是一个重要的工程权衡

可以理解成:

Group Size 小

Scale 多

适应能力强

但额外开销大

Group Size 大

Scale 少

额外开销小

但适应能力弱

所以:

$$
\boxed{
Group\ Size

Accuracy
\ vs
Overhead
}
$$

这也是后面 GPTQ/AWQ 等 4-bit 方法中经常出现:

group_size = 128

等参数的原因。


4.3 低到 4-bit 仍然可以工作的原因

现在来到本章最核心的问题。

已经知道: 4 b i t = 16   s t a t e s 4bit=16\ states 4bit=16 states 这看起来非常粗糙。

那么:

一个拥有几十亿参数的大模型,把权重压到 4-bit 后仍然可以正常工作。

这背后的原因不是:

“因为 4-bit 足够精确。”

实际上:

4-bit 一点也不精确。

它之所以仍然有效,是因为神经网络本身具有很强的:

R e d u n d a n c y \boxed{Redundancy} Redundancy

也就是:

一定程度的冗余性和容错能力。


4.3.1 第一:LLM 权重并不是完全随机的

神经网络中的权重通常不是:

[-1000000, 1000000]

这样毫无规律地分布。

很多参数会集中在一个相对有限的范围内。

可以想象:

                         *
                     *   * *
                 ** ******* **
              *******************
          **************************
------------------------------------------→ Weight

即:

大部分权重集中在中心区域,少量值可能更大。

因此,如果合理设计量化区间:

可以使用有限的离散等级描述大部分权重。


4.3.2 第二:神经网络具有冗余性

假设一个模型有: 7 B 7B 7B 个参数。

并不是说:

每一个参数都承担完全独立、不可替代的功能。

神经网络通常具有一定冗余性。

可以简单理解成:

很多参数

共同完成某种表示

所以其中某些参数发生: Δ w \Delta w Δw 并不一定导致输出发生灾难性变化。

这给量化留下了空间。


4.3.3 量化误差不一定会被无限放大

设: W W W 量化为:

W ^ = W + Δ W \hat W=W+\Delta W W^=W+ΔW

原始计算: Y = W X Y=WX Y=WX 量化后:

Y ^ = W ^ X \hat Y=\hat WX Y^=W^X

所以:

$$
\hat Y

(W+\Delta W)X
$$

于是:

$$
\hat Y-Y

\Delta W X
$$

因此输出误差由: Δ W \Delta W ΔW 和输入:

X X X

共同决定。

只要量化误差在合理范围内:

最终输出不一定发生巨大变化。


4.3.4 第三:Transformer 有大量参数协同工作

一个 Transformer Block 并不是:

一个参数

直接决定最终答案

而是:

Embedding

Attention

Residual

Normalization

FFN

Residual

... 很多层

最终输出

所以一个单独的权重出现微小变化: w → w + ϵ w\rightarrow w+\epsilon ww+ϵ 通常不会直接等价于:

“模型突然不会回答问题了。”

这也是低比特量化能够工作的一个重要原因。


4.3.5 但是不是所有权重都同样重要?

不是。

这点非常重要。

有些参数变化: Δ w \Delta w Δw 可能对模型输出影响很小。

但另一些参数可能: Δ w \Delta w Δw 就会导致比较明显的变化。

所以实际的 4-bit 量化研究中才会出现:

“如何保护重要权重?”

这也是后面 AWQ 等算法需要重点解决的问题。

注意:

本章只理解这个问题,不提前进入 AWQ。


4.3.6 4-bit 的真正逻辑不是“4-bit 很精确”

而是:

4 − b i t 虽然粗糙 → 但模型允许一定程度的误差 \boxed{ 4-bit虽然粗糙 \rightarrow 但模型允许一定程度的误差 } 4bit虽然粗糙但模型允许一定程度的误差

进一步:

量化方案足够好 → 误差可以控制 \boxed{ 量化方案足够好 \rightarrow 误差可以控制 } 量化方案足够好误差可以控制

最终:

模型仍然可以工作 \boxed{ 模型仍然可以工作 } 模型仍然可以工作


4.3.7 Quantization ≠ Pruning

这里要避免一个常见误解:“权重有冗余"不等于"可以随便删权重”

4-bit 量化并不是删掉 75% 的参数,而是仍然保存全部参数,只是用更低精度的数值表示它们。例如 0.7321 0.7321 0.7321 变成 0.7 0.7 0.7——参数还在原来的位置,只是记录得更"粗"。这和 Pruning(剪枝)是完全不同的两件事:

Pruning

0.7321 → 删除(参数被移除 / 变稀疏)

Quantization

0.7321 → 0.7(参数还在,精度降低)

Q u a n t i z a t i o n ≠ P r u n i n g \boxed{ Quantization \neq Pruning } Quantization=Pruning

可以这样理解量化的直觉:原始模型说"这个参数是 0.731482",4-bit 模型说"这个参数大约在 0.7 这一档"。单个参数的信息确实明显减少,但几十亿参数放在一起时,整体仍能保留大量有价值的结构信息——这就是 4-bit 能工作的根本原因。


4.4 W4A16 到底是什么?

现在我们经常看到:

W 4 A 16 \boxed{W4A16} W4A16

这个名字一眼看起来很专业,实际上非常简单。

把它拆开: W 4 A 16 W4A16 W4A16 其中:

W = W e i g h t W=Weight W=Weight A = A c t i v a t i o n A=Activation A=Activation 所以:

$$
\boxed{
W4A16

Weight\ 4-bit
+
Activation\ 16-bit
}
$$


4.4.1 W4A16

也就是:

Activation

16-bit

Weight

4-bit

因此:

W e i g h t = I N T 4 \boxed{ Weight=INT4 } Weight=INT4

而:

A c t i v a t i o n = F P 16 / B F 16 \boxed{ Activation=FP16/BF16 } Activation=FP16/BF16

这里的“16”通常表示 16-bit 浮点计算,如 FP16 或 BF16,而不是必须存在一种名为“A16”的数据类型。


4.4.2 Weight 可以 4-bit 的原因

因为 Weight: W W W 在推理过程中是固定的。

模型加载以后:

W

不会随着每个输入发生变化。

因此:

可以提前把 Weight 量化。


4.4.3 Activation 保留 16-bit 的原因

因为 Activation: A A A 取决于输入:

X X X

也就是说: A = f ( X , W ) A=f(X,W) A=f(X,W) 换一个 Prompt:

X 1 X_1 X1

可能得到: A 1 A_1 A1 另一个 Prompt:

X 2 X_2 X2

则: A 2 A_2 A2 所以:

A c t i v a t i o n   i s   i n p u t   d e p e n d e n t \boxed{ Activation\ is\ input\ dependent } Activation is input dependent

它的分布比固定 Weight 更难提前处理。


4.4.4 W4A16 的直观计算过程

假设: Y = W X Y=WX Y=WX W4A16 可以理解为:

Weight INT4

反量化/转换

FP16/BF16

Activation FP16/BF16

Matrix Multiply

Y

所以:

Weight 使用低比特存储,Activation 仍保持较高精度。


4.4.5 这种方式流行的原因

因为它刚好解决了两个问题:

第一

Weight 占模型绝大部分存储。

因此: W 4 W4 W4 能够大幅减少:

M e m o r y Memory Memory


第二

Activation 不量化到 4-bit。

因此:

可以减少部分 Activation 量化带来的精度风险。

于是形成:

W 4 A 16 \boxed{ W4A16 } W4A16

这样的折中方案。


4.4.6 W4A16 本质上是一种“折中”

它不是:

“所有东西都 4-bit。”

而是:

Weight
→ 4-bit
→ 极力压缩

Activation
→ 16-bit
→ 保持较高精度

所以:

M e m o r y   E f f i c i e n t + R e l a t i v e l y   S t a b l e \boxed{ Memory\ Efficient + Relatively\ Stable } Memory Efficient+Relatively Stable


4.4.7 W8A16 又是什么?

同理:

W 8 A 16 \boxed{ W8A16 } W8A16

就是:

Weight
→ INT8

Activation
→ FP16/BF16

而: W 4 A 16 W4A16 W4A16 进一步把 Weight 从 8-bit 降到了 4-bit。

所以:

W8A16

Weight 8-bit

W4A16

Weight 4-bit


4.4.8 W8A8 又是什么?

继续:

W 8 A 8 \boxed{ W8A8 } W8A8

表示:

Weight     → 8-bit
Activation → 8-bit

于是:

W8A16
= Weight 8 + Activation 16

W4A16
= Weight 4 + Activation 16

W8A8
= Weight 8 + Activation 8

这样我们就可以从名称直接判断:

哪个部分被量化了。


4.4.9 一张表看懂

方案WeightActivation主要特点
FP1616-bit16-bit高精度基线
W8A168-bit16-bit主要压缩 Weight
W4A164-bit16-bit强力压缩 Weight
W8A88-bit8-bitWeight + Activation 都量化

4.4.10 W4A16 特别适合 LLM 推理的原因

LLM 推理中的一个重要问题是:

模型权重非常大。

例如: 7 B 7B 7B 模型。

FP16: 14 G B 14GB 14GB 如果变成:

W 4 W4 W4

理论上约: 3.5 G B 3.5GB 3.5GB 因此:

W e i g h t   M e m o r y ↓ Weight\ Memory \downarrow Weight Memory

同时: A c t i v a t i o n Activation Activation 仍然保持:

F P 16 / B F 16 FP16/BF16 FP16/BF16

所以可以获得一个很好的折中:

4-bit Weight
+
16-bit Activation

4.4.11 W4A16 是不是意味着 GPU 全程执行 INT4?

不是。

这是另一个非常常见的误解。 W 4 A 16 W4A16 W4A16 主要描述:

权重和激活的表示/计算精度配置。

实际 Runtime 怎样执行还取决于:

  • Hardware
  • Kernel
  • Dequantization
  • Accumulation
  • Backend

所以:

“Weight 是 4-bit”不等于“整个矩阵乘法从头到尾都是纯 INT4 数学”。

不同硬件和 Runtime 可以采用不同的实现方式。


4.4.12 “4-bit”不等于“速度一定 4 倍”

例如:

INT4

读取 INT4 Weight

Dequantize / unpack

参与计算

FP16

读取 FP16 Weight

因此: M e m o r y   T r a f f i c Memory\ Traffic Memory Traffic 可能显著减少,但:

C o m p u t a t i o n Computation Computation

并不会简单变成原来的: 1 4 \frac14 41 所以:

4 b i t   C o m p r e s s i o n ≠ 4 × S p e e d u p \boxed{ 4bit\ Compression \neq 4\times Speedup } 4bit Compression=4×Speedup


4.4.13 4-bit 的第一个真正价值是什么?

如果只记一个:

M e m o r y \boxed{ Memory } Memory

例如: F P 16 → I N T 4 FP16\rightarrow INT4 FP16INT4 权重理论上:

14 G B → 3.5 G B 14GB\rightarrow3.5GB 14GB3.5GB

于是:

原来需要很大显存的模型,现在可能进入更小的设备。

所以量化首先解决:

M o d e l   F i t \boxed{ Model\ Fit } Model Fit


4.4.14 第二个价值:Memory Bandwidth

GPU 推理中:

模型权重需要不断从显存层级读取。

如果 Weight 从: 16 b i t 16bit 16bit 变成:

4 b i t 4bit 4bit

那么理论上需要搬运的数据量大幅下降。

因此: M e m o r y   T r a f f i c ↓ Memory\ Traffic\downarrow Memory Traffic 这在某些 LLM Decode 场景下尤其重要。


4.4.15 第三个价值:成本

如果模型太大:

需要 4 张 GPU

量化以后可能:

只需要 2 张 GPU

那么量化带来的已经不只是:

“模型小了。”

而是:

I n f r a s t r u c t u r e   C o s t ↓ \boxed{ Infrastructure\ Cost\downarrow } Infrastructure Cost


4.5 第一次真实 4-bit 推理

现在进入本章最后一个部分。

理论已经知道:

FP16
→ 大

INT8
→ 小

INT4
→ 更小

那么:

实际跑起来到底有什么差别?

我们做一个非常简单的实验。


4.5.1 实验目标

比较:

FP16
INT8
INT4

观察:

1. Model Size
2. Memory
3. Load Time
4. Tokens/s
5. Output Quality

本章目录也正是按照这一组指标设计第一次真实 4-bit 推理。


4.5.2 实验环境

建议:

Python
PyTorch
Transformers
CUDA GPU

例如:

python --version

然后:

python -c "import torch; print(torch.__version__)"

例如本节实验所用的环境为:

Python 3.12.3
torch 2.7.0+cu126        # PyTorch 2.7.0 + CUDA 12.6

检查 GPU:

nvidia-smi

本节实验所用的 GPU:

GPU: NVIDIA RTX 4090 (24GB)   # Driver 575.51.03, CUDA 12.9

4.5.3 三档实验:可直接运行的完整代码

为了方便你动手复现,本节把整个实验整理成三段可直接复制运行的代码。三段共用同一个模型、同一个 prompt,只改变精度,最后对比资源与输出。

说明:三段实验使用同一个模型(默认 Qwen/Qwen2.5-7B-Instruct,需约 14GB 显存跑 FP16,RTX 4090 24GB 足够;显存不足可换 Qwen/Qwen2.5-1.5B-Instruct)。INT8 / INT4 不是去下载"别人量化好的模型",而是下载同一份 FP16 原始权重,在本地加载时即时量化

再补一点容易搞混的:bitsandbytes 的量化只发生在显存里,不会写回磁盘、也不会覆盖原始模型——磁盘上始终只有那份原始 FP16 权重,每次以 INT8/INT4 加载都会重新量化一遍,程序退出后量化结果即消失。如果想把量化后的模型存成一份新的 INT4 模型,需要用第 5 章的 GPTQ(save_pretrained() 会新建目录保存,默认也不覆盖原模型)。

第 1 步:下载模型(会缓存到默认路径)

第一次运行会把模型下载到本地默认缓存目录,之后各步直接读缓存、不再重复下载。

  • Windows 默认缓存:C:\Users\<你的用户名>\.cache\huggingface\hub
  • Linux/macOS 默认缓存:~/.cache/huggingface/hub
# ===== 第 1 步:下载模型到本地默认缓存 =====
import os
# 国内网络:走 HF 镜像(必须在 import transformers 之前设置)
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
os.environ["HF_HUB_DISABLE_XET"] = "1"   # 关闭 Xet,退回普通下载(镜像才能代理,避免 401)

from huggingface_hub import snapshot_download

MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"   # 24GB 显存(如 RTX 4090)可跑;显存不足可换 "Qwen/Qwen2.5-1.5B-Instruct"

# 下载到默认缓存目录并返回本地路径
local_path = snapshot_download(repo_id=MODEL_ID)
print("模型已下载到:", local_path)

第 2 步:本地量化前,先跑一次 FP16 答复(基准)

在做任何量化之前,先用原始 FP16 模型对同一个 prompt 生成一次答复,作为对比基准。

# ===== 第 2 步:FP16 基准(量化前) =====
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
os.environ["HF_HUB_DISABLE_XET"] = "1"   # 关闭 Xet,退回普通下载(镜像才能代理,避免 401)

import time, torch
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"

# 三组都用完全相同的 prompt(这是对比的前提)
PROMPT = "请解释什么是 Transformer,并说明 Self-Attention 的基本工作原理。"

def run_once(model, tokenizer, prompt, max_new_tokens=128):
    """跑一次生成,返回 (答复文本, tokens/s)。用贪心解码保证可复现。"""
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    if torch.cuda.is_available():
        torch.cuda.synchronize()
    t0 = time.perf_counter()
    out = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)
    if torch.cuda.is_available():
        torch.cuda.synchronize()
    dt = time.perf_counter() - t0
    new_tokens = out.shape[-1] - inputs["input_ids"].shape[-1]
    text = tokenizer.decode(out[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True)
    return text, new_tokens / dt

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

if torch.cuda.is_available():
    torch.cuda.reset_peak_memory_stats()
t0 = time.perf_counter()
model = AutoModelForCausalLM.from_pretrained(
    MODEL_ID, torch_dtype=torch.float16, device_map="auto"
)
load_time = time.perf_counter() - t0

text, tps = run_once(model, tokenizer, PROMPT)
peak = torch.cuda.max_memory_allocated() / 1024**3 if torch.cuda.is_available() else 0

print("===== FP16 =====")
print(f"加载耗时: {load_time:.1f}s | 峰值显存: {peak:.2f} GB | 速度: {tps:.1f} tokens/s")
print("答复:\n", text)

# 释放显存,给后面的量化实验腾地方
del model
if torch.cuda.is_available():
    torch.cuda.empty_cache()

在本节实验环境(RTX 4090 24GB,Qwen2.5-7B-Instruct)下,第 2 步的实际运行结果如下:

===== FP16 =====
加载耗时: 4.2s | 峰值显存: 14.21 GB | 速度: 54.0 tokens/s
答复:
  Transformer 是一种基于自注意力机制(Self-Attention)的神经网络架构,最初由 Vaswani 等人在 2017 年提出,
  主要用于自然语言处理任务,如机器翻译、文本生成等。Transformer 架构在处理序列数据时表现出色,因为它能够
  并行处理输入序列中的所有元素,从而大大提高了训练和推理的速度。

  Self-Attention 是 Transformer 中的核心组件之一,它允许模型关注输入序列中不同位置的信息。
  Self-Attention 的基本工作原理如下:

  1. 输入:给定一个长度为 N 的输入序列,每个元素可以是一个词或词向量。
  2. 查询(Query)、键(Key)和值(Value):对于序列中的每个元素,我们计算三个向量:查询向量、键向量和
     值向量。这些向量通常通过线性变换从原始输入向量得到。
  3. 计算注意力分数:对于序列中的每个元素,我们计算与其他元素之间的注意力分数。这可以通过计算查询向量与
     键向量的点积来实现,然后应用一个缩放因子和一个激活函数(如 softmax)来归一化分数。
  4. 加权求和:根据注意力分数对值向量进行加权求和,得到最终的输出向量。这个过程可以看作是将序列中不同位置
     的信息加权组合在一起。

  通过 Self-Attention,Transformer 可以有效地捕捉输入序列中的长距离依赖关系,而无需像传统的循环神经网络
  (RNN)那样依赖于顺序处理。此外,Self-Attention 还具有并行化的优势,使得 Transformer 在处理大规模序列
  数据时更加高效。

其中峰值显存 14.21 GB 与 7B 模型 FP16 理论占用(约 7 B × 2 Byte ≈ 14 GB 7\text{B}\times 2\text{Byte}\approx 14\text{GB} 7B×2Byte14GB)高度吻合,这就是后面 INT8 / INT4 两组要对比的基准线。

提示:默认 max_new_tokens=128 可能导致答复被截断;想看完整答复可调大(如 512)。但做三档对比时,三组必须用相同的 max_new_tokens,速度和质量对比才公平。

第 3 步:分批量化并各跑一次答复(INT8 / INT4)

下面用一个循环,依次以 INT8、INT4 加载同一个模型并生成答复。每一组:加载 → 记录加载时间/峰值显存 → 生成答复 → 记录 tokens/s → 释放显存,再进入下一组。

# ===== 第 3 步:分批量化 + 各跑一次答复 =====
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
os.environ["HF_HUB_DISABLE_XET"] = "1"   # 关闭 Xet,退回普通下载(镜像才能代理,避免 401)

import time, torch
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"
PROMPT = "请解释什么是 Transformer,并说明 Self-Attention 的基本工作原理。"

def run_once(model, tokenizer, prompt, max_new_tokens=128):
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    if torch.cuda.is_available():
        torch.cuda.synchronize()
    t0 = time.perf_counter()
    out = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)
    if torch.cuda.is_available():
        torch.cuda.synchronize()
    dt = time.perf_counter() - t0
    text = tokenizer.decode(out[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True)
    new_tokens = out.shape[-1] - inputs["input_ids"].shape[-1]
    return text, new_tokens / dt

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

# 两组量化配置:INT8 和 INT4
configs = {
    "INT8": BitsAndBytesConfig(load_in_8bit=True),
    "INT4": BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16),
}

results = {}
for name, quant_config in configs.items():
    if torch.cuda.is_available():
        torch.cuda.reset_peak_memory_stats()
    t0 = time.perf_counter()
    model = AutoModelForCausalLM.from_pretrained(
        MODEL_ID, quantization_config=quant_config, device_map="auto"
    )
    load_time = time.perf_counter() - t0

    text, tps = run_once(model, tokenizer, PROMPT)
    peak = torch.cuda.max_memory_allocated() / 1024**3 if torch.cuda.is_available() else 0
    results[name] = (load_time, peak, tps, text)

    print(f"===== {name} =====")
    print(f"加载耗时: {load_time:.1f}s | 峰值显存: {peak:.2f} GB | 速度: {tps:.1f} tokens/s")
    print("答复:\n", text, "\n")

    del model
    if torch.cuda.is_available():
        torch.cuda.empty_cache()

跑完这三步,你就得到了同一个模型在 FP16 / INT8 / INT4 三种精度下的:加载时间、峰值显存、生成速度,以及对同一个 prompt 的三份答复——把它们并排放在一起,就是 4.5.1 说的那组对比。

在本节实验环境(RTX 4090 24GB,Qwen2.5-7B-Instruct)下,第 3 步的实际运行结果如下:

===== INT8 =====
加载耗时: 8.6s | 峰值显存: 8.34 GB | 速度: 21.7 tokens/s
答复:
  Transformer 是一种基于注意力机制的神经网络架构,最初被用于自然语言处理任务,特别是机器翻译。它由
  Vaswani 等人在 2017 年提出,是当前许多先进 NLP 模型的基础。

  Transformer 由编码器和解码器两部分组成,其中编码器将输入序列转换为固定长度的向量表示,而解码器则根据
  这些向量生成输出序列。编码器和解码器都包含多个相同的层,每一层都包括自注意力(Self-Attention)机制、
  前馈神经网络(Feed-Forward Neural Network)以及残差连接(Residual Connection)和层归一化(Layer
  Normalization)等技术。

  Self-Attention 是 Transformer 中的核心组件之一,它的基本工作原理如下:

  1. 输入:给定一个序列,例如一个句子中的单词或字符。每个元素(如单词或字符)都有一个对应的嵌入向量。
  2. Q、K 和 V 向量:对于序列中的每个元素,我们计算三个向量:查询向量(Query, Q)、键向量(Key, K)和
     值向量(Value, V)。这些向量通常通过线性变换从原始嵌入向量中得到。
  3. 计算注意力分数:对于序列中的每个元素,我们计算与其他所有元素之间的注意力分数。这可以通过计算 Q 和 K
     向量的点积并除以根号下 K 向量维度来实现。这样可以确保分数不会过大或过小。
  4. 应用 softmax 函数:将注意力分数进行归一化,使得每个元素的总和为 1。这一步骤确保了注意力权重的合理分配。
  5. 加权求和:使用 softmax 函数得到的权重对 V 向量进行加权求和,得到最终的注意力表示。
  6. 输出:将注意力表示与原始嵌入向量相加,得到最终的注意力输出。

  通过 Self-Attention 机制,Transformer 可以在不依赖于顺序信息的情况下捕捉到序列中的长距离依赖关系。这使得
  Transformer 在处理自然语言等序列数据时具有强大的建模能力。同时,Self-Attention 机制也使得模型能够并行
  计算,从而提高了训练速度。需要注意的是,Self-Attention 仅关注序列内部的信息,因此被称为“自我”注意力。
  在实际应用中,Transformer 还会结合其他技术,
===== INT4 =====
加载耗时: 3.4s | 峰值显存: 5.57 GB | 速度: 85.1 tokens/s
答复:
  Transformer 是一种用于处理序列数据的神经网络架构,它在自然语言处理领域取得了巨大的成功。Transformer
  通过引入自注意力机制(Self-Attention)来替代传统的循环神经网络和卷积神经网络中的递归和卷积操作。

  Self-Attention 的基本工作原理如下:

  1. 输入:首先将输入序列进行嵌入表示,得到一个矩阵形式的表示。
  2. Q、K 和 V:将矩阵按照列分成三个不同的矩阵,分别称为 Query (Q)、Key (K) 和 Value (V)。
  3. 计算注意力分数:对于每个位置 i,计算它与其他所有位置 j 的注意力分数。注意力分数通常使用点积相似度
     计算,即 Q_i 和 K_j 的点积除以它们的维度平方根。
  4. 归一化:将注意力分数进行归一化,通常使用 softmax 函数。
  5. 加权求和:将归一化后的注意力分数与对应的 V 矩阵相乘,然后求和,得到最终的输出向量。

  通过 Self-Attention,Transformer 可以关注到整个序列中的任意一对元素之间的关系,而不需要像 RNN 那样依赖于
  前一个时间步的信息。此外,Self-Attention 还可以并行计算,从而提高了模型的效率。这些特性使得 Transformer
  在处理长序列时具有明显的优势。

三档对比小结

指标FP16INT8INT4
峰值显存14.21 GB8.34 GB5.57 GB
加载耗时4.2s8.6s3.4s
速度(tokens/s)54.021.785.1
输出质量完整准确完整准确准确、略简洁

从这组数据可以读出几个重要结论:

  • 显存随精度显著下降:14.2 GB → 8.3 GB → 5.6 GB,与"4-bit 约为 FP16 的 1/3 ~ 1/4"的理论完全吻合。这是量化最直接的收益。
  • 速度并不是"位数越低越慢":这里 INT8 反而最慢(21.7),INT4 反而最快(85.1,甚至超过 FP16)。原因在于 kernel 实现:bitsandbytes 的 INT8(LLM.int8())会做"离群值用 FP16、其余用 INT8"的混合精度分解,小 batch 推理时这个拆分/合并开销明显;而 INT4(NF4)用了高度优化的融合 kernel,加上显存带宽压力更小,所以最快。低比特是否更快,取决于 kernel,而不是位数本身。
  • 质量损失很小:三档答复都正确,INT4 只是表述更简洁(省略了残差/LayerNorm 等细节),核心原理无误——说明 4-bit 对这个 7B 模型几乎无损。

注:三档必须使用相同的 max_new_tokens,上面的速度对比才公平。不同硬件、不同 bitsandbytes 版本,速度数字会有差异,但"显存大幅下降、INT4 kernel 更快"这两个趋势通常一致。

提示:bitsandbytes 在 Windows 上的支持偶有问题。若第 3 步报 bitsandbytes 相关错误,可改用 GPTQ / AWQ 预量化模型(见第 5 章),或在 Linux / WSL2 环境下运行本节实验。安装:pip install -U "bitsandbytes>=0.46.1"

4.5.4 你可能看到的典型趋势

虽然具体数字需要实际测试,但通常你会观察到类似趋势:

FP16

Model Size 最大

Memory 压力最大

Quality 作为 Baseline

INT8

Model Size ↓

Memory ↓

Quality 通常接近 FP16

INT4

Model Size ↓↓↓

Memory ↓↓↓

Quality 可能出现更明显变化

注意:

这是一种理解趋势,不是固定 Benchmark 数字。


4.5.5 INT4 质量可能下降的原因

现在我们可以用本章的知识解释。

因为: 4 b i t = 16   s t a t e s 4bit=16\ states 4bit=16 states 所以:

Q u a n t i z a t i o n   E r r o r Quantization\ Error Quantization Error

通常会比: 8 b i t 8bit 8bit 更加明显。

于是:

F P 16 → I N T 8 → I N T 4 FP16 \rightarrow INT8 \rightarrow INT4 FP16INT8INT4

随着 bit 降低: Q u a n t i z a t i o n   E r r o r Quantization\ Error Quantization Error 可能增加。

不过要注意"可能"两个字——它是趋势,不是必然。回到 4.5.3 的实验:我们对 Qwen2.5-7B-Instruct 分别用 FP16 / INT8 / INT4 回答同一个关于 Transformer 的问题,三档答复都准确、无明显错误,INT4 只是表述更简洁(省略了残差、LayerNorm 等细节),核心原理并没有讲错。也就是说,对这个 7B 模型、这个任务,4-bit 带来的质量下降几乎观察不到

那"质量可能下降"体现在哪里?通常在更苛刻的场景才明显,例如:

  • 更小的模型(参数越少,冗余越少,越经不起量化误差);
  • 更依赖精确数值的任务(数学、代码、长链推理);
  • 更长的生成(误差会随着 token 逐步累积)。

所以正确的理解是:bit 降低会增大量化误差的上界,但是否表现为可感知的质量下降,取决于模型、任务和量化方法——这正好引出下一节。


4.5.6 有些 INT4 模型几乎没变化的原因

从 4.5.3 的实验也能直接感受到这一点:同样是把 7B 模型压到 4-bit,显存从 14.21 GB 降到 5.57 GB(省了约 60%),但答复质量几乎没变。为什么"位数砍到 1/4,质量却没怎么掉"?

因为量化误差并不是简单:

B i t ↓ ⇒ Q u a l i t y ↓ Bit\downarrow \Rightarrow Quality\downarrow Bit↓⇒Quality

还受到:

Scale
Group Size
Weight Distribution
Quantization Method
Calibration
Model Architecture

等因素影响。

结合本节实验看:我们用的 bitsandbytes INT4 采用 NF4 这种更贴合权重分布的量化格式,加上 7B 模型本身权重冗余较大,所以 4-bit 下质量损失很小。但换一个量化方法(比如朴素的均匀量化)、或换一个更小/更敏感的模型,同样是 4-bit,结果可能明显变差。

所以:

同样是 4-bit,不同量化方法、不同模型可能出现明显不同的效果。

这就是后面 GPTQ、AWQ 等章节存在的原因——它们通过更聪明的量化策略(如误差补偿、按重要性缩放),在同样的 4-bit 预算下把质量损失压得更低。


4.5.7 4-bit 的真正意义是什么?

现在可以回答本章标题:

LLM 4-bit 量化到底意味着什么?

它并不是简单地说:

“把模型变成 4 个 bit。”

真正含义是:

用极少的离散数值等级近似表示原来的高精度权重 \boxed{ 用极少的离散数值等级近似表示原来的高精度权重 } 用极少的离散数值等级近似表示原来的高精度权重

同时通过:

Scale
Group
Quantization Scheme

等手段尽量降低: Q u a n t i z a t i o n   E r r o r Quantization\ Error Quantization Error 最终实现:

M e m o r y   ↓ S t o r a g e   ↓ B a n d w i d t h   ↓ \boxed{ Memory\ ↓ Storage\ ↓ Bandwidth\ ↓ } Memory Storage Bandwidth 

同时尽量维持:

M o d e l   Q u a l i t y \boxed{ Model\ Quality } Model Quality


4.5.8 4-bit 不是魔法,而是一个取舍

可以把整个过程理解成:

Bit Width

Memory 更低

Quality 更好

通常: B i t W i d t h ↓ BitWidth\downarrow BitWidth 意味着:

M e m o r y ↓ Memory\downarrow Memory

但: Q u a l i t y Quality Quality 可能受到更大影响。于是出现 Memory 与 Quality 之间的基本权衡:

M e m o r y ↔ Q u a l i t y \boxed{ Memory \leftrightarrow Quality } MemoryQuality

而 4-bit 恰好落在这个权衡里一个很有吸引力的位置: F P 16 → I N T 8 FP16 \rightarrow INT8 FP16INT8 已能显著减少显存, I N T 8 → I N T 4 INT8 \rightarrow INT4 INT8INT4 又进一步减半,在 Memory、Quality、Speed 之间形成了一个平衡区域。

FP16

INT8

INT4

所以 4-bit 之所以重要,不是因为它"理论上完美",而是因为它在工程上非常有价值


4.5.9 但是不同 4-bit 方案不能混为一谈

这一点从本章开始就需要建立。

后面我们会看到:

INT4
GPTQ-4bit
AWQ-4bit
NF4
GGUF-Q4
FP4

这些名字都可能带: 4 b i t 4bit 4bit 但它们:

不是完全相同的技术。

所以看到:

4-bit

以后还应该继续问:

什么 4-bit?
怎么量化?
怎么分组?
怎么存?
怎么计算?
哪个 Runtime?

4.5.10 本章与后面章节的关系

现在可以把后面的学习路线理解得更加自然:

第4章 4-bit 是什么?
我们知道了问题

第5章 GPTQ
如何更聪明地解决问题?

第6章 AWQ
如何保护更重要的权重?

第7章 NF4 / QLoRA
为什么还有另一种 4-bit 表示?

第8章 Evaluation
怎么判断量化到底好不好?

第9章 GGUF
怎么把量化模型保存和运行?

第10章 Jetson
怎么放进边缘设备?

第11章 TensorRT-LLM
怎么让 NVIDIA GPU 跑得更快?

第12章 QAT
PTQ 不够准怎么办?

这样每一章都在回答一个新的问题,而不是重复介绍“量化”。


4.5.11 本章核心代码实验

可以把整个第4章实验浓缩成下面三个模型:

同一个 7B 模型

FP16

INT8

INT4

统一测试:

Model Size
VRAM
Load Time
Tokens/s
Output Quality

最终得到:

results.csv

这张表会成为后面第13章综合 Benchmark 的基础。


4.6 本章小结

这一章我们没有学习复杂的 GPTQ,也没有学习 AWQ,更没有进入 QAT。

我们只做了一件非常重要的事情:

把“4-bit”真正理解清楚。

现在我们知道:

4 b i t = 16   d i s c r e t e   s t a t e s \boxed{ 4bit=16\ discrete\ states } 4bit=16 discrete states

它意味着:

原来的连续高精度权重,被映射到有限的离散数值等级。


4.6.1 4-bit 让模型变小的原理

因为:

$$
Memory

Parameters\times
\frac{Bits}{8}
$$

例如: 7 B   F P 16 ≈ 14 G B 7B\ FP16\approx14GB 7B FP1614GB 而:

7 B   I N T 4 ≈ 3.5 G B 7B\ INT4\approx3.5GB 7B INT43.5GB

理论上降低约: 4 × 4\times 4× 权重存储。


4.6.2 4-bit 仍能工作的原因

因为:

LLM 权重具有一定结构
+
模型存在冗余性
+
合理量化可以控制误差
+
不是每一个权重都同等敏感

因此:

L o w   P r e c i s i o n ≠ N o   I n f o r m a t i o n \boxed{ Low\ Precision \neq No\ Information } Low Precision=No Information

4-bit 虽然丢失了很多精度,但仍然可以保留足够的有效信息。


4.6.3 W4A16 是什么?

$$
\boxed{
W4A16

4-bit\ Weight
+
16-bit\ Activation
}
$$

核心思想:

Weight
→ 强力压缩

Activation
→ 保持较高精度

所以它是一个非常重要的:

M e m o r y ↔ Q u a l i t y \boxed{ Memory \leftrightarrow Quality } MemoryQuality

折中。


4.6.4 最重要的几个概念

4-bit

16 个离散状态

Scale

控制量化范围

Group Size

控制局部量化粒度

W4A16

Weight 4-bit / Activation 16-bit

Quantization Error

低 bit 带来的核心代价


4.6.6 从本章进入第5章

现在我们已经知道:

4-bit 有巨大的价值,但也有明显的量化误差。

于是下一个问题自然产生:

如果只是简单地 round(),4-bit 精度可能损失比较大,那么有没有一种更加聪明的方法,让 4-bit 尽可能接近原始 FP16 模型?

答案就是:

G P T Q \boxed{ GPTQ } GPTQ

下一章我们将从:

“简单 R o u n d ” \boxed{ “简单 Round” } 简单Round

开始,逐步理解:

“误差最小化” \boxed{ “误差最小化” } 误差最小化

最后回答:

GPTQ 为什么不是简单地把每一个 Weight Round 一下,而是要利用 Hessian、Layer Reconstruction 和 Error Compensation?

这也正是从“理解 4-bit”进入“理解真正的 LLM 4-bit 量化算法”的关键一步。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值