OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  代码  ›  LoRA — 低秩适配微调方法实现

LoRA — 低秩适配微调方法实现

 
  cloud ·  None · 2 次点击  · 0 条评论  

LoRA:大语言模型的低秩自适应

本仓库包含 Python 包 loralib 的源代码,以及如何将其与 PyTorch 模型(例如 Hugging Face 中的模型)集成的多个示例。目前我们仅支持 PyTorch。有关 LoRA 的详细描述,请参阅我们的论文。

LoRA:大语言模型的低秩自适应

Edward J. Hu*, Yelong Shen*, Phillip Wallis, Zeyuan Allen-Zhu, Yuanzhi Li, Shean Wang, Lu Wang, Weizhu Chen

论文:https://arxiv.org/abs/2106.09685

视频讲解:https://www.youtube.com/watch?v=DhRoTONcyZE

2023年2月更新:LoRA 现已获得 Hugging Face 的 State-of-the-art Parameter-Efficient Fine-Tuning (PEFT) 库支持。

LoRA 通过冻结原始权重并学习一对低秩分解矩阵,来减少可训练参数的数量。这极大地降低了针对特定任务适配大语言模型时的存储需求,并且能够在部署时高效地进行任务切换,而不会引入推理延迟。LoRA 的性能也优于其他几种适配方法,包括适配器、前缀微调和全参数微调。

我们在 GLUE 基准测试上,使用 RoBERTa (Liu et al., 2019) 的 base 和 large 版本以及 DeBERTa (He et al., 2020) XXL 1.5B 模型,获得了与全参数微调相当或更优的结果,同时仅需训练和存储一小部分参数。点击下方数字可下载 RoBERTa 和 DeBERTa 的 LoRA 检查点。

RoBERTa base
全参数微调
RoBERTa base
LoRA
DeBERTa XXL
全参数微调
DeBERTa XXL
LoRA
可训练参数量 125M 0.8M 1.5B 4.7M
MNLI (m-Acc/mm-Acc) 87.6 87.5±.3/86.9±.3 91.7/91.9 91.9±.1/91.9±.2
SST2 (Acc) 94.8 95.1±.2 97.2 96.9±.2
MRPC (Acc) 90.2 89.7±.7 92.0 92.6±.6
CoLA (Matthew's Corr) 63.6 63.4±1.2 72.0 72.4±1.1
QNLI (Acc) 92.8 93.3±.3 96.0 96.0±.1
QQP (Acc) 91.9 90.8±.1 92.7 92.9±.1
RTE (Acc) 78.7 86.6±.7 93.9 94.9±.4
STSB (Pearson/Spearman Corr) 91.2 91.5±.2/91.3±.2 92.9/92.6 93.0±.2/92.9±.3
平均值 86.40 87.24 91.06 91.32

注意:要使用 LoRA 检查点,你仍然需要来自 Hugging Face 的原始预训练检查点。

全参数微调的数据取自 Liu et al. (2019)He et al. (2020)。我们包含了实验结果的置信区间。请按照 examples/NLU/ 中的说明来复现我们的结果。

在 GPT-2 上,LoRA 与全参数微调以及其他高效调优方法(如 适配器 (Houlsby et al., 2019)前缀调优 (Li and Liang, 2021))相比表现优异。我们在 E2E NLG Challenge、DART 和 WebNLG 上进行了评估:

方法 可训练参数量 E2E (BLEU) DART (BLEU) WebNLG (BLEU-U/S/A)
GPT-2 M (全参数微调) 354.92M 68.2 46.0 30.4/63.2/47.6
GPT-2 M (适配器) 0.37M 66.3 42.4 45.1/54.5/50.2
GPT-2 M (前缀调优) 0.35M 69.7 45.7 44.1/63.1/54.4
GPT-2 M (LoRA) 0.35M 70.4±.1 47.1±.2 46.7±.4/62.1±.2/55.3±.2
GPT-2 L (全参数微调) 774.03M 68.5 46.5 41.7/64.6/54.2
GPT-2 L (适配器) 0.88M 69.1±.1 45.7±.1 49.8±.0/61.1±.0/56.0±.0
GPT-2 L (前缀调优) 0.77M 70.3 46.5 47.0/64.2/56.4
GPT-2 L (LoRA) 0.77M 70.4±.1 47.5±.1 48.4±.3/64.0±.3/57.0±.1

非 LoRA 基线(GPT-2 large 上的适配器除外)取自 Li and Liang (2021)。我们包含了实验结果的置信区间。

下载 GPT-2 LoRA 检查点:
* GPT-2 Medium E2E (1.5 MB)
* GPT-2 Medium DART (1.5 MB)
* GPT-2 Medium WebNLG (1.5 MB)
* GPT-2 Large E2E (2.3 MB)
* GPT-2 Large DART (2.3 MB)
* GPT-2 Large WebNLG (2.3 MB)

请按照 examples/NLG/ 中的说明来复现我们的结果。

仓库概览

(此仓库的初始版本已存档在分支 "snapshot-9-15-2021" 中)

本仓库包含以下几个目录:
* loralib/ 包含 loralib 包的源代码,需要安装此包才能运行我们提供的示例;
* examples/NLG/ 包含使用我们的包在 GPT-2 中实现 LoRA 的示例,可用于复现论文中的结果;
* examples/NLU/ 包含使用我们的包在 RoBERTa 和 DeBERTa 中实现 LoRA 的示例,可在 GLUE 基准测试上产生有竞争力的结果;
* 查看我们如何在 GPT-2RoBERTaDeBERTa v2 中使用 loralib

快速开始

  1. 安装 loralib 非常简单:
    bash pip install loralib # 或者 # pip install git+https://github.com/microsoft/LoRA

  2. 你可以选择通过替换为 loralib 中实现的对应模块来适配某些层。目前我们支持 nn.Linearnn.Embeddingnn.Conv2d。我们还支持 MergedLinear,用于单个 nn.Linear 代表多个层的情况,例如在某些注意力 qkv 投影的实现中(更多信息请参阅附加说明)。
    ```python
    # ===== 替换前 =====
    # layer = nn.Linear(in_features, out_features)

# ===== 替换后 ======
import loralib as lora
# 添加一对秩 r=16 的低秩自适应矩阵
layer = lora.Linear(in_features, out_features, r=16)
```

  1. 在训练循环开始之前,仅将 LoRA 参数标记为可训练。
    python import loralib as lora model = BigModel() # 这将为名称中不包含字符串 "lora_" 的所有参数设置 requires_grad=False lora.mark_only_lora_as_trainable(model) # 训练循环 for batch in dataloader: ...
  2. 保存检查点时,生成一个仅包含 LoRA 参数的 state_dict
    python # ===== 替换前 ===== # torch.save(model.state_dict(), checkpoint_path) # ===== 替换后 ===== torch.save(lora.lora_state_dict(model), checkpoint_path)
  3. 使用 load_state_dict 加载检查点时,请确保设置 strict=False
    python # 首先加载预训练检查点 model.load_state_dict(torch.load('ckpt_pretrained.pt'), strict=False) # 然后加载 LoRA 检查点 model.load_state_dict(torch.load('ckpt_lora.pt'), strict=False)

现在可以像往常一样进行训练。

附加说明

  1. 虽然我们在示例中专注于一个简单而有效的设置,即仅适配 Transformer 中的 qv 投影,但 LoRA 可以应用于预训练权重的任何子集。我们鼓励你探索不同的配置,例如通过将 nn.Embedding 替换为 lora.Embedding 来适配嵌入层,和/或适配 MLP 层。很可能最优配置会因模型架构和任务的不同而有所变化。

  2. 某些 Transformer 实现使用单个 nn.Linear 作为查询、键和值的投影矩阵。如果希望限制对单个矩阵更新的秩,则必须将其拆分为三个独立的矩阵或使用 lora.MergedLinear。如果选择拆分该层,请确保相应地修改检查点。

# ===== 替换前 =====
# qkv_proj = nn.Linear(d_model, 3*d_model)
# ===== 替换后 =====
# 将其拆分(记得相应地修改预训练检查点)
q_proj = lora.Linear(d_model, d_model, r=8)
k_proj = nn.Linear(d_model, d_model)
v_proj = lora.Linear(d_model, d_model, r=8)
# 或者,使用 lora.MergedLinear(推荐)
qkv_proj = lora.MergedLinear(d_model, 3*d_model, r=8, enable_lora=[True, False, True])
  1. 与 LoRA 一起训练偏置向量可能是榨取额外任务性能的一种经济高效的方法(如果你仔细调整学习率)。虽然我们在论文中没有深入研究其效果,但我们在 lora 中使其易于尝试。你可以在调用 mark_only_lora_as_trainable 时通过传递 "all" 或 "lora_only" 给 bias= 参数来将某些偏置标记为可训练。保存检查点时,记得将相应的 bias= 参数传递给 lora_state_dict
# ===== 替换前 =====
# lora.mark_only_lora_as_trainable(model) # 不训练任何偏置向量
# ===== 替换后 =====
# 训练与我们所应用 LoRA 的模块相关的所有偏置向量
lora.mark_only_lora_as_trainable(model, bias='lora_only')
# 或者,我们可以训练模型中的 *所有* 偏置向量,包括 LayerNorm 的偏置
lora.mark_only_lora_as_trainable(model, bias='all')
# 保存检查点时,使用相同的 bias= 参数('all' 或 'lora_only')
torch.save(lora.lora_state_dict(model, bias='all'), checkpoint_path)
  1. 调用 model.eval() 将触发 LoRA 参数与相应预训练参数的合并,从而消除后续前向传递的额外延迟。再次调用 model.train() 将撤销合并。可以通过向 LoRA 层传递 merge_weights=False 来禁用此功能。

联系方式

如有任何问题,请联系我们或发布 issue。

关于 loralib 包的问题:
* Edward Hu (edward@edwardjhu.com)
* Phillip Wallis (phwallis@microsoft.com)
* Weizhu Chen (wzchen@microsoft.com)

GPT-2 示例相关问题:
* Phillip Wallis (phwallis@microsoft.com)
* Yelong Shen (yeshe@microsoft.com)

RoBERTa/DeBERTa 示例相关问题:
* Lu Wang (luw@microsoft.com)

致谢

我们按字母顺序感谢以下人员提供了宝贵的反馈:Jianfeng Gao, Jade Huang

2 次点击  ∙  0 人收藏  
登录后收藏  
目前尚无回复
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor