LoRA

LoRA (Low-Rank Adaptation): 保留原来的权重, 只学习一个由两个小矩阵表示的更新量.

令 y=W0xy = W_0x. Fine-tuning (FT) 时, 将权重 W0W_0 更新为 W0+ΔWW_0 + \Delta W, 其中:

ΔW=sBA.\Delta W = sBA.

各矩阵的维度为:

W0∈Rdout×din,B∈Rdout×r,A∈Rr×din.W_0 \in \mathbb{R}^{d_{\mathrm{out}} \times d_{\mathrm{in}}}, \qquad B \in \mathbb{R}^{d_{\mathrm{out}} \times r}, \qquad A \in \mathbb{R}^{r \times d_{\mathrm{in}}}.

r≪dout,dinr \ll d_{\mathrm{out}}, d_{\mathrm{in}}, 因而大大减少需要更新的参数量.

y2=(W0+ΔW)x=W0x+sB(Ax).y_2 = (W_0 + \Delta W)x = W_0x + sB(Ax).

其中 W0W_0 固定, FT 时实际更新的参数是 A,BA, B.

对于序列输入 x∈Rdin×dseqx \in \mathbb{R}^{d_{\mathrm{in}} \times d_{\mathrm{seq}}}:

Ax∈Rr×dseq.Ax \in \mathbb{R}^{r \times d_{\mathrm{seq}}}.

rank 的证明

rank⁡(BA)≤min⁡{rank⁡(A),rank⁡(B)}≤r.\operatorname{rank}(BA) \leq \min\{\operatorname{rank}(A), \operatorname{rank}(B)\} \leq r.

把 AA 的列向量记为 a1,a2,…,ana_1, a_2, \ldots, a_n, 则:

BA=[Ba1,Ba2,…,Ban].BA = [Ba_1, Ba_2, \ldots, Ba_n].

BABA 的每一列都是 BB 的列向量的线性组合, 因而:

rank⁡(BA)≤rank⁡(B).\operatorname{rank}(BA) \leq \operatorname{rank}(B).

对应地, 从行空间也可得到 rank⁡(BA)≤rank⁡(A)\operatorname{rank}(BA) \leq \operatorname{rank}(A).

例子: LoRA 生图模型

冻结 Foundation Model 的 W0W_0, 用特定画风的 dataset 训练一组 A,BA, B:

Y=W0X+sB(AX).Y = W_0X + sB(AX).

这样可以用较低成本适配不同画风. 示意图见下方手写原稿.

类似思路: DeepSeek 的 MLA.

QLoRA

1. NF4

4-bit weight→dequantBF16 approximate weight→GEMMoutput.\text{4-bit weight} \xrightarrow{\mathrm{dequant}} \text{BF16 approximate weight} \xrightarrow{\mathrm{GEMM}} \text{output}.

4-bit 可以表示 24=162^4 = 16 个数据点. 如何分布这 16 个点? 如果零附近数据多, 两端数据少, 就可以考虑 Quantile Quantization (QQ).

Gaussian 假设与分位数

假设权重分布为:

W∼N(0,σ2).W \sim \mathcal{N}(0, \sigma^2).

令 Z∼N(0,1)Z \sim \mathcal{N}(0, 1), 则分位数满足:

QW(p)=σQZ(p).Q_W(p) = \sigma Q_Z(p).

QZ(⋅)Q_Z(\cdot) 表示标准正态分布的分位数函数: 给定分位 pp, 返回对应的随机变量取值.

在 CDF 的概率轴上等分, 映射到数值轴后, 零附近的区间更窄, 两端的区间更宽. 原稿中的 CDF 图画的就是这个关系.

分位数采样与端点问题

一个直观的构造是:

q~i=QZ ⁣(i2k).\widetilde q_i = Q_Z\!\left(\frac{i}{2^k}\right).

但要避开两个端点:

QZ(0)=−∞,QZ(1)=+∞.Q_Z(0) = -\infty, \qquad Q_Z(1) = +\infty.

因此, 对单个分位数样点, 可以考虑用 2k+12^k + 1 作分母, 取 i=1,…,16i = 1, \ldots, 16.

原文中的形式则是:

qi=12[QZ ⁣(i2k+1)+QZ ⁣(i+12k+1)].q_i = \frac{1}{2}\left[ Q_Z\!\left(\frac{i}{2^k + 1}\right) + Q_Z\!\left(\frac{i + 1}{2^k + 1}\right) \right].

这里仍有一个疑问: 如果采样包含 i=0i = 0, 或包含使 (i+1)/(2k+1)=1(i + 1)/(2^k + 1) = 1 的端点, 仍然会遇到无穷值. 原文的采样索引与端点该怎样处理?

这个式子是在用区间端点的均值代替区间内的值, 而且均值取在随机变量的数值空间, 并非分位数的概率空间.

量化还有一个要求: 0→00 \to 0, 即必须有 exact-zero. 这与零值和 sparsity 有关, 同时也要考虑对称性问题.

归一化与匹配

令:

a=max⁡∣W∣.a = \max |W|.

把权重归一化到 [−1,1][-1, 1], 再与归一化后的分位数匹配:

Wa∈[−1,1]⟷QZ(pi)max⁡iQZ(pi).\frac{W}{a} \in [-1, 1] \quad \longleftrightarrow \quad \frac{Q_Z(p_i)}{\max_i Q_Z(p_i)}.

2. Double Quantization (DQ)

每个权重块还需要额外保存一个 32-bit 的量化常数 aja_j. 如果一个块包含 64 个 weight, 平均位宽就会达到 4.5 bit. 因此, 可以进一步压缩 aja_j.

对于包含 64 个 weight 的块 WjW_j, 用量化常数 aja_j 和量化后的数值 qq 表示:

Wj≈ajq,aj=max⁡∣Wj∣.W_j \approx a_j q, \qquad a_j = \max |W_j|.

qq 来自前面的 QQ 过程, aja_j 是 quantization constant.

对所有 aja_j 再做量化. 先减去均值 μ\mu, 再缩放:

rj=aj−μb.r_j = \frac{a_j - \mu}{b}.

将 rjr_j 从 32-bit 量化到 8-bit, 得到 r^j\widehat r_j, 再重建:

a^j=μ+br^j.\widehat a_j = \mu + b\widehat r_j.

其中 μ\mu 和 bb 用 32-bit 保存. 最终得到约 4.127 bit/param.

手写原稿

LoRA 与 QLoRA 手写原稿, 含生图模型示意与分位数 CDF 图