从 Smooth Quant 到 SVD Quant
最近在尝试给公司的 DiT 生图模型做推理加速的过程中,了解到 SVDQuant 这种较新的扩散模型量化方案,在此记录一下学习心得。
首先需要明确的是,LLM 由于瓶颈通常在于 decode 部分的权重搬运,所以只量化权重就能拿到性能收益;但 diffusion model 往往是 compute bound,想加速是绕不开激活量化的,同时对权重和激活进行量化会带来很多精度挑战。
Smooth Quant(W8A8)
Smooth Quant 可以看作是 SVDQuant 的科技树前置,它本身是对静态量化方案的一种改进。
W8A8 面临的主要问题是激活的 outlier 带来的精度损失,一个离群值会导致 block 内的其他正常值全部被映射到 zero point 附近,从而失去彼此之间的差异。Smooth Quant 的提出者统计了激活的 outlier 分布,他们发现离群值的分布并不是随机的,而是固定在少数几个 channel 中:
基于这一现象,他们进一步提出,可以给激活的每个 channel 寻找一个缩放因子,然后通过下面的运算把 outlier 带来的影响转移到权重中:
其中第 j 个 channel 的缩放因子通过下面的公式计算得到:
$\alpha$ 是一个超参,用来分配 W 和 A 之间的量化难度,论文中提到:
$\alpha=0.5$ is a general sweet spot for all the OPT and BLOOM models, and $\alpha=0.75$ for GLM-130B since its activations are more difficult to quantize.
SVDQuant(W4A4)
Smooth Quant 本质是把激活的 outlier 影响部分转移到权重侧承担,这种方案在 W8A8 的场景下被证实是有效的。
当量化推进到 4 bit 领域后,权重和激活的表示范围都只有 16 个值,此时权重也无法再承担激活的 outlier,于是 Smooth Quant 的提出者另辟蹊径,又提出了基于 SVD 分解的量化方案。
SVD 分解
SVD(Singular Value Decomposition,奇异值分解)本身是线性代数中的一种运算。我们知道任意矩阵 $A\in\mathbb{R}^{M\times N}$ 都可以写成如下形式:
其中:
- $U\in\mathbb{R}^{M\times M}$ 是 $AA^T$ 的特征向量构成的正交矩阵;
- $V\in\mathbb{R}^{N\times N}$ 是 $A^TA$ 的特征向量构成的正交矩阵;
- $\Sigma\in\mathbb{R}^{M\times N}$ 对角线上的元素称为奇异值,从大到小排列,其余元素为 0。奇异值是 $AA^T$ 特征值的平方根;
SVD 分解本质上是在说:一个线性变换 $A$ 可以被看作是在输入空间上的一组标准正交基 $V$ 的各个方向上做了一些缩放,然后再旋转到另一组输出空间上的标准正交基 $U$ 的方向上。由于 $A^TA$ 的特征向量 $v_i$ 满足
所以 $V$ 就是这样一组经过 $A$ 变换后依然正交的基。与此同时:
所以 $Av_i$ 是 $AA^T$ 的特征向量。这表明 $V$ 经过 $A$ 变换后得到的正交基和 $U$ 的方向正是一致的。考虑一个输入向量 $x\in\mathbb{R}^N$,SVD 下整个线性变换的计算流程为:
- 分解:$V^Tx$ 求的是 $x$ 在 $V$ 这组正交基下的坐标表示;
- 缩放:$\Sigma V^Tx$ 则是把上述坐标分别进行缩放,表示在基底各方向上的调制;
- 合成:$U\Sigma V^Tx$ 中的 $U$ 也是正交基,所以这里的左乘表示将调制后的坐标旋转到目标基底的方向;
量化方案
还是基于前面提到的经验事实:激活的 outlier 会集中分布在几个 channel 中。
SVDQuant 的第一步是利用 Smooth Quant 中的方案将激活的 outlier 全部抹平到权重,这会让激活变得更易于量化,但会让权重中的特定列被明显放大。
接下来对已乘上 smooth factor 的权重做 SVD 分解。由于权重的特定列被放大,所以离群值会满足低秩结构,即离群值更集中于奇异值最大的前若干个 rank 中。此时对权重做 SVD 截断将其分为低秩分支(论文中默认截断前 32 个 rank)和残差:
假设 $W$ 的维度是
[hidden_size, hidden_size],那么 $L_1$ 的维度是[hidden_size, 32],$L_2$ 的维度是[32, hidden_size],对应前 32 个最大的奇异值。
由于整列离群值更多被保留在高精度的低秩分支,残差 $R$ 中的 outlier 会更少、更小,而这正是量化最关心的问题。因此,对残差做 4 bit 量化,而低秩分支保持 16 bit 比直接量化权重整体的误差更小。
从下图中可以看到,经过处理的激活和残差中 outlier 都明显变少、变小,利于量化:
再来看看量化后具体的计算方式,假设是 PTQ 方案:
- 静态量化:量化权重用到的 scale、smoothing factor、low-rank branch 都可以在离线校准阶段写入产物,不随推理过程更新;
- 动态量化:量化激活所需的 scale 一般是 per-tensor 在线计算;
- kernel fusion:low-rank branch 的参数量很小,但如果要和残差分开计算求和会导致 bf16 精度的激活需要反复从 HBM load,所以 nunchaku 的实现中是把 low-rank 和残差的计算做了 kernel fusion。
个人见解
我认为 svdquant 的收益来源主要有两点,且都是 smooth 带来的:
- smooth 给权重带来的按列分布的离群值,在 SVD 分解后集中于低秩分支;
- smooth 导致权重 SVD 分解后的残差有更低的能量占比,导致更低的量化底噪;
对于 INT4 这种 group 128 甚至 per tensor 的量化方案,smooth 能让激活和权重产生很大的变化。但在 nvfp4 这种 group 16 的两级 scale 方案中,smooth 能产生的影响是非常有限的,这会导致权重的离群值不能随低秩分支被剥离,且权重的奇异值谱不够陡峭,低秩分支的能量占比较低,二者叠加会导致 nvfp4 的 svdquant 收益相比裸的 nvfp4 并没有非常大的提升。
在我的实际测试中,nvfp4 下 svdquant 的相对误差收益可能在 1.16-3 倍不等,而且主要取决于上述原因中的第二点,即收益明显跟 F-32 的能量占比强相关。
总结
Smooth Quant 和 SVD Quant 都是面向激活量化的算法,而激活量化本身对于 compute bound 的模型来说是非常重要的一环。这两个量化算法对 INT4 而言应该说算是必备方案,不过在 nvfp4 已经成熟的今天,svdquant 这个方案的误差收益和推理效率可能还需要更充分的权衡。