LoRA:低秩适配的高效参数微调方法
简介
LoRA (Low-Rank Adaptation) 是一种高效的大模型参数微调技术,通过低秩分解实现了高效参数微调,且不需要新增 speaker id。这种方法在保持模型性能的同时,大幅降低了可训练参数的数量。
核心思想
LoRA的核心思想是通过低秩矩阵分解来近似全参数微调中的权重更新。具体来说,对于预训练模型的权重矩阵,LoRA假设其更新可以用两个低秩矩阵的乘积来表示。
数学原理
以下是LoRA公式的详细数学表示:
1. 原始前向传播
\[h = W_0 x\]其中:
- $W_0 \in \mathbb{R}^{d \times k}$:预训练权重矩阵
- $x \in \mathbb{R}^k$:输入向量
- $h \in \mathbb{R}^d$:输出向量
2. 低秩适配矩阵定义
\[\Delta W = BA\]其中:
- $B \in \mathbb{R}^{d \times r}$:下投影矩阵
- $A \in \mathbb{R}^{r \times k}$:上投影矩阵
- $r \ll \min(d,k)$:低秩约束(典型值 $r=8$)
3. 带缩放因子的前向传播
\[h = W_0 x + \frac{\alpha}{r} (BA) x\]其中:
- $\alpha$:控制更新强度的超参数(通常 $\alpha=16$)
- $\frac{\alpha}{r}$:解耦缩放因子
4. 高效计算分解
\[h = W_0 x + \frac{\alpha}{r} B \underbrace{(A x)}_{\text{维度 } \mathbb{R}^r}\]计算步骤:
- 先计算 $u = A x$(复杂度 $\mathcal{O}(rk)$)
- 再计算 $v = B u$(复杂度 $\mathcal{O}(dr)$)
5. 参数初始化
\[A \sim \mathcal{N}(0,\sigma^2), \quad B = \mathbf{0}\]其中:
- $\sigma$:小常数(如 $\sigma=0.01$)
- 初始状态: $\Delta W = BA = 0$ (保持原始模型行为)
6. 训练参数更新
\[\theta_{\text{new}} = \theta_{\text{old}} - \eta \nabla_\theta \mathcal{L} \quad \text{其中} \quad \theta = \{A,B\}\]其中:
- $\eta$:学习率
- $\mathcal{L}$:损失函数
- 冻结 $W_0$,仅更新 $A,B$
参数效率对比
7. 参数效率分析
原始微调参数量:
\(\mathcal{O}(dk)\)
LoRA参数量:
\(\mathcal{O}(r(d + k))\)
效率提升示例: 当 $r=8, d=1024, k=1024$ 时:
- 原始参数: $1.05 \times 10^6$
- LoRA参数: $16,384$ (减少 $98.4\%$)
实现方法
8. 使用 Hugging Face PEFT 的最简实践
class LoRALinear(nn.Module):
def __init__(self, base: nn.Linear, r=8, alpha=32):
super().__init__()
self.base = base # frozen
for p in self.base.parameters():
p.requires_grad_(False)
self.A = nn.Parameter(torch.randn(r, base.in_features) * 0.01)
self.B = nn.Parameter(torch.zeros(base.out_features, r))
self.scaling = alpha / r
def forward(self, x):
# 表示矩阵乘法
return self.base(x) + self.scaling * F.linear(x, self.B @ self.A)
实用技巧
模型部署优化
如何 merge 以便部署?
weight += scaling * (B @ A)
# 然后删除 adapter
多任务场景
多任务场景如何热插拔?
- 运行时加载不同 (A,B)
- 或用 Router 把 rank 拆块做 Mixture-of-Adapters
总结
LoRA通过巧妙的低秩分解设计,在保持模型性能的同时显著降低了参数微调的计算和存储成本。这种方法特别适用于大模型的领域适配和多任务学习场景,已成为当前参数高效微调的主流方法之一。