目录
- 第一部分:低秩分解基础理论
- 第一章:绪论------模型压缩的第四条路
- 第二章:矩阵低秩分解的数学基础------SVD 与 Eckart-Young 定理
- 第三章:张量分解------从矩阵到高阶张量
- 第二部分:低秩分解在模型压缩中的应用
- 第四章:权重矩阵的低秩近似
- 第五章:卷积层的低秩分解
- 第六章:注意力机制的低秩近似
- 第三部分:低秩适配(LoRA)与参数高效微调
- 第七章:LoRA 的数学原理
- 第八章:LoRA 的变体与扩展
- 第九章:QLoRA------量化低秩适配
- 第十章:DoRA、AdaLoRA 与自适应秩选择
- 第四部分:低秩结构的理论分析
- 第十一章:内在维度假说与低秩结构
- 第十二章:神经网络的低秩偏置
- 第十三章:低秩与泛化理论
- 第五部分:完整可运行代码实现
- 第十四章:从零实现 SVD 分解与低秩近似
- 第十五章:从零实现权重低秩分解压缩
- 第十六章:从零实现 LoRA 与 QLoRA
- 第十七章:完整低秩压缩 Pipeline 与精度对比
- 附录
第一部分:低秩分解基础理论
第一章:绪论------模型压缩的第四条路
1.1 低秩分解的定位
在前三篇文档中,我们讨论了量化 、剪枝 和蒸馏。低秩分解是模型压缩的第四大范式:
| 范式 | 核心思想 | 压缩方式 | 数学工具 |
|---|---|---|---|
| 量化 | 降低参数精度 | 减少每个参数的比特数 | 信息论 |
| 剪枝 | 移除冗余参数 | 减少非零参数数量 | 稀疏优化 |
| 蒸馏 | 知识迁移 | 训练更小的模型 | KL 散度 |
| 低秩分解 | 矩阵分解 | 将大矩阵分解为小矩阵 | 线性代数 |
1.1.1 核心思想
低秩分解(Low-Rank Factorization) 的核心思想是:将大的权重矩阵分解为多个小矩阵的乘积,利用矩阵的低秩结构来减少参数量。
例子 :对于权重矩阵 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n,将其分解为:
W≈AB,A∈Rm×r,B∈Rr×nW \approx A B, \quad A \in \mathbb{R}^{m \times r}, \quad B \in \mathbb{R}^{r \times n}W≈AB,A∈Rm×r,B∈Rr×n
其中 r≪min(m,n)r \ll \min(m, n)r≪min(m,n) 是秩(rank)。
参数量对比:
- 原始:mnmnmn 个参数
- 低秩分解:(m+n)r(m + n)r(m+n)r 个参数
- 压缩比:mn(m+n)r\frac{mn}{(m+n)r}(m+n)rmn
当 r=mnk(m+n)r = \frac{mn}{k(m+n)}r=k(m+n)mn 时,压缩比为 kkk。
1.1.2 为什么权重矩阵是低秩的?
观察 :训练好的神经网络权重矩阵通常具有低有效秩(low effective rank)。
定理 1.1(权重矩阵的有效秩) :设权重矩阵 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n 的奇异值为 σ1≥σ2≥⋯≥σmin(m,n)\sigma_1 \geq \sigma_2 \geq \dots \geq \sigma_{\min(m,n)}σ1≥σ2≥⋯≥σmin(m,n)。定义有效秩为:
reff(W)=exp(−∑ipilogpi),pi=σi∑jσjr_{\text{eff}}(W) = \exp\left(-\sum_i p_i \log p_i\right), \quad p_i = \frac{\sigma_i}{\sum_j \sigma_j}reff(W)=exp(−i∑pilogpi),pi=∑jσjσi
实证观察 :对于典型的深度学习模型,reff(W)/min(m,n)r_{\text{eff}}(W) / \min(m, n)reff(W)/min(m,n) 通常在 10%-50% 之间------意味着大部分奇异值接近零,权重矩阵近似低秩。
1.2 低秩分解的优势
| 效益 | 说明 | 数学刻画 |
|---|---|---|
| 减少参数量 | mn→(m+n)rmn \to (m+n)rmn→(m+n)r | 压缩比 mn/((m+n)r)mn / ((m+n)r)mn/((m+n)r) |
| 减少计算量 | O(mn)→O((m+n)r)O(mn) \to O((m+n)r)O(mn)→O((m+n)r) | 矩阵乘法的 FLOPs |
| 减少存储 | 更少的参数需要存储 | 与参数量成正比 |
| 提高泛化 | 低秩约束起到正则化作用 | 减少模型复杂度 |
| 参数高效微调 | LoRA 只训练少量参数 | r(m+n)≪mnr(m+n) \ll mnr(m+n)≪mn |
第二章:矩阵低秩分解的数学基础------SVD 与 Eckart-Young 定理
2.1 奇异值分解(SVD)
2.1.1 SVD 的定义
定理 2.1(奇异值分解) :任意矩阵 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n 可以分解为:
W=UΣVTW = U \Sigma V^TW=UΣVT
其中:
- U∈Rm×mU \in \mathbb{R}^{m \times m}U∈Rm×m 是正交矩阵(左奇异向量)
- Σ∈Rm×n\Sigma \in \mathbb{R}^{m \times n}Σ∈Rm×n 是对角矩阵(奇异值 σ1≥σ2≥⋯≥0\sigma_1 \geq \sigma_2 \geq \dots \geq 0σ1≥σ2≥⋯≥0)
- V∈Rn×nV \in \mathbb{R}^{n \times n}V∈Rn×n 是正交矩阵(右奇异向量)
紧凑 SVD :如果 rank(W)=r\text{rank}(W) = rrank(W)=r,则:
W=UrΣrVrTW = U_r \Sigma_r V_r^TW=UrΣrVrT
其中 Ur∈Rm×rU_r \in \mathbb{R}^{m \times r}Ur∈Rm×r,Σr∈Rr×r\Sigma_r \in \mathbb{R}^{r \times r}Σr∈Rr×r,Vr∈Rn×rV_r \in \mathbb{R}^{n \times r}Vr∈Rn×r。
2.1.2 SVD 的几何解释
定理 2.2(SVD 的几何意义) :SVD 将线性变换 W:Rn→RmW: \mathbb{R}^n \to \mathbb{R}^mW:Rn→Rm 分解为三个步骤:
- 旋转/反射 :VTV^TVT 将输入空间旋转到奇异向量方向
- 缩放 :Σ\SigmaΣ 沿每个奇异向量方向缩放 σi\sigma_iσi 倍
- 旋转/反射 :UUU 将结果旋转到输出空间
推论 2.1 :奇异值 σi\sigma_iσi 衡量了 WWW 在第 iii 个奇异方向上的"强度"------σi\sigma_iσi 越大,该方向越重要。
2.1.3 SVD 的计算
算法 2.1(SVD 的计算步骤):
1. 计算 W^T W 的特征值分解:W^T W = V Λ V^T
2. 奇异值:σ_i = √λ_i
3. 左奇异向量:u_i = W v_i / σ_i
复杂度:
- 完整 SVD:O(mnmin(m,n))O(mn \min(m, n))O(mnmin(m,n))
- 截断 SVD(前 rrr 个奇异值):O(mnr)O(mnr)O(mnr)
2.2 Eckart-Young-Mirsky 定理
2.2.1 定理陈述
定理 2.3(Eckart-Young-Mirsky 定理) :设 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n 的 SVD 为 W=UΣVTW = U \Sigma V^TW=UΣVT,奇异值为 σ1≥σ2≥⋯≥σp\sigma_1 \geq \sigma_2 \geq \dots \geq \sigma_pσ1≥σ2≥⋯≥σp(p=min(m,n)p = \min(m, n)p=min(m,n))。则对于任意秩不超过 rrr 的矩阵 XXX:
∥W−Wr∥F≤∥W−X∥F\|W - W_r\|_F \leq \|W - X\|_F∥W−Wr∥F≤∥W−X∥F
∥W−Wr∥2≤∥W−X∥2\|W - W_r\|_2 \leq \|W - X\|_2∥W−Wr∥2≤∥W−X∥2
其中 Wr=UrΣrVrTW_r = U_r \Sigma_r V_r^TWr=UrΣrVrT 是 WWW 的最佳秩 rrr 近似(截断 SVD)。
等号成立当且仅当 X=WrX = W_rX=Wr(对于 Frobenius 范数,在一定条件下)。
2.2.2 Frobenius 范数误差
定理 2.4(最佳秩 rrr 近似的误差):
∥W−Wr∥F=∑i=r+1pσi2\|W - W_r\|F = \sqrt{\sum{i=r+1}^{p} \sigma_i^2}∥W−Wr∥F=i=r+1∑pσi2
证明:
∥W−Wr∥F2=∥U(Σ−Σr)VT∥F2=∥Σ−Σr∥F2=∑i=r+1pσi2\|W - W_r\|_F^2 = \|U(\Sigma - \Sigma_r)V^T\|_F^2 = \|\Sigma - \Sigma_r\|F^2 = \sum{i=r+1}^{p} \sigma_i^2∥W−Wr∥F2=∥U(Σ−Σr)VT∥F2=∥Σ−Σr∥F2=i=r+1∑pσi2
因为 Frobenius 范数在正交变换下不变。□\square□
推论 2.2 :如果奇异值快速衰减(σr+1,σr+2,...\sigma_{r+1}, \sigma_{r+2}, \dotsσr+1,σr+2,... 很小),则低秩近似误差很小。
2.2.3 谱范数误差
定理 2.5(谱范数下的最佳近似):
∥W−Wr∥2=σr+1\|W - W_r\|2 = \sigma{r+1}∥W−Wr∥2=σr+1
证明 :谱范数等于最大奇异值。∥W−Wr∥2=σr+1\|W - W_r\|2 = \sigma{r+1}∥W−Wr∥2=σr+1。□\square□
2.2.4 Eckart-Young 定理的重要性
核心意义 :截断 SVD 是全局最优 的低秩近似------在所有秩不超过 rrr 的矩阵中,截断 SVD 的误差最小。
这为低秩分解压缩提供了坚实的理论基础:使用 SVD 进行低秩近似是最佳策略。
2.3 奇异值的衰减与低秩性
2.3.1 奇异值衰减的度量
定义 2.1(有效秩):
reff(W)=(∑iσi)2∑iσi2r_{\text{eff}}(W) = \frac{\left(\sum_i \sigma_i\right)^2}{\sum_i \sigma_i^2}reff(W)=∑iσi2(∑iσi)2
性质:
- 1≤reff≤p1 \leq r_{\text{eff}} \leq p1≤reff≤p
- 当所有奇异值相等时,reff=pr_{\text{eff}} = preff=p
- 当只有一个非零奇异值时,reff=1r_{\text{eff}} = 1reff=1
2.3.2 奇异值衰减的理论分析
定理 2.6(随机矩阵的奇异值分布) :设 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n 的元素独立同分布于 N(0,1/n)\mathcal{N}(0, 1/n)N(0,1/n)。当 m,n→∞m, n \to \inftym,n→∞ 且 m/n→γm/n \to \gammam/n→γ 时,奇异值的极限分布服从 Marchenko-Pastur 分布:
p(σ)=12πγσ2(σ+2−σ2)(σ2−σ−2),σ∈σ−,σ+p(\sigma) = \frac{1}{2\pi \gamma \sigma^2} \sqrt{(\sigma_+^2 - \sigma^2)(\sigma^2 - \sigma_-^2)}, \quad \sigma \in \\sigma_-, \\sigma_+p(σ)=2πγσ21(σ+2−σ2)(σ2−σ−2) ,σ∈σ−,σ+
其中 σ±=1±γ\sigma_\pm = 1 \pm \sqrt{\gamma}σ±=1±γ 。
推论 2.3 :对于随机初始化的权重矩阵,奇异值分布是连续的,没有明显的低秩结构。但训练后的权重矩阵通常表现出快速的奇异值衰减------这是低秩分解有效的关键原因。
2.3.3 训练导致低秩的理论解释
定理 2.7(梯度下降的低秩偏置) :在过参数化的线性网络中,梯度下降训练倾向于找到低秩的权重矩阵。
直觉:梯度下降沿着损失函数的"最陡下降方向"更新权重。在过参数化的情况下,这些方向通常是低秩的------因为高秩方向对应的奇异值很小,梯度信号很弱。
第三章:张量分解------从矩阵到高阶张量
3.1 张量的基本概念
3.1.1 张量的定义
定义 3.1(张量) :NNN 阶张量是 NNN 个向量空间的张量积中的元素:
T∈RI1×I2×⋯×IN\mathcal{T} \in \mathbb{R}^{I_1 \times I_2 \times \dots \times I_N}T∈RI1×I2×⋯×IN
- 1 阶张量 = 向量
- 2 阶张量 = 矩阵
- 3 阶及以上 = 高阶张量
3.1.2 张量的展开矩阵
定义 3.2(模式-nnn 展开) :将张量 T∈RI1×⋯×IN\mathcal{T} \in \mathbb{R}^{I_1 \times \dots \times I_N}T∈RI1×⋯×IN 沿第 nnn 个模式展开为矩阵 T(n)∈RIn×(I1...In−1In+1...IN)T_{(n)} \in \mathbb{R}^{I_n \times (I_1 \dots I_{n-1} I_{n+1} \dots I_N)}T(n)∈RIn×(I1...In−1In+1...IN)。
3.2 CP 分解(CANDECOMP/PARAFAC)
3.2.1 定义
定义 3.3(CP 分解) :NNN 阶张量 T\mathcal{T}T 的秩 RRR CP 分解为:
T≈∑r=1Rar(1)∘ar(2)∘⋯∘ar(N)\mathcal{T} \approx \sum_{r=1}^{R} \mathbf{a}_r^{(1)} \circ \mathbf{a}_r^{(2)} \circ \dots \circ \mathbf{a}_r^{(N)}T≈r=1∑Rar(1)∘ar(2)∘⋯∘ar(N)
其中 ar(n)∈RIn\mathbf{a}_r^{(n)} \in \mathbb{R}^{I_n}ar(n)∈RIn 是第 nnn 个模式的因子向量,∘\circ∘ 表示外积。
参数量 :R∑n=1NInR \sum_{n=1}^{N} I_nR∑n=1NIn
3.2.2 CP 分解的计算
算法 3.1(交替最小二乘,ALS):
输入:张量 T,秩 R
输出:因子矩阵 A^(1), ..., A^(N)
1. 初始化:随机初始化 A^(1), ..., A^(N)
2. 重复:
对 n = 1, ..., N:
固定其他因子,更新 A^(n):
A^(n) = T_(n) (A^(N) ⊙ ... ⊙ A^(n+1) ⊙ A^(n-1) ... ⊙ A^(1))†
3. 直到收敛
其中 ⊙\odot⊙ 是 Khatri-Rao 积,†\dagger† 是伪逆。
3.3 Tucker 分解
3.3.1 定义
定义 3.4(Tucker 分解):
T≈G×1U(1)×2U(2)⋯×NU(N)\mathcal{T} \approx \mathcal{G} \times_1 U^{(1)} \times_2 U^{(2)} \dots \times_N U^{(N)}T≈G×1U(1)×2U(2)⋯×NU(N)
其中:
- G∈RR1×R2×⋯×RN\mathcal{G} \in \mathbb{R}^{R_1 \times R_2 \times \dots \times R_N}G∈RR1×R2×⋯×RN 是核心张量
- U(n)∈RIn×RnU^{(n)} \in \mathbb{R}^{I_n \times R_n}U(n)∈RIn×Rn 是第 nnn 个模式的因子矩阵
参数量 :∏n=1NRn+∑n=1NInRn\prod_{n=1}^{N} R_n + \sum_{n=1}^{N} I_n R_n∏n=1NRn+∑n=1NInRn
3.3.2 Tucker 分解与 SVD 的关系
定理 3.1(Tucker 分解是 SVD 的高阶推广):对于 2 阶张量(矩阵),Tucker 分解退化为 SVD:
W=UΣVT=Σ×1U×2VW = U \Sigma V^T = \Sigma \times_1 U \times_2 VW=UΣVT=Σ×1U×2V
定理 3.2(高阶 SVD,HOSVD) :任意 NNN 阶张量可以精确分解为:
T=G×1U(1)×2U(2)⋯×NU(N)\mathcal{T} = \mathcal{G} \times_1 U^{(1)} \times_2 U^{(2)} \dots \times_N U^{(N)}T=G×1U(1)×2U(2)⋯×NU(N)
其中 U(n)U^{(n)}U(n) 是模式-nnn 展开矩阵 T(n)T_{(n)}T(n) 的左奇异向量。
第二部分:低秩分解在模型压缩中的应用
第四章:权重矩阵的低秩近似
4.1 全连接层的低秩分解
4.1.1 问题形式化
对于全连接层 Y=XWY = XWY=XW,W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n,将其分解为:
W≈AB,A∈Rm×r,B∈Rr×nW \approx AB, \quad A \in \mathbb{R}^{m \times r}, \quad B \in \mathbb{R}^{r \times n}W≈AB,A∈Rm×r,B∈Rr×n
计算变为 :Y=X(AB)=(XA)BY = X(AB) = (XA)BY=X(AB)=(XA)B------先计算 XAXAXA(O(nr⋅T)O(nr \cdot T)O(nr⋅T)),再计算结果乘以 BBB(O(mr⋅T)O(mr \cdot T)O(mr⋅T))。
总 FLOPs :O((m+n)rT)O((m+n)rT)O((m+n)rT) vs O(mnT)O(mnT)O(mnT)------当 r<mnm+nr < \frac{mn}{m+n}r<m+nmn 时,计算量减少。
4.1.2 SVD 分解
算法 4.1(SVD 低秩近似):
输入:权重矩阵 W,目标秩 r
输出:分解后的 A, B
1. 计算 SVD:W = U Σ V^T
2. 截断:U_r = U[:, :r], Σ_r = Σ[:r, :r], V_r = V[:, :r]
3. 分解:A = U_r Σ_r^{1/2}, B = Σ_r^{1/2} V_r^T
返回 A, B
误差 :∥W−AB∥F=∑i=r+1pσi2\|W - AB\|F = \sqrt{\sum{i=r+1}^{p} \sigma_i^2}∥W−AB∥F=∑i=r+1pσi2
4.1.3 非对称分解
问题 :SVD 分解得到的 AAA 和 BBB 是特殊的(正交矩阵)。更一般的分解可能更优。
定义 4.1(非对称分解):
minA,B∥W−AB∥F2\min_{A, B} \|W - AB\|_F^2A,Bmin∥W−AB∥F2
定理 4.1(非对称分解的最优解):最优解为:
A=UrΣr1/2Q,B=Q−1Σr1/2VrTA = U_r \Sigma_r^{1/2} Q, \quad B = Q^{-1} \Sigma_r^{1/2} V_r^TA=UrΣr1/2Q,B=Q−1Σr1/2VrT
其中 QQQ 是任意 r×rr \times rr×r 可逆矩阵。
推论 4.1 :SVD 分解(Q=IQ = IQ=I)是所有非对称分解中的一个特解,但在 Frobenius 范数下是最优的。
4.2 低秩分解的微调
4.2.1 问题
直接 SVD 分解的问题:截断 SVD 最小化的是权重矩阵的近似误差,而不是模型输出的误差。这可能导致精度下降。
4.2.2 数据感知的低秩分解
定义 4.2(数据感知分解):
minA,B∥(W−AB)X∥F2=minA,B∥(W−AB)X∥F2\min_{A, B} \|(W - AB)X\|F^2 = \min{A, B} \|(W - AB)X\|_F^2A,Bmin∥(W−AB)X∥F2=A,Bmin∥(W−AB)X∥F2
定理 4.2(数据感知分解的最优解) :设 H=XXTH = XX^TH=XXT 是输入的协方差矩阵,则最优分解为:
Wrdata=Ur(H)(Σr(H))1/2Q⋅Q−1(Σr(H))1/2(Vr(H))TW_{r}^{\text{data}} = U_r^{(H)} (\Sigma_r^{(H)})^{1/2} Q \cdot Q^{-1} (\Sigma_r^{(H)})^{1/2} (V_r^{(H)})^TWrdata=Ur(H)(Σr(H))1/2Q⋅Q−1(Σr(H))1/2(Vr(H))T
其中 Ur(H),Σr(H),Vr(H)U_r^{(H)}, \Sigma_r^{(H)}, V_r^{(H)}Ur(H),Σr(H),Vr(H) 是 WWW 在 HHH-加权范数下的 SVD。
直觉:数据感知分解优先保留那些对输入数据影响最大的方向。
4.3 逐层分解 vs 全局分解
4.3.1 逐层分解
方法:独立地对每一层的权重矩阵进行 SVD 分解。
优点:简单,每层可以独立优化秩。
缺点:没有考虑层间误差传播。
4.3.2 全局分解
方法:联合优化所有层的分解,最小化全局输出误差。
目标:
min{Al,Bl}∑l=1L∥(Wl−AlBl)Xl∥F2\min_{\{A_l, B_l\}} \sum_{l=1}^{L} \|(W_l - A_l B_l) X_l\|_F^2{Al,Bl}minl=1∑L∥(Wl−AlBl)Xl∥F2
挑战:这是一个非凸优化问题,需要迭代求解。
第五章:卷积层的低秩分解
5.1 卷积的矩阵表示
5.1.1 卷积核的展开
定义 5.1(卷积核矩阵) :对于卷积层的权重张量 W∈RCout×Cin×K×K\mathcal{W} \in \mathbb{R}^{C_{\text{out}} \times C_{\text{in}} \times K \times K}W∈RCout×Cin×K×K,可以将其展开为矩阵:
W(2)∈RCin×(CoutK2)W_{(2)} \in \mathbb{R}^{C_{\text{in}} \times (C_{\text{out}} K^2)}W(2)∈RCin×(CoutK2)
5.1.2 卷积的低秩分解
方法 1:空间分解:
W≈W1∗W2\mathcal{W} \approx \mathcal{W}_1 * \mathcal{W}_2W≈W1∗W2
将 K×KK \times KK×K 卷积分解为 K×1K \times 1K×1 和 1×K1 \times K1×K 卷积的级联。
方法 2:通道分解:
W≈A∗B\mathcal{W} \approx \mathcal{A} * \mathcal{B}W≈A∗B
其中 A∈RCout×r×1×1\mathcal{A} \in \mathbb{R}^{C_{\text{out}} \times r \times 1 \times 1}A∈RCout×r×1×1,B∈Rr×Cin×K×K\mathcal{B} \in \mathbb{R}^{r \times C_{\text{in}} \times K \times K}B∈Rr×Cin×K×K。
5.2 卷积分解的理论分析
定理 5.1(卷积分解的计算节省) :将 K×KK \times KK×K 卷积分解为 K×1K \times 1K×1 和 1×K1 \times K1×K 卷积:
- 原始 FLOPs:O(CoutCinK2HW)O(C_{\text{out}} C_{\text{in}} K^2 HW)O(CoutCinK2HW)
- 分解后 FLOPs:O(CoutCinK⋅2HW)O(C_{\text{out}} C_{\text{in}} K \cdot 2 HW)O(CoutCinK⋅2HW)
- 节省比:K/2K/2K/2
对于 K=3K = 3K=3,节省 1.5 倍;对于 K=5K = 5K=5,节省 2.5 倍;对于 K=7K = 7K=7,节省 3.5 倍。
第六章:注意力机制的低秩近似
6.1 自注意力的计算复杂度
6.1.1 标准自注意力
Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) VAttention(Q,K,V)=softmax(dk QKT)V
其中 Q,K,V∈Rn×dQ, K, V \in \mathbb{R}^{n \times d}Q,K,V∈Rn×d。
计算复杂度:
- QKTQK^TQKT:O(n2d)O(n^2 d)O(n2d)
- softmax\text{softmax}softmax:O(n2)O(n^2)O(n2)
- 乘以 VVV:O(n2d)O(n^2 d)O(n2d)
- 总复杂度 :O(n2d)O(n^2 d)O(n2d)
6.1.2 低秩注意力
思想 :将 QQQ 和 KKK 投影到低维空间:
Q~=QPQ,K~=KPK\tilde{Q} = Q P_Q, \quad \tilde{K} = K P_KQ~=QPQ,K~=KPK
其中 PQ,PK∈Rd×rP_Q, P_K \in \mathbb{R}^{d \times r}PQ,PK∈Rd×r,r≪dr \ll dr≪d。
低秩注意力:
Attentionlow-rank=softmax(Q~K~Tr)V\text{Attention}_{\text{low-rank}} = \text{softmax}\left(\frac{\tilde{Q} \tilde{K}^T}{\sqrt{r}}\right) VAttentionlow-rank=softmax(r Q~K~T)V
复杂度 :O(n2r+nrd)O(n^2 r + nrd)O(n2r+nrd)------当 r<dr < dr<d 时,计算量减少。
6.2 Linformer
6.2.1 核心思想
Linformer(Wang et al., 2020)将 Key 和 Value 投影到低维:
K~=EK,F~=FV\tilde{K} = E K, \quad \tilde{F} = F VK~=EK,F~=FV
其中 E,F∈Rk×nE, F \in \mathbb{R}^{k \times n}E,F∈Rk×n,k≪nk \ll nk≪n。
Linformer 注意力:
AttentionLinformer=softmax(QK~Td)F~\text{Attention}_{\text{Linformer}} = \text{softmax}\left(\frac{Q \tilde{K}^T}{\sqrt{d}}\right) \tilde{F}AttentionLinformer=softmax(d QK~T)F~
复杂度 :O(nkd)O(nkd)O(nkd)------线性复杂度!
6.2.2 Linformer 的理论分析
定理 6.1(Linformer 的近似误差):在一定假设下,Linformer 的近似误差满足:
∥Attention−AttentionLinformer∥F≤O(nk)\|\text{Attention} - \text{Attention}_{\text{Linformer}}\|_F \leq O\left(\frac{n}{\sqrt{k}}\right)∥Attention−AttentionLinformer∥F≤O(k n)
推论 :当 k=O(n/ϵ2)k = O(n/\epsilon^2)k=O(n/ϵ2) 时,近似误差不超过 ϵ\epsilonϵ。
6.3 Performer
6.3.1 核心思想
Performer(Choromanski et al., 2021)使用随机特征映射来近似 softmax 核:
softmax(QKT)≈ϕ(Q)ϕ(K)T\text{softmax}(QK^T) \approx \phi(Q) \phi(K)^Tsoftmax(QKT)≈ϕ(Q)ϕ(K)T
其中 ϕ:Rd→Rm\phi: \mathbb{R}^d \to \mathbb{R}^mϕ:Rd→Rm 是随机特征映射。
Performer 注意力:
AttentionPerformer=ϕ(Q)(ϕ(K)TV)ϕ(Q)(ϕ(K)T1)\text{Attention}_{\text{Performer}} = \frac{\phi(Q) (\phi(K)^T V)}{\phi(Q) (\phi(K)^T \mathbf{1})}AttentionPerformer=ϕ(Q)(ϕ(K)T1)ϕ(Q)(ϕ(K)TV)
复杂度 :O(nmd)O(nmd)O(nmd)------通过改变计算顺序避免 O(n2)O(n^2)O(n2) 的注意力矩阵。
第三部分:低秩适配(LoRA)与参数高效微调
第七章:LoRA 的数学原理
7.1 LoRA 的核心思想
7.1.1 问题形式化
全参数微调:对预训练模型的所有参数进行微调。
W′=W+ΔWW' = W + \Delta WW′=W+ΔW
其中 ΔW∈Rm×n\Delta W \in \mathbb{R}^{m \times n}ΔW∈Rm×n 是微调更新。
问题 :对于大模型,ΔW\Delta WΔW 的参数量与原始模型相同------存储和计算成本很高。
7.1.2 LoRA 的低秩假设
核心假设 :微调更新 ΔW\Delta WΔW 是低秩的。
LoRA 分解:
ΔW=BA,B∈Rm×r,A∈Rr×n\Delta W = BA, \quad B \in \mathbb{R}^{m \times r}, \quad A \in \mathbb{R}^{r \times n}ΔW=BA,B∈Rm×r,A∈Rr×n
其中 r≪min(m,n)r \ll \min(m, n)r≪min(m,n)。
参数量 :r(m+n)r(m+n)r(m+n) vs mnmnmn------当 r=16r = 16r=16,m=n=4096m = n = 4096m=n=4096 时,参数量减少 4096/(2×16)=1284096/(2 \times 16) = 1284096/(2×16)=128 倍。
7.1.3 LoRA 的前向传播
标准前向传播:
h=Wxh = Wxh=Wx
LoRA 前向传播:
h=Wx+ΔWx=Wx+BAx=Wx+B(Ax)h = Wx + \Delta Wx = Wx + BAx = Wx + B(Ax)h=Wx+ΔWx=Wx+BAx=Wx+B(Ax)
计算步骤:
- 计算 AxAxAx:O(rn)O(rn)O(rn)
- 计算 B(Ax)B(Ax)B(Ax):O(mr)O(mr)O(mr)
- 加上 WxWxWx:O(m)O(m)O(m)
总计算量 :O(mn+(m+n)r)O(mn + (m+n)r)O(mn+(m+n)r)------当 rrr 很小时,额外开销可以忽略。
7.2 LoRA 的训练
7.2.1 初始化策略
定理 7.1(LoRA 的初始化):
策略 1(标准初始化):
- A∼N(0,σ2)A \sim \mathcal{N}(0, \sigma^2)A∼N(0,σ2)
- B=0B = 0B=0
策略 2(Kaiming 初始化):
- A∼N(0,2/n)A \sim \mathcal{N}(0, 2/n)A∼N(0,2/n)
- B=0B = 0B=0
为什么 B=0B = 0B=0? 确保训练开始时 ΔW=BA=0\Delta W = BA = 0ΔW=BA=0------LoRA 不改变预训练模型的行为。
7.2.2 缩放因子
定义 7.1(LoRA 缩放):
h=Wx+αrBAxh = Wx + \frac{\alpha}{r} BAxh=Wx+rαBAx
其中 α\alphaα 是缩放超参数。
定理 7.2(缩放因子的作用) :缩放因子 α/r\alpha/rα/r 确保了 LoRA 更新的梯度量级与全参数微调一致。
证明 :设损失为 L\mathcal{L}L,对 BBB 的梯度为:
∂L∂B=∂L∂h⋅αr(Ax)T\frac{\partial \mathcal{L}}{\partial B} = \frac{\partial \mathcal{L}}{\partial h} \cdot \frac{\alpha}{r} (Ax)^T∂B∂L=∂h∂L⋅rα(Ax)T
缩放因子 α/r\alpha/rα/r 使得梯度量级不随 rrr 变化。□\square□
7.2.3 LoRA 的训练算法
算法 7.1(LoRA 训练):
输入:预训练权重 W,训练数据,秩 r,缩放 α
输出:训练好的 A, B
1. 初始化:A ~ N(0, σ²), B = 0
2. 冻结 W,只训练 A 和 B
3. 对每个训练步:
a. 前向传播:h = Wx + (α/r) BAx
b. 计算损失
c. 反向传播:计算 ∂L/∂A 和 ∂L/∂B
d. 更新:A = A - lr * ∂L/∂A, B = B - lr * ∂L/∂B
4. 合并:W' = W + (α/r) BA
7.3 LoRA 的理论分析
7.3.1 低秩假设的合理性
定理 7.3(微调更新的低秩性) :在一定假设下,预训练模型的微调更新 ΔW\Delta WΔW 的有效秩满足:
reff(ΔW)≤O(dtaskdmodel)⋅min(m,n)r_{\text{eff}}(\Delta W) \leq O\left(\frac{d_{\text{task}}}{d_{\text{model}}}\right) \cdot \min(m, n)reff(ΔW)≤O(dmodeldtask)⋅min(m,n)
其中 dtaskd_{\text{task}}dtask 是任务的内在维度。
直觉:微调只需要调整模型的一小部分"方向"------对应于任务相关的低维子空间。
7.3.2 LoRA 的泛化分析
定理 7.4(LoRA 的泛化界) :设 LoRA 的秩为 rrr,训练样本数为 TTT,则泛化误差满足:
ELtest≤ELtrain+O(r(m+n)log(mn)T)\mathbb{E}\\mathcal{L}_{\\text{test}} \leq \mathbb{E}\\mathcal{L}_{\\text{train}} + O\left(\frac{r(m+n) \log(mn)}{T}\right)ELtest≤ELtrain+O(Tr(m+n)log(mn))
推论 :LoRA 的泛化误差上界与 r(m+n)r(m+n)r(m+n) 成正比------参数量越少,泛化越好。
第八章:LoRA 的变体与扩展
8.1 LoRA 的架构变体
8.1.1 标准 LoRA
ΔW=BA\Delta W = BAΔW=BA
8.1.2 多头 LoRA
将 rrr 个 LoRA 分成 hhh 个头,每个头 r/hr/hr/h 维:
ΔW=B1A1,B2A2,...,BhAh\Delta W = B_1 A_1, B_2 A_2, \\dots, B_h A_hΔW=B1A1,B2A2,...,BhAh
8.1.3 共享 LoRA
多个层共享同一组 AAA 和 BBB:
ΔWl=BlA,l=1,...,L\Delta W_l = B_l A, \quad l = 1, \dots, LΔWl=BlA,l=1,...,L
8.2 LoRA 的应用变体
8.2.1 LoRA 的应用位置
问题:在 Transformer 中,LoRA 应该应用到哪些权重矩阵?
常见选择:
| 位置 | 权重矩阵 | 说明 |
|---|---|---|
| 自注意力 | WQ,WK,WV,WOW_Q, W_K, W_V, W_OWQ,WK,WV,WO | Query, Key, Value, Output |
| FFN | Wup,Wdown,WgateW_{\text{up}}, W_{\text{down}}, W_{\text{gate}}Wup,Wdown,Wgate | 上投影、下投影、门控 |
经验 :WQW_QWQ 和 WVW_VWV 通常最有效。
8.2.2 LoRA+
LoRA+ (Hayou et al., 2024)为 AAA 和 BBB 使用不同的学习率:
A←A−ηA∂L∂A,B←B−ηB∂L∂BA \leftarrow A - \eta_A \frac{\partial \mathcal{L}}{\partial A}, \quad B \leftarrow B - \eta_B \frac{\partial \mathcal{L}}{\partial B}A←A−ηA∂A∂L,B←B−ηB∂B∂L
其中 ηB≫ηA\eta_B \gg \eta_AηB≫ηA(通常 ηB/ηA=16\eta_B / \eta_A = 16ηB/ηA=16)。
定理 8.1(LoRA+ 的最优学习率比):在一定假设下,最优学习率比为:
ηB∗ηA∗=λmax(ATA)λmax(BTB)\frac{\eta_B^*}{\eta_A^*} = \frac{\lambda_{\max}(A^T A)}{\lambda_{\max}(B^T B)}ηA∗ηB∗=λmax(BTB)λmax(ATA)
其中 λmax\lambda_{\max}λmax 是最大特征值。
第九章:QLoRA------量化低秩适配
9.1 QLoRA 的核心思想
9.1.1 动机
问题:LoRA 虽然减少了可训练参数,但预训练权重仍然需要以 FP16 存储------对于 70B 模型需要 140GB 显存。
QLoRA(Dettmers et al., 2023)将预训练权重量化为 4 比特,进一步减少显存。
9.1.2 QLoRA 的架构
QLoRA 的前向传播:
h=Dequant(W4bit)⋅x+αrBAxh = \text{Dequant}(W_{\text{4bit}}) \cdot x + \frac{\alpha}{r} BAxh=Dequant(W4bit)⋅x+rαBAx
其中:
- W4bitW_{\text{4bit}}W4bit:4 比特量化的预训练权重(冻结)
- B,AB, AB,A:LoRA 参数(可训练,FP16/BF16)
9.1.3 NF4 量化
QLoRA 使用 NF4(4-bit NormalFloat) 量化------专为正态分布设计的 4 比特格式。
NF4 的量化点是标准正态分布的等概率分位数。
9.2 QLoRA 的技术细节
9.2.1 双重量化
问题:量化缩放因子本身也需要存储。
双重量化(Double Quantization):对缩放因子再进行一次量化:
squant=Quant(sFP32)s_{\text{quant}} = \text{Quant}(s_{\text{FP32}})squant=Quant(sFP32)
存储节省:从每 64 个参数 32 bit 缩放因子,减少到每 64 个参数约 4 bit。
9.2.2 分页优化
问题:GPU 显存不足时需要将数据换出到 CPU 内存。
分页优化(Paged Optimizers):使用 NVIDIA 的统一内存管理,在 GPU 显存不足时自动将优化器状态换出到 CPU。
9.3 QLoRA 的理论分析
定理 9.1(QLoRA 的精度损失) :设预训练权重的量化误差为 ϵQ\epsilon_QϵQ,LoRA 的近似误差为 ϵL\epsilon_LϵL,则 QLoRA 的总误差满足:
∥W+ΔW−(Dequant(W4bit)+BA)∥F≤ϵQ+ϵL\|W + \Delta W - (\text{Dequant}(W_{\text{4bit}}) + BA)\|_F \leq \epsilon_Q + \epsilon_L∥W+ΔW−(Dequant(W4bit)+BA)∥F≤ϵQ+ϵL
推论 :QLoRA 的精度损失主要来自量化,LoRA 部分的损失可以忽略(因为 BBB 和 AAA 是以高精度训练的)。
第十章:DoRA、AdaLoRA 与自适应秩选择
10.1 DoRA------权重分解 LoRA
10.1.1 核心思想
DoRA (Weight-Decomposed Low-Rank Adaptation)将权重分解为幅度(magnitude) 和方向(direction):
W=m⋅V∥V∥cW = m \cdot \frac{V}{\|V\|_c}W=m⋅∥V∥cV
其中 m∈R1×nm \in \mathbb{R}^{1 \times n}m∈R1×n 是幅度,V∈Rm×nV \in \mathbb{R}^{m \times n}V∈Rm×n 是方向矩阵,∥⋅∥c\|\cdot\|_c∥⋅∥c 是列范数。
DoRA 的微调:
W′=(m+Δm)⋅V+BA∥V+BA∥cW' = (m + \Delta m) \cdot \frac{V + BA}{\|V + BA\|_c}W′=(m+Δm)⋅∥V+BA∥cV+BA
其中 Δm\Delta mΔm 是幅度更新,BABABA 是方向更新(LoRA)。
10.1.2 DoRA 的理论优势
定理 10.1(DoRA 的表达能力):DoRA 可以表示标准 LoRA 无法表示的某些权重更新模式------特别是仅改变幅度而不改变方向的更新。
证明 :标准 LoRA 的更新 ΔW=BA\Delta W = BAΔW=BA 不能独立控制幅度和方向。DoRA 通过分离幅度和方向,提供了更大的灵活性。□\square□
10.2 AdaLoRA------自适应秩分配
10.2.1 核心思想
AdaLoRA (Zhang et al., 2023)为不同的权重矩阵自适应地分配不同的秩。
观察:不同层、不同注意力头对任务的重要性不同------应该为重要的层分配更高的秩。
10.2.2 SVD 参数化
AdaLoRA 将 ΔW\Delta WΔW 参数化为 SVD 形式:
ΔW=PΛQ\Delta W = P \Lambda QΔW=PΛQ
其中 P∈Rm×rP \in \mathbb{R}^{m \times r}P∈Rm×r,Λ∈Rr×r\Lambda \in \mathbb{R}^{r \times r}Λ∈Rr×r(对角),Q∈Rr×nQ \in \mathbb{R}^{r \times n}Q∈Rr×n。
秩的自适应:通过训练过程中逐步将不重要的奇异值设为零,实现秩的自适应调整。
10.2.3 重要性度量
定义 10.1(奇异值重要性):
I(σi)=∣σi∣⋅∥∂L∂σi∥I(\sigma_i) = |\sigma_i| \cdot \left\|\frac{\partial \mathcal{L}}{\partial \sigma_i}\right\|I(σi)=∣σi∣⋅ ∂σi∂L
算法 10.1(AdaLoRA 的秩调整):
1. 初始化:所有层的秩为 r_max
2. 训练若干步
3. 计算每个奇异值的重要性
4. 将最不重要的奇异值设为零(降低秩)
5. 重新分配预算到更重要的层
6. 重复 2-5
10.3 秩选择的理论指导
10.3.1 基于奇异值衰减的秩选择
定理 10.2(最优秩的选择) :设权重矩阵 WWW 的奇异值为 σ1,...,σp\sigma_1, \dots, \sigma_pσ1,...,σp。最优秩 r∗r^*r∗ 应满足:
∑i=1r∗σi2∑i=1pσi2≥1−ϵ\frac{\sum_{i=1}^{r^*} \sigma_i^2}{\sum_{i=1}^{p} \sigma_i^2} \geq 1 - \epsilon∑i=1pσi2∑i=1r∗σi2≥1−ϵ
其中 ϵ\epsilonϵ 是允许的信息损失比例(通常 ϵ=0.01\epsilon = 0.01ϵ=0.01 或 0.050.050.05)。
10.3.2 基于任务性能的秩选择
方法:在验证集上搜索最优秩:
r∗=argminrLval(r)+λ⋅cost(r)r^* = \arg\min_r \mathcal{L}_{\text{val}}(r) + \lambda \cdot \text{cost}(r)r∗=argrminLval(r)+λ⋅cost(r)
第四部分:低秩结构的理论分析
第十一章:内在维度假说与低秩结构
11.1 内在维度假说
11.1.1 定义
定义 11.1(内在维度) :数据或任务的内在维度(intrinsic dimension) 是表示数据/解决任务所需的最小维度。
形式化 :设 M⊂RD\mathcal{M} \subset \mathbb{R}^DM⊂RD 是数据流形,其内在维度 ddd 满足:
M≅Rd\mathcal{M} \cong \mathbb{R}^dM≅Rd
(局部同胚于 ddd 维欧氏空间)
11.1.2 神经网络的内在维度
定理 11.1(神经网络的内在维度) :对于参数量为 NNN 的神经网络,其有效参数维度(内在维度)dintd_{\text{int}}dint 满足:
dint≪Nd_{\text{int}} \ll Ndint≪N
实验支持 :Aghajanyan et al. (2021) 发现,微调大型语言模型只需要 dint≈100−1000d_{\text{int}} \approx 100-1000dint≈100−1000 维------远小于模型的参数量。
11.1.3 低秩与内在维度的关系
定理 11.2(低秩分解与内在维度) :如果权重矩阵的微调更新 ΔW\Delta WΔW 的内在维度为 dintd_{\text{int}}dint,则存在秩 r=O(dint)r = O(d_{\text{int}})r=O(dint) 的分解 ΔW=BA\Delta W = BAΔW=BA 使得:
∥ΔW−BA∥F≤ϵ\|\Delta W - BA\|_F \leq \epsilon∥ΔW−BA∥F≤ϵ
证明 :由 Eckart-Young 定理,ΔW\Delta WΔW 的最佳秩 rrr 近似误差为 ∑i=r+1pσi2\sqrt{\sum_{i=r+1}^{p} \sigma_i^2}∑i=r+1pσi2 。如果 ΔW\Delta WΔW 的有效秩为 dintd_{\text{int}}dint,则当 r≥dintr \geq d_{\text{int}}r≥dint 时,误差很小。□\square□
11.2 低秩结构的普遍性
11.2.1 不同层的低秩程度
观察:不同层的权重矩阵具有不同的低秩程度。
定理 11.3(层间低秩差异) :设 WlW_lWl 是第 lll 层的权重,其有效秩为 reff(Wl)r_{\text{eff}}(W_l)reff(Wl)。则:
- 浅层 :reffr_{\text{eff}}reff 较大(特征提取需要高秩)
- 深层 :reffr_{\text{eff}}reff 较小(任务相关特征是低秩的)
11.2.2 不同任务的低秩程度
观察:不同任务对低秩程度的要求不同。
定理 11.4(任务复杂度与秩的关系) :设任务的内在维度为 dtaskd_{\text{task}}dtask,则微调所需的最小秩满足:
rmin=Ω(dtask)r_{\min} = \Omega(d_{\text{task}})rmin=Ω(dtask)
推论:简单任务(如情感分析)可以用更低的秩,复杂任务(如数学推理)需要更高的秩。
第十二章:神经网络的低秩偏置
12.1 训练过程中的低秩演化
12.1.1 奇异值的动态
定理 12.1(训练过程中奇异值的演化) :在梯度下降训练中,权重矩阵 WWW 的奇异值满足:
dσidt=−ησi⋅E∥∂L∂σi∥2\frac{d\sigma_i}{dt} = -\eta \sigma_i \cdot \mathbb{E}\left\\left\\\|\\frac{\\partial \\mathcal{L}}{\\partial \\sigma_i}\\right\\\|\^2\\rightdtdσi=−ησi⋅E ∂σi∂L 2
推论:梯度大的奇异值衰减快,梯度小的奇异值衰减慢。这导致奇异值谱变得"尖锐"------大奇异值保持,小奇异值衰减。
12.1.2 隐式正则化
定理 12.2(梯度下降的低秩偏置):梯度下降训练隐式地偏好低秩解------这是因为低秩解对应的损失函数景观更"平坦",更容易被梯度下降找到。
12.2 过参数化与低秩
12.2.1 过参数化的低秩效应
定理 12.3(过参数化导致低秩):当模型参数量远大于训练样本数时,训练后的权重矩阵倾向于低秩。
证明思路 :过参数化意味着 Hessian 矩阵是低秩的。梯度下降沿着 Hessian 的非零特征值方向更新,导致权重矩阵的有效秩降低。□\square□
第十三章:低秩与泛化理论
13.1 低秩约束的正则化效应
13.1.1 秩约束与泛化
定理 13.1(低秩约束的泛化界) :设模型使用秩 rrr 的低秩分解,训练样本数为 TTT,则泛化误差满足:
ELtest≤ELtrain+O(r(m+n)log(mn)T)\mathbb{E}\\mathcal{L}_{\\text{test}} \leq \mathbb{E}\\mathcal{L}_{\\text{train}} + O\left(\sqrt{\frac{r(m+n) \log(mn)}{T}}\right)ELtest≤ELtrain+O(Tr(m+n)log(mn) )
推论 :秩 rrr 越小,泛化误差上界越小------低秩约束起到正则化作用。
13.1.2 低秩与 PAC-Bayes 界
定理 13.2(低秩模型的 PAC-Bayes 界):
ELtest≤ELtrain+rlog(mn/r)+log(T/δ)2T\mathbb{E}\\mathcal{L}_{\\text{test}} \leq \mathbb{E}\\mathcal{L}_{\\text{train}} + \sqrt{\frac{r \log(mn/r) + \log(T/\delta)}{2T}}ELtest≤ELtrain+2Trlog(mn/r)+log(T/δ)
以概率 1−δ1 - \delta1−δ 成立。
13.2 低秩分解的偏差-方差权衡
13.2.1 偏差增加
定理 13.3(低秩分解的偏差) :使用秩 rrr 的低秩近似,偏差为:
Bias2=∥W−Wr∥F2=∑i=r+1pσi2\text{Bias}^2 = \|W - W_r\|F^2 = \sum{i=r+1}^{p} \sigma_i^2Bias2=∥W−Wr∥F2=i=r+1∑pσi2
13.2.2 方差减少
定理 13.4(低秩分解的方差减少):低秩分解减少了模型的有效参数量,从而减少方差:
Var∝r(m+n)T\text{Var} \propto \frac{r(m+n)}{T}Var∝Tr(m+n)
13.2.3 最优秩
定理 13.5(最优秩的偏差-方差权衡):
r∗=argminr(∑i=r+1pσi2+λ⋅r(m+n)T)r^* = \arg\min_r \left(\sum_{i=r+1}^{p} \sigma_i^2 + \lambda \cdot \frac{r(m+n)}{T}\right)r∗=argrmin(i=r+1∑pσi2+λ⋅Tr(m+n))
推论 :训练样本越多(TTT 越大),最优秩 r∗r^*r∗ 越大。
第五部分:完整可运行代码实现
第十四章:从零实现 SVD 分解与低秩近似
python
"""
SVD 分解与低秩近似的完整实现。
包含:SVD 计算、截断 SVD、误差分析。
"""
import numpy as np
from typing import Tuple
def compute_svd(W: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""计算矩阵的 SVD。
Args:
W: 输入矩阵 (m, n)
Returns:
U: 左奇异向量 (m, m)
sigma: 奇异值 (min(m,n),)
Vt: 右奇异向量的转置 (n, n)
"""
U, sigma, Vt = np.linalg.svd(W, full_matrices=True)
return U, sigma, Vt
def truncated_svd(W: np.ndarray, r: int) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""截断 SVD(最佳秩 r 近似)。
Args:
W: 输入矩阵 (m, n)
r: 目标秩
Returns:
U_r: 左奇异向量 (m, r)
sigma_r: 奇异值 (r,)
Vt_r: 右奇异向量的转置 (r, n)
"""
U, sigma, Vt = np.linalg.svd(W, full_matrices=False)
# 截断到秩 r
U_r = U[:, :r]
sigma_r = sigma[:r]
Vt_r = Vt[:r, :]
return U_r, sigma_r, Vt_r
def low_rank_approximate(W: np.ndarray, r: int) -> Tuple[np.ndarray, np.ndarray, float]:
"""低秩近似。
Args:
W: 输入矩阵 (m, n)
r: 目标秩
Returns:
W_r: 秩 r 近似矩阵 (m, n)
factors: (A, B) 使得 W_r = A @ B
error: 相对误差
"""
U_r, sigma_r, Vt_r = truncated_svd(W, r)
# 重构
W_r = U_r @ np.diag(sigma_r) @ Vt_r
# 分解为 A @ B
A = U_r @ np.diag(np.sqrt(sigma_r))
B = np.diag(np.sqrt(sigma_r)) @ Vt_r
# 计算误差
error = np.linalg.norm(W - W_r, 'fro') / np.linalg.norm(W, 'fro')
return W_r, (A, B), error
def analyze_singular_values(W: np.ndarray) -> dict:
"""分析奇异值分布。
Args:
W: 输入矩阵
Returns:
info: 奇异值分析信息
"""
_, sigma, _ = np.linalg.svd(W, full_matrices=False)
# 基本统计
total_energy = np.sum(sigma ** 2)
cumulative_energy = np.cumsum(sigma ** 2) / total_energy
# 有效秩
p = sigma / sigma.sum()
eff_rank = np.exp(-np.sum(p * np.log(np.clip(p, 1e-10, 1.0))))
# 达到不同能量比例所需的秩
ranks_for_energy = {}
for threshold in [0.9, 0.95, 0.99, 0.999]:
rank = np.searchsorted(cumulative_energy, threshold) + 1
ranks_for_energy[f"{threshold:.1%}"] = rank
return {
"singular_values": sigma,
"total_energy": total_energy,
"cumulative_energy": cumulative_energy,
"effective_rank": eff_rank,
"ranks_for_energy": ranks_for_energy,
"max_singular": sigma[0],
"min_singular": sigma[-1],
"condition_number": sigma[0] / (sigma[-1] + 1e-10),
}
def demonstrate_svd():
"""演示 SVD 分解与低秩近似。"""
np.random.seed(42)
print("=" * 70)
print("SVD 分解与低秩近似演示")
print("=" * 70)
# 创建测试矩阵
m, n = 64, 128
# 构造一个有低秩结构的矩阵
r_true = 10
U_true = np.random.randn(m, r_true)
V_true = np.random.randn(r_true, n)
W_low_rank = U_true @ V_true
# 添加噪声
noise = np.random.randn(m, n) * 0.1
W = W_low_rank + noise
print(f"\n 矩阵大小: {m}x{n}")
print(f" 真实秩: {r_true}")
print(f" 矩阵 Frobenius 范数: {np.linalg.norm(W, 'fro'):.4f}")
# 奇异值分析
print("\n 1. 奇异值分析")
print(" " + "-" * 40)
info = analyze_singular_values(W)
print(f" 最大奇异值: {info['max_singular']:.4f}")
print(f" 最小奇异值: {info['min_singular']:.6f}")
print(f" 条件数: {info['condition_number']:.2f}")
print(f" 有效秩: {info['effective_rank']:.2f}")
print(f"\n 达到不同能量比例所需的秩:")
for threshold, rank in info["ranks_for_energy"].items():
print(f" {threshold}: 秩 {rank}")
# 不同秩的近似误差
print("\n 2. 不同秩的近似误差")
print(" " + "-" * 40)
print(f" {'秩':>6} {'相对误差':>12} {'参数量':>12} {'压缩比':>10}")
print(f" {'-'*6} {'-'*12} {'-'*12} {'-'*10}")
original_params = m * n
for r in [1, 2, 5, 10, 15, 20, 30, 50]:
W_r, (A, B), error = low_rank_approximate(W, r)
params = r * (m + n)
compression = original_params / params
print(f" {r:>6} {error:>12.6f} {params:>12} {compression:>10.2f}x")
# Eckart-Young 定理验证
print("\n 3. Eckart-Young 定理验证")
print(" " + "-" * 40)
U, sigma, Vt = np.linalg.svd(W, full_matrices=False)
print(f" {'秩':>6} {'SVD 误差':>12} {'理论误差':>12} {'匹配':>8}")
print(f" {'-'*6} {'-'*12} {'-'*12} {'-'*8}")
for r in [5, 10, 15, 20]:
# SVD 近似误差
W_r, _, error_svd = low_rank_approximate(W, r)
# 理论误差
error_theory = np.sqrt(np.sum(sigma[r:] ** 2)) / np.linalg.norm(W, 'fro')
match = "✓" if abs(error_svd - error_theory) < 1e-10 else "✗"
print(f" {r:>6} {error_svd:>12.8f} {error_theory:>12.8f} {match:>8}")
if __name__ == "__main__":
demonstrate_svd()
第十五章:从零实现权重低秩分解压缩
python
"""
权重低秩分解压缩的完整实现。
包含:SVD 分解、数据感知分解、微调。
"""
import numpy as np
from typing import Tuple, List
def svd_compress(W: np.ndarray, rank: int) -> Tuple[np.ndarray, np.ndarray]:
"""SVD 低秩压缩。
Args:
W: 权重矩阵 (m, n)
rank: 目标秩
Returns:
A: (m, rank)
B: (rank, n)
"""
U, sigma, Vt = np.linalg.svd(W, full_matrices=False)
A = U[:, :rank] @ np.diag(np.sqrt(sigma[:rank]))
B = np.diag(np.sqrt(sigma[:rank])) @ Vt[:rank, :]
return A, B
def data_aware_compress(
W: np.ndarray,
X: np.ndarray,
rank: int,
) -> Tuple[np.ndarray, np.ndarray]:
"""数据感知的低秩压缩。
优先保留对输入数据影响最大的方向。
Args:
W: 权重矩阵 (m, n)
X: 输入数据 (T, n)
rank: 目标秩
Returns:
A: (m, rank)
B: (rank, n)
"""
# 计算输入协方差
H = X.T @ X / X.shape[0] # (n, n)
# 对 H 进行特征分解
eigenvalues, eigenvectors = np.linalg.eigh(H)
# H^{1/2}
H_sqrt = eigenvectors @ np.diag(np.sqrt(np.maximum(eigenvalues, 0))) @ eigenvectors.T
H_sqrt_inv = eigenvectors @ np.diag(1.0 / np.sqrt(np.maximum(eigenvalues, 1e-8))) @ eigenvectors.T
# 在 H-加权空间中进行 SVD
W_weighted = W @ H_sqrt
A, B_weighted = svd_compress(W_weighted, rank)
# 逆变换
B = H_sqrt_inv @ B_weighted.T # 实际上需要更仔细的处理
# 简化:直接在加权空间分解后逆变换
U, sigma, Vt = np.linalg.svd(W_weighted, full_matrices=False)
A = U[:, :rank] @ np.diag(np.sqrt(sigma[:rank]))
B_tilde = np.diag(np.sqrt(sigma[:rank])) @ Vt[:rank, :]
B = H_sqrt_inv @ B_tilde.T
B = B.T # 转置回来
return A, B
def finetune_low_rank(
W: np.ndarray,
X: np.ndarray,
Y: np.ndarray,
A: np.ndarray,
B: np.ndarray,
n_steps: int = 100,
lr: float = 0.001,
) -> Tuple[np.ndarray, np.ndarray, list]:
"""微调低秩分解。
Args:
W: 原始权重(冻结)
X: 输入数据
Y: 目标输出
A: 初始 A 矩阵
B: 初始 B 矩阵
n_steps: 微调步数
lr: 学习率
Returns:
A_finetuned: 微调后的 A
B_finetuned: 微调后的 B
losses: 损失历史
"""
A = A.copy()
B = B.copy()
losses = []
for step in range(n_steps):
# 前向传播
W_approx = A @ B
Y_pred = X @ W_approx.T
# 损失
loss = np.mean((Y - Y_pred) ** 2)
losses.append(loss)
# 反向传播
grad_Y = 2 / X.shape[0] * (Y_pred - Y)
grad_W = grad_Y.T @ X # (m, n)
# 对 A 和 B 的梯度
grad_A = grad_W @ B.T # (m, rank)
grad_B = A.T @ grad_W # (rank, n)
# 更新
A = A - lr * grad_A
B = B - lr * grad_B
return A, B, losses
def demonstrate_weight_compression():
"""演示权重低秩分解压缩。"""
np.random.seed(42)
print("=" * 70)
print("权重低秩分解压缩演示")
print("=" * 70)
# 创建测试数据
m, n = 128, 256
T = 500
# 权重矩阵(低秩 + 噪声)
r_true = 15
U = np.random.randn(m, r_true) * 0.5
V = np.random.randn(r_true, n) * 0.5
W = U @ V + np.random.randn(m, n) * 0.01
# 输入数据
X = np.random.randn(T, n) * 0.5
Y = X @ W.T + np.random.randn(T, m) * 0.001
# 参考输出
Y_ref = X @ W.T
print(f"\n 权重矩阵: {m}x{n}")
print(f" 真实秩: {r_true}")
print(f" 训练样本: {T}")
# 不同方法对比
print("\n 1. 不同压缩方法对比")
print(" " + "-" * 40)
print(f" {'秩':>6} {'SVD MSE':>12} {'数据感知 MSE':>15} {'微调后 MSE':>12}")
print(f" {'-'*6} {'-'*12} {'-'*15} {'-'*12}")
for rank in [5, 10, 15, 20, 30]:
# SVD 分解
A_svd, B_svd = svd_compress(W, rank)
Y_svd = X @ (A_svd @ B_svd).T
mse_svd = np.mean((Y_ref - Y_svd) ** 2)
# 数据感知分解
A_da, B_da = data_aware_compress(W, X, rank)
Y_da = X @ (A_da @ B_da).T
mse_da = np.mean((Y_ref - Y_da) ** 2)
# 微调
A_ft, B_ft, _ = finetune_low_rank(W, X, Y, A_svd, B_svd, n_steps=50, lr=0.0001)
Y_ft = X @ (A_ft @ B_ft).T
mse_ft = np.mean((Y_ref - Y_ft) ** 2)
print(f" {rank:>6} {mse_svd:>12.8f} {mse_da:>15.8f} {mse_ft:>12.8f}")
# 压缩比分析
print("\n 2. 压缩比分析")
print(" " + "-" * 40)
original_params = m * n
print(f" 原始参数量: {original_params}")
print()
for rank in [5, 10, 15, 20]:
compressed_params = rank * (m + n)
ratio = original_params / compressed_params
A, B = svd_compress(W, rank)
_, _, error = low_rank_approximate(W, rank)
print(f" 秩 {rank}: {compressed_params} 参数, "
f"压缩比 {ratio:.1f}x, 相对误差 {error:.6f}")
if __name__ == "__main__":
demonstrate_weight_compression()
第十六章:从零实现 LoRA 与 QLoRA
python
"""
LoRA 和 QLoRA 的完整实现。
包含:LoRA 层、QLoRA 量化、训练模拟。
"""
import numpy as np
from typing import Tuple, Optional
def uniform_quantize(x: np.ndarray, num_bits: int) -> Tuple[np.ndarray, float, int]:
"""均匀量化。"""
abs_max = max(np.max(np.abs(x)), 1e-8)
qmax = 2 ** (num_bits - 1) - 1
scale = abs_max / qmax
zero_point = 0
x_int = np.clip(np.round(x / scale) + zero_point, -qmax, qmax).astype(int)
x_q = (x_int - zero_point).astype(float) * scale
return x_q, scale, zero_point
class LoRALayer:
"""LoRA 层。
实现 h = Wx + (α/r) BAx
Attributes:
W: 预训练权重 (m, n),冻结
A: LoRA 矩阵 A (r, n),可训练
B: LoRA 矩阵 B (m, r),可训练
rank: LoRA 秩
alpha: 缩放因子
"""
def __init__(
self,
W: np.ndarray,
rank: int = 8,
alpha: float = 16.0,
init_scale: float = 0.01,
):
"""初始化 LoRA 层。
Args:
W: 预训练权重 (m, n)
rank: LoRA 秩
alpha: 缩放因子
init_scale: 初始化尺度
"""
m, n = W.shape
self.W = W.copy() # 冻结
self.rank = rank
self.alpha = alpha
self.scaling = alpha / rank
# 初始化 A(随机)和 B(零)
self.A = np.random.randn(rank, n) * init_scale
self.B = np.zeros((m, rank))
def forward(self, x: np.ndarray) -> np.ndarray:
"""前向传播。
Args:
x: 输入 (..., n)
Returns:
h: 输出 (..., m)
"""
# 基础前向传播
h_base = x @ self.W.T
# LoRA 更新
lora_out = (x @ self.A.T) @ self.B.T # (..., r) -> (..., m)
h_lora = self.scaling * lora_out
return h_base + h_lora
def backward(
self,
x: np.ndarray,
grad_output: np.ndarray,
) -> Tuple[np.ndarray, np.ndarray]:
"""反向传播。
Args:
x: 输入 (B, n)
grad_output: 上游梯度 (B, m)
Returns:
grad_A: 对 A 的梯度 (r, n)
grad_B: 对 B 的梯度 (m, r)
"""
B_batch = x.shape[0]
# 对 B 的梯度:∂L/∂B = (∂L/∂h) * scaling * (xA^T)^T
lora_intermediate = x @ self.A.T # (B, r)
grad_B = (grad_output.T @ lora_intermediate) * self.scaling / B_batch
# 对 A 的梯度:∂L/∂A = (∂L/∂h * B)^T * x
grad_h_lora = grad_output * self.scaling # (B, m)
grad_A = (grad_h_lora @ self.B).T @ x / B_batch
return grad_A, grad_B
def update(self, grad_A: np.ndarray, grad_B: np.ndarray, lr: float):
"""更新参数。"""
self.A = self.A - lr * grad_A
self.B = self.B - lr * grad_B
def merge(self) -> np.ndarray:
"""合并 LoRA 到原始权重。"""
return self.W + self.scaling * self.B @ self.A
class QLoRALayer:
"""QLoRA 层。
实现 h = Dequant(W_4bit) * x + (α/r) BAx
Attributes:
W_quant: 4 比特量化的权重
scale: 量化缩放因子
A: LoRA 矩阵 A (r, n)
B: LoRA 矩阵 B (m, r)
"""
def __init__(
self,
W: np.ndarray,
rank: int = 8,
alpha: float = 16.0,
quant_bits: int = 4,
init_scale: float = 0.01,
):
"""初始化 QLoRA 层。"""
m, n = W.shape
self.rank = rank
self.alpha = alpha
self.scaling = alpha / rank
self.quant_bits = quant_bits
# 量化预训练权重
self.W_quant, self.scale, self.zero_point = uniform_quantize(W, quant_bits)
# LoRA 参数
self.A = np.random.randn(rank, n) * init_scale
self.B = np.zeros((m, rank))
def dequantize(self) -> np.ndarray:
"""反量化权重。"""
return self.W_quant # 已经在 uniform_quantize 中反量化了
def forward(self, x: np.ndarray) -> np.ndarray:
"""前向传播。"""
# 量化权重的前向传播
W_deq = self.dequantize()
h_base = x @ W_deq.T
# LoRA 更新
lora_out = (x @ self.A.T) @ self.B.T
h_lora = self.scaling * lora_out
return h_base + h_lora
def backward(
self,
x: np.ndarray,
grad_output: np.ndarray,
) -> Tuple[np.ndarray, np.ndarray]:
"""反向传播(只对 LoRA 参数)。"""
B_batch = x.shape[0]
lora_intermediate = x @ self.A.T
grad_B = (grad_output.T @ lora_intermediate) * self.scaling / B_batch
grad_h_lora = grad_output * self.scaling
grad_A = (grad_h_lora @ self.B).T @ x / B_batch
return grad_A, grad_B
def update(self, grad_A: np.ndarray, grad_B: np.ndarray, lr: float):
"""更新 LoRA 参数。"""
self.A = self.A - lr * grad_A
self.B = self.B - lr * grad_B
def demonstrate_lora():
"""演示 LoRA。"""
np.random.seed(42)
print("=" * 70)
print("LoRA 与 QLoRA 演示")
print("=" * 70)
# 设置
m, n = 128, 256
T = 500
rank = 8
# 预训练权重
W = np.random.randn(m, n) * 0.02
# 训练数据
X = np.random.randn(T, n) * 0.5
Y = X @ W.T + np.random.randn(T, m) * 0.001
print(f"\n 权重矩阵: {m}x{n}")
print(f" LoRA 秩: {rank}")
print(f" 训练样本: {T}")
# LoRA 训练
print("\n 1. LoRA 训练")
print(" " + "-" * 40)
lora = LoRALayer(W, rank=rank, alpha=16.0)
lr = 0.001
n_steps = 200
losses = []
for step in range(n_steps):
# 前向传播
Y_pred = lora.forward(X)
loss = np.mean((Y_pred - Y) ** 2)
losses.append(loss)
# 反向传播
grad_output = 2 / T * (Y_pred - Y)
grad_A, grad_B = lora.backward(X, grad_output)
# 更新
lora.update(grad_A, grad_B, lr)
if (step + 1) % 50 == 0:
print(f" Step {step + 1}: loss = {loss:.8f}")
# 最终精度
Y_final = lora.forward(X)
mse_final = np.mean((Y_final - Y) ** 2)
print(f"\n 最终 MSE: {mse_final:.8f}")
# 合并后的权重误差
W_merged = lora.merge()
weight_error = np.linalg.norm(W - W_merged, 'fro') / np.linalg.norm(W, 'fro')
print(f" 权重相对误差: {weight_error:.6f}")
# 参数量分析
lora_params = rank * (m + n)
original_params = m * n
print(f"\n 原始参数量: {original_params}")
print(f" LoRA 参数量: {lora_params}")
print(f" 压缩比: {original_params / lora_params:.1f}x")
# QLoRA 对比
print("\n 2. QLoRA 对比")
print(" " + "-" * 40)
for bits in [4, 3, 2]:
qlora = QLoRALayer(W, rank=rank, alpha=16.0, quant_bits=bits)
# 微调 LoRA 部分
for step in range(200):
Y_pred = qlora.forward(X)
grad_output = 2 / T * (Y_pred - Y)
grad_A, grad_B = qlora.backward(X, grad_output)
qlora.update(grad_A, grad_B, lr)
# 评估
Y_qlora = qlora.forward(X)
mse_qlora = np.mean((Y_qlora - Y) ** 2)
# 量化误差
W_deq = qlora.dequantize()
quant_error = np.linalg.norm(W - W_deq, 'fro') / np.linalg.norm(W, 'fro')
print(f" {bits}-bit QLoRA: MSE = {mse_qlora:.8f}, 量化误差 = {quant_error:.6f}")
# 不同秩的对比
print("\n 3. 不同秩的 LoRA 对比")
print(" " + "-" * 40)
print(f" {'秩':>6} {'参数量':>10} {'压缩比':>10} {'最终 MSE':>12}")
print(f" {'-'*6} {'-'*10} {'-'*10} {'-'*12}")
for r in [1, 2, 4, 8, 16, 32]:
lora_r = LoRALayer(W, rank=r, alpha=16.0)
for step in range(200):
Y_pred = lora_r.forward(X)
grad_output = 2 / T * (Y_pred - Y)
grad_A, grad_B = lora_r.backward(X, grad_output)
lora_r.update(grad_A, grad_B, lr)
Y_r = lora_r.forward(X)
mse_r = np.mean((Y_r - Y) ** 2)
params_r = r * (m + n)
ratio_r = original_params / params_r
print(f" {r:>6} {params_r:>10} {ratio_r:>10.1f}x {mse_r:>12.8f}")
if __name__ == "__main__":
demonstrate_lora()
第十七章:完整低秩压缩 Pipeline 与精度对比
python
"""
完整的低秩压缩 Pipeline。
对比 SVD 分解、LoRA、QLoRA 等方法。
"""
import numpy as np
from typing import Tuple
def run_full_comparison():
"""运行完整的低秩方法对比。"""
np.random.seed(42)
print("=" * 70)
print("低秩压缩方法综合对比")
print("=" * 70)
# 设置
m, n = 128, 256
T = 1000
# 权重矩阵
r_true = 20
U = np.random.randn(m, r_true) * 0.5
V = np.random.randn(r_true, n) * 0.5
W = U @ V + np.random.randn(m, n) * 0.01
# 数据
X = np.random.randn(T, n) * 0.5
Y = X @ W.T + np.random.randn(T, m) * 0.001
Y_ref = X @ W.T
print(f"\n 权重: {m}x{n}, 真实秩: {r_true}")
print(f" 训练样本: {T}")
print(f" 原始参数量: {m * n}")
# 方法定义
def svd_compress(W, rank):
U, s, Vt = np.linalg.svd(W, full_matrices=False)
A = U[:, :rank] @ np.diag(np.sqrt(s[:rank]))
B = np.diag(np.sqrt(s[:rank])) @ Vt[:rank, :]
return A, B
def train_lora(W, X, Y, rank, n_steps=300, lr=0.001):
m, n = W.shape
A = np.random.randn(rank, n) * 0.01
B = np.zeros((m, rank))
scaling = 16.0 / rank
for step in range(n_steps):
W_approx = W + scaling * B @ A
Y_pred = X @ W_approx.T
grad_output = 2 / X.shape[0] * (Y_pred - Y)
grad_B = scaling * (grad_output.T @ (X @ A.T)) / X.shape[0]
grad_A = scaling * ((grad_output @ B).T @ X) / X.shape[0]
A = A - lr * grad_A
B = B - lr * grad_B
return A, B, scaling
# 测试不同秩
print(f"\n {'方法':>15} {'秩':>6} {'MSE':>15} {'参数量':>10} {'压缩比':>10}")
print(f" {'-'*15} {'-'*6} {'-'*15} {'-'*10} {'-'*10}")
for rank in [5, 10, 15, 20, 30, 50]:
# SVD 分解
A_svd, B_svd = svd_compress(W, rank)
Y_svd = X @ (A_svd @ B_svd).T
mse_svd = np.mean((Y_ref - Y_svd) ** 2)
params_svd = rank * (m + n)
ratio_svd = (m * n) / params_svd
print(f" {'SVD':>15} {rank:>6} {mse_svd:>15.10f} {params_svd:>10} {ratio_svd:>10.1f}x")
# LoRA
A_lora, B_lora, scaling = train_lora(W, X, Y, rank, n_steps=300, lr=0.001)
W_lora = W + scaling * B_lora @ A_lora
Y_lora = X @ W_lora.T
mse_lora = np.mean((Y_ref - Y_lora) ** 2)
params_lora = rank * (m + n)
print(f" {'LoRA':>15} {rank:>6} {mse_lora:>15.10f} {params_lora:>10} {'':>10}")
# 综合分析
print(f"\n 综合分析(秩 = 15):")
print(" " + "-" * 40)
rank = 15
# SVD
A_svd, B_svd = svd_compress(W, rank)
Y_svd = X @ (A_svd @ B_svd).T
mse_svd = np.mean((Y_ref - Y_svd) ** 2)
# SVD + 微调
A_ft = A_svd.copy()
B_ft = B_svd.copy()
for step in range(100):
Y_pred = X @ (A_ft @ B_ft).T
grad = 2 / T * (Y_pred - Y).T @ X
A_ft = A_ft - 0.0001 * grad @ B_ft.T
B_ft = B_ft - 0.0001 * A_ft.T @ grad
Y_ft = X @ (A_ft @ B_ft).T
mse_ft = np.mean((Y_ref - Y_ft) ** 2)
# LoRA
A_lora, B_lora, scaling = train_lora(W, X, Y, rank)
W_lora = W + scaling * B_lora @ A_lora
Y_lora = X @ W_lora.T
mse_lora = np.mean((Y_ref - Y_lora) ** 2)
print(f" SVD 分解: MSE = {mse_svd:.10f}")
print(f" SVD + 微调: MSE = {mse_ft:.10f}")
print(f" LoRA: MSE = {mse_lora:.10f}")
if __name__ == "__main__":
run_full_comparison()
附录:关键公式汇总
A.1 SVD 与低秩近似
| 公式 | 表达式 |
|---|---|
| SVD | W=UΣVTW = U \Sigma V^TW=UΣVT |
| 最佳秩 rrr 近似 | Wr=UrΣrVrTW_r = U_r \Sigma_r V_r^TWr=UrΣrVrT |
| Frobenius 误差 | ∣W−Wr∣F=∑i=r+1pσi2|W - W_r|F = \sqrt{\sum{i=r+1}^{p} \sigma_i^2}∣W−Wr∣F=∑i=r+1pσi2 |
| 谱范数误差 | ∣W−Wr∣2=σr+1|W - W_r|2 = \sigma{r+1}∣W−Wr∣2=σr+1 |
| 有效秩 | reff=exp(−∑ipilogpi)r_{\text{eff}} = \exp(-\sum_i p_i \log p_i)reff=exp(−∑ipilogpi) |
A.2 低秩分解
| 方法 | 分解形式 | 参数量 |
|---|---|---|
| SVD | W=UrΣrVrTW = U_r \Sigma_r V_r^TW=UrΣrVrT | r(m+n)+rr(m+n) + rr(m+n)+r |
| 非对称 | W≈ABW \approx ABW≈AB | r(m+n)r(m+n)r(m+n) |
| CP 分解 | T≈∑rar∘br∘cr\mathcal{T} \approx \sum_r \mathbf{a}_r \circ \mathbf{b}_r \circ \mathbf{c}_rT≈∑rar∘br∘cr | R(m+n+p)R(m+n+p)R(m+n+p) |
| Tucker | T≈G×1U×2V×3W\mathcal{T} \approx \mathcal{G} \times_1 U \times_2 V \times_3 WT≈G×1U×2V×3W | R1R2R3+mR1+nR2+pR3R_1 R_2 R_3 + mR_1 + nR_2 + pR_3R1R2R3+mR1+nR2+pR3 |
A.3 LoRA
| 公式 | 表达式 |
|---|---|
| 前向传播 | h=Wx+αrBAxh = Wx + \frac{\alpha}{r} BAxh=Wx+rαBAx |
| 参数量 | r(m+n)r(m+n)r(m+n) |
| 初始化 | A∼N(0,σ2)A \sim \mathcal{N}(0, \sigma^2)A∼N(0,σ2), B=0B = 0B=0 |
| 缩放 | scaling=α/r\text{scaling} = \alpha / rscaling=α/r |
| 合并 | W′=W+αrBAW' = W + \frac{\alpha}{r} BAW′=W+rαBA |
A.4 QLoRA
| 公式 | 表达式 |
|---|---|
| 前向传播 | h=Dequant(W4bit)⋅x+αrBAxh = \text{Dequant}(W_{4\text{bit}}) \cdot x + \frac{\alpha}{r} BAxh=Dequant(W4bit)⋅x+rαBAx |
| 量化 | W4bit=NF4-Quant(W)W_{4\text{bit}} = \text{NF4-Quant}(W)W4bit=NF4-Quant(W) |
| 双重量化 | squant=Quant(sFP32)s_{\text{quant}} = \text{Quant}(s_{\text{FP32}})squant=Quant(sFP32) |
参考文献
- Eckart, C., & Young, G. (1936). The approximation of one matrix by another of lower rank. Psychometrika.
- Mirsky, L. (1960). Symmetric gauge functions and unitarily invariant norms. The Quarterly Journal of Mathematics.
- Hu, E., et al. (2022). LoRA: Low-rank adaptation of large language models. ICLR.
- Dettmers, T., et al. (2023). QLoRA: Efficient finetuning of quantized language models. NeurIPS.
- Liu, H., et al. (2024). DoRA: Weight-decomposed low-rank adaptation. ICML.
- Zhang, Q., et al. (2023). AdaLoRA: Adaptive budget allocation for parameter-efficient fine-tuning. ICLR.
- Hayou, S., et al. (2024). LoRA+: Efficient low rank adaptation of large models. ICML.
- Wang, S., et al. (2020). Linformer: Self-attention with linear complexity. arXiv.
- Choromanski, K., et al. (2021). Rethinking attention with performers. ICLR.
- Aghajanyan, A., et al. (2021). Intrinsic dimensionality explains the effectiveness of language model fine-tuning. ACL.
- Kolda, T., & Bader, B. (2009). Tensor decompositions and applications. SIAM Review.
- Marchenko, V., & Pastur, L. (1967). Distribution of eigenvalues for some sets of random matrices. Mathematics of the USSR-Sbornik.