关于LoRA必须知道的知识点

LoRA(Low-Rank Adaptation)的主要思想是节约微调时需要调整的参数量,LoRA思想中使用两个低秩的矩阵来替代原需要微调的参数矩阵,假设原参数矩阵的维度为 W ∈ R ( M × N ) W \in R(M\times N) WR(M×N) , 那么可以使用两个秩为 r ( r ≪ m i n ( M , N ) ) r(r\ll min(M,N)) r(rmin(M,N))的矩阵进行表示 A ∈ R ( M × r ) , B ∈ R ( r × N ) A\in R(M\times r), B\in R(r\times N) AR(M×r),BR(r×N), 则 Δ W = A ⋅ B \Delta W=A\cdot B ΔW=AB

那么该如何初始化两个低秩矩阵呢?

在原始 LoRA 论文和主流实现中,两个矩阵的初始化方式如下:

1. 矩阵 A 的初始化

高斯分布初始化(Gaussian initialization)

  • A 使用均值为 0,标准差为 1 / r 1/\sqrt r 1/r 的高斯分布随机初始化
  • 数学表达式: A ∽ N ( 0 , 1 / r ) A \backsim N(0, 1/r) AN(0,1/r)
A = torch.nn.init.normal_(torch.empty(M, R), mean=0, std=1.0 / math.sqrt(R))

这种初始化方式遵循 He 初始化的思想,有助于在前向传播过程中保持方差稳定。

2. 矩阵 B 的初始化

零初始化(Zero initialization)

  • B 初始化为全零矩阵
  • 数学表达式:B = 0
B = torch.zeros(R, N)

为什么这样初始化?

这种初始化组合有几个重要的优点:

1. 训练初期保持原模型行为

由于 B 初始化为零矩阵,在训练开始时:

  • ΔW = A·B = A·0 = 0
  • 这意味着微调开始时,模型的行为与原预训练模型完全相同
  • 微调过程可以被视为从预训练模型平滑过渡的过程

2. 稳定的训练过程

  • A 使用缩放的高斯分布初始化,有助于保持梯度和激活值的方差稳定
  • B 的零初始化避免了训练初期引入随机噪声
  • 这种组合使得训练过程更加稳定,减少了发散的风险

3. 有效的梯度流动

  • 尽管 B 初始化为零,但由于 A 非零,梯度仍然可以有效地流过这些参数
  • 这种设计使得模型可以从预训练权重开始,逐渐学习必要的适应性变化

代码实现示例

以下是 LoRA 矩阵初始化的 PyTorch 实现示例:

import torch
import math

class LoRALayer(torch.nn.Module):
    def __init__(self, in_features, out_features, rank=4, alpha=1.0):
        super().__init__()
        self.rank = rank
        self.alpha = alpha
        self.scaling = alpha / rank
        
        # 创建 A 矩阵 (M x R)
        self.A = torch.nn.Parameter(torch.empty(in_features, rank))
        # 创建 B 矩阵 (R x N)
        self.B = torch.nn.Parameter(torch.empty(rank, out_features))
        
        # 初始化
        self.reset_parameters()
        
    def reset_parameters(self):
        # A 初始化为高斯分布
        torch.nn.init.normal_(self.A, mean=0, std=1.0 / math.sqrt(self.rank))
        # B 初始化为零
        torch.nn.init.zeros_(self.B)
        
    def forward(self, x):
        # LoRA 适配: x @ (A @ B) * scaling
        return (x @ self.A @ self.B) * self.scaling

LoRA 的变体初始化方法

除了标准初始化方法外,还有一些变体和改进:

1. 使用 α 缩放因子

在许多 LoRA 实现中,会引入一个额外的缩放因子 α:

  • 更新公式变为:ΔW = (α/R)·A·B
  • 其中 α 是一个超参数,通常设置为 R 的倍数(如 α=R 或 α=2R)
  • 这样可以控制 LoRA 更新的大小,而不改变初始化方差
# 应用缩放因子
delta_w = (alpha / R) * (A @ B)

2. SVD 初始化

一些研究提出使用奇异值分解(SVD)来初始化 LoRA 矩阵:

  • 对预训练权重的变化估计进行 SVD: Δ W _ e s t ≈ U ⋅ Σ ⋅ V T ΔW\_est ≈ U·Σ·V^T ΔW_estUΣVT
  • 取前 R 个奇异值和对应的奇异向量
  • 设置 A = U ⋅ Σ ( 1 / 2 ) A = U·Σ^{(1/2)} A=UΣ(1/2) B = Σ ( 1 / 2 ) ⋅ V T B = Σ^{(1/2)}·V^T B=Σ(1/2)VT

这种方法可能在某些任务上提供更好的起点,但计算成本更高。

3. 任务特定初始化

根据特定任务的需求调整初始化:

  • 对于某些任务,可能希望一开始就有非零的 ΔW
  • 可以根据任务先验知识初始化 B 为非零值
  • 或者使用小规模任务特定数据预训练 LoRA 参数

不同框架中的实现

1. Hugging Face PEFT 库

在 Hugging Face 的 PEFT(Parameter-Efficient Fine-Tuning)库中,LoRA 的初始化遵循标准方法:

# 来自 PEFT 库的简化代码
def reset_lora_parameters(self, adapter_name):
    if adapter_name in self.lora_A:
        # 初始化 A 为高斯分布
        nn.init.normal_(self.lora_A[adapter_name].weight, mean=0, std=1 / self.r)
        # 初始化 B 为零
        nn.init.zeros_(self.lora_B[adapter_name].weight)

2. Microsoft LoRA 实现

微软的原始 LoRA 实现也使用相同的初始化策略:

# 来自 Microsoft LoRA 的简化代码
def reset_parameters(self):
    torch.nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5))
    torch.nn.init.zeros_(self.lora_B)

实践建议

  1. 保持标准初始化:在大多数情况下,A 使用高斯初始化、B 使用零初始化是最佳选择
  2. 调整 R 和 α
    • 增大 R 可以提高模型容量,但会增加参数量
    • 调整 α 可以控制 LoRA 更新的幅度,而不改变初始化方差
  3. 特定层的差异化处理
    • 对不同层使用不同的 R 值(如注意力层和 MLP 层)
    • 对关键层使用更大的 R 值
  4. 监控训练稳定性
    • 如果训练不稳定,可以尝试降低学习率或 α 值
    • 确保梯度裁剪以防止梯度爆炸

实践场景

Stable Diffusion,LLM 等
在这里插入图片描述

总结

LoRA 矩阵的标准初始化方式是:

  • 矩阵 A:使用均值为 0,标准差为 1 / r 1/\sqrt r 1/r 的高斯分布初始化
  • 矩阵 B:初始化为全零矩阵

这种初始化组合确保了:

  1. 训练开始时模型行为与原预训练模型一致(因为 ΔW = A·B = 0)
  2. 训练过程稳定,避免了随机噪声
  3. 梯度可以有效流动,使模型能够逐渐学习必要的适应性变化

通过这种设计,LoRA 能够在极少量参数的情况下有效适应下游任务,同时保持训练的稳定性和效率。

参考资料

  • https://arxiv.org/pdf/2106.09685

关注公众号,持续更新:北北文的自留地

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北北文

同为爱码士,咋能不打赏一下呢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值