菜单

微调技术

相关源文件

微调技术可以以最小的计算资源将预训练语言模型适应于特定任务或领域。本页重点介绍低秩适配(LoRA)的实现,这是一种参数高效的微调方法,位于 labml_nn 存储库中。

概述

传统上,微调大型语言模型需要大量的计算资源,因为需要更新所有模型参数。LoRA 等参数高效微调方法通过仅训练一小部分参数并将原始模型权重冻结大部分来减少此计算负担。

来源: labml_nn/lora/__init__.py1-22 labml_nn/lora/experiment.py1-12

低秩适应 (LoRA)

LoRA,在论文 LoRA: Low-Rank Adaptation of Large Language Models 中提出,通过向冻结的预训练权重添加可训练的低秩矩阵来实现。

数学公式

如果我们有一个预训练的权重矩阵 $W_0 \in \mathbb{R}^{d \times k}$,LoRA 将更新参数化为

$W_0 + \Delta W = W_0 + BA$

其中

  • $B \in \mathbb{R}^{d \times r}$ 和 $A \in \mathbb{R}^{r \times k}$
  • 秩 $r \ll \min(d, k)$
  • 仅训练参数 $A$ 和 $B$;$W_0$ 保持冻结
  • 训练开始时,$\Delta W$ 初始化为零
  • 输出乘以因子 $\alpha/r$ 进行缩放

来源: labml_nn/lora/__init__.py28-45

关键组件

该实现包括两种主要的 LoRA 模块类型

  1. LoRA 线性层:用 LoRA 增强版本替换标准线性层
  2. LoRA Embedding 层:将相同的概念应用于 embedding 层

两个模块都维护原始冻结权重,同时添加可训练的低秩矩阵。

来源: labml_nn/lora/__init__.py28-151

实现细节

LoRA 线性层

Linear 类通过添加低秩适配来替换标准的线性层

主要实现细节

  1. 原始权重矩阵(self.weight)通过 requires_grad = False 保持冻结
  2. 两个可训练矩阵 lora_alora_b 构成了低秩分解
  3. 初始化时,lora_b 被设置为零,以便 $\Delta W = BA$ 最初为零
  4. 前向传播计算: result = nn.functional.linear(x, self.weight) + (x @ self.lora_a.T @ self.lora_b.T) * self.scaling

来源: labml_nn/lora/__init__.py28-98

LoRA Embedding 层

Embedding 类将相同的概念应用于 embedding 层

主要实现细节

  1. 原始 embedding 权重被冻结
  2. 在前向传播中,它计算: result = nn.functional.embedding(x, self.weight) + (nn.functional.embedding(x, self.lora_a.T) @ self.lora_b.T) * self.scaling

来源: labml_nn/lora/__init__.py101-151

与模型集成:GPT-2 示例

该存储库在 GPTModel 类中演示了 LoRA 与 GPT-2 的集成

集成用 LoRA 启用版本替换了标准的 PyTorch 层

  1. Token 和位置 embedding 使用带 LoRA 的 Embedding
  2. 注意力机制中的所有线性投影均使用带 LoRA 的 Linear
  3. 前馈网络层使用带 LoRA 的 Linear
  4. 最终的语言模型头使用带 LoRA 的 Linear

来源: labml_nn/lora/gpt2.py19-192

微调流程

微调过程涉及几个步骤

1. 模型初始化

Trainer 类使用 LoRA 层初始化 GPT-2 模型

来源: labml_nn/lora/experiment.py119-136

2. 加载预训练权重

_load_pretrained_weights 方法从 HuggingFace 加载预训练的 GPT-2 权重

  1. 使用 AutoModelForCausalLM.from_pretrained("gpt2") 加载原始模型
  2. 将 HuggingFace 格式的参数映射到自定义实现
  3. 使用 strict=False 加载权重,允许缺失 LoRA 参数
  4. 验证只有 LoRA 参数未从预训练模型加载

来源: labml_nn/lora/experiment.py64-117

3. 训练循环

Trainer 类中的 run 方法处理训练循环

  1. 对于每个批次,将输入 token 通过模型进行处理
  2. 计算交叉熵损失
  3. 执行反向传播和优化器步骤
  4. 由于原始权重被冻结,只有 LoRA 参数接收梯度更新

来源: labml_nn/lora/experiment.py143-169

4. 优化器配置

使用 Adam 优化器,并具有可配置的学习率,仅优化可训练的 LoRA 参数

来源: labml_nn/lora/experiment.py138

配置选项

该实现提供了几个可配置参数

参数描述默认值
lora_rLoRA 矩阵的秩32
d_model模型 embedding 维度768 (GPT-2)
n_layersTransformer 层数12 (GPT-2)
n_heads注意力头的数量12 (GPT-2)
learning_rate优化器的学习率1e-4
batch_size训练批次大小32
epochs训练轮数10

来源: labml_nn/lora/experiment.py32-49

使用示例

experiment.ipynb 笔记本中提供了使用 LoRA 微调 GPT-2 的完整示例

  1. 安装库: pip install labml-nn
  2. 导入 Trainer
  3. 创建和配置实验
  4. 初始化模型并进行训练

来源: labml_nn/lora/experiment.ipynb1-74

LoRA 的优势

  1. 参数效率:显著减少了可训练参数的数量

    • 对于 GPT-2(1.24 亿参数),r=32 时,LoRA 仅增加了约 400 万可训练参数
  2. 内存效率:训练时需要的 GPU 内存更少

    • 原始权重不需要梯度存储
  3. 训练稳定性:通常能实现更稳定的微调

  4. 模型组合:可以组合或切换多个 LoRA 适配

来源: labml_nn/lora/__init__.py1-22 labml_nn/lora/experiment.py1-12

与其他微调技术的比较

LoRA 在其他微调方法方面具有多项优势

技术参数效率训练稳定性实现复杂度
全微调中等
LoRA中等
Adapter Layers中等中等中等
Prompt Tuning非常高

该存储库目前侧重于 LoRA,但可以在相同的架构内改编为其他技术。

结论

此存储库中的 LoRA 实现为微调 GPT-2 等大型语言模型提供了一种有效的方法。通过添加可训练的低秩矩阵同时保持原始权重冻结,它显著降低了计算要求,同时保持了模型性能。

未来的扩展可以包括其他参数高效的微调技术或与更多模型架构的集成。

来源: labml_nn/lora/__init__.py labml_nn/lora/experiment.py labml_nn/lora/gpt2.py