LoRA 的核心思想是用低秩矩阵分解来建模参数的变化,而不是直接调整整个权重矩阵。这种方法通过减少微调的参数数量来提高训练效率。
假设预训练模型的某一层权重为 ( W \in \mathbb{R}^{d \times k} ),LoRA 的调整方式是:
[ W’ = W + \Delta W ]
其中 ( \Delta W ) 是调整后的权重变化。
LoRA 假设权重变化 ( \Delta W ) 的秩较低,可以表示为两个低秩矩阵的乘积:
[ \Delta W = A \times B ]
其中:
在训练时,仅更新 ( A ) 和 ( B ) 的参数,( W ) 保持冻结,极大地减少了训练参数。
以下是一个使用 PyTorch 实现 LoRA 的示例,应用于简单的线性层。
import torch
import torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, in_features, out_features, r=4, alpha=1.0):
super(LoRALinear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.r = r # 低秩矩阵的秩
self.alpha = alpha # 调节因子
# 原始权重矩阵,冻结不更新
self.weight = nn.Parameter(torch.randn(out_features, in_features))
self.weight.requires_grad = False
# LoRA 的可训练部分
self.A = nn.Parameter(torch.randn(out_features, r)) # 低秩矩阵 A
self.B = nn.Parameter(torch.randn(r, in_features)) # 低秩矩阵 B
# 调整 LoRA 更新的缩放比例
self.scaling = alpha / r
def forward(self, x):
# 原始权重加上低秩变化
delta_W = torch.matmul(self.A, self.B) * self.scaling
W_eff = self.weight + delta_W
return torch.matmul(x, W_eff.T)
以下展示如何使用 LoRALinear
模块,并验证其有效性。
# 输入维度、输出维度和低秩矩阵的秩
in_features = 16
out_features = 32
rank = 4
# 定义 LoRA 线性层
lora_layer = LoRALinear(in_features, out_features, r=rank, alpha=2.0)
# 创建输入数据
x = torch.randn(8, in_features) # Batch size = 8
# 前向传播
output = lora_layer(x)
print("输出维度:", output.shape)
以下比较微调参数数量:
# 全参数线性层
full_linear = nn.Linear(in_features, out_features)
# LoRA 线性层
lora_linear = LoRALinear(in_features, out_features, r=rank)
# 参数数量对比
print("全参数线性层的参数数量:", sum(p.numel() for p in full_linear.parameters()))
print("LoRA 微调的参数数量:", sum(p.numel() for p in lora_linear.parameters() if p.requires_grad))
假设 ( \text{in_features} = 16 )、( \text{out_features} = 32 )、( \text{rank} = 4 ):
LoRA 大幅减少了需要训练的参数,尤其是在大模型中,这种差距会更明显。
集成到预训练模型中
在 Transformer 等架构的注意力层中,插入 LoRA 模块用于调整权重变化。
调节参数规模
通过调整 ( r )(低秩矩阵的秩)来权衡性能与效率。
与其他 PEFT 方法结合
LoRA 可以与 Adapter、Prompt Tuning 等方法结合,进一步提高效率。