重要提示

您正在查看 NeMo 2.0 文档。此版本对 API 和新库 NeMo Run 进行了重大更改。我们目前正在将 NeMo 1.0 的所有功能移植到 2.0。有关先前版本或 2.0 中尚不可用的功能的文档,请参阅 NeMo 24.07 文档

参数高效微调 (PEFT)#

NeMo 2.0 引入了参数高效微调 (PEFT) 的全面改革。新设计将 PEFT 制定为模型转换,该转换冻结基础模型并在模型内的特定位置插入可训练的适配器。

以下部分描述了类对象的层次结构。

graph LR A(LoRA) -->B(PEFT) B --> C(ModelTransform) C --> D(lightning.Callback) E("... \n(其他 PEFT\n 方法)") --> B G("... \n(其他模型 \n自定义)") --> C

ModelTransform 类#

PEFT 的支柱是模型转换机制,它是一个 PyTorch Lightning 回调,可在拟合或验证开始时改变模型架构。

此回调旨在在拟合或验证开始时(而不是在首次初始化模型时)将转换函数应用于模型。此设计允许先加载原始检查点,然后应用转换,这对于 PEFT 等技术特别有用。

转换函数应在 LightningModule 上定义为名为 model_transform 的属性。

除了 PEFT 之外,模型转换还允许对模型进行其他自定义,而无需修改或复制 Megatron Core 中的 PyTorch 模型源代码。以下是一些示例

  • 使用带有输出缩放的自定义嵌入层(例如 Gemma 模型)。

  • 使用带有 logits 软上限的自定义注意力层(例如 Gemma 2 模型)。

  • 向输出添加分类或嵌入头。

PEFT 类#

PEFT 类定义了一个接口,该接口具有所有 PEFT 方法通用的功能,例如

  • 冻结基础模型权重。

  • 仅将可训练权重保存到检查点。

  • 在推理时加载两个检查点(基础模型和适配器)。

此外,PEFT 类使用 NeMo 2.0 API 的 walk 函数应用转换。这会递归地迭代模型中的所有模块,并将某些模块替换为用户定义的模块。替换标准可以基于模块名称、模块前缀或模块索引。

因此,不应直接使用 PEFT 类,而应使用实现 transform() 抽象方法的特定方法对其进行子类化。

LoRA 类(或任何其他 PEFT 方法)#

例如,LoRA 转换函数将线性层替换为“LoRA 线性”层,该层具有并行计算路径来计算适配器输出(用作线性层的低秩更新)。这个“LoRA 线性”层(称为 AdapterParallelAdd)在 NeMo 2.0 中为每种 PEFT 方法单独定义。

为了确定是否应在给定模块上进行替换,LoRA 转换函数将当前模块名称target_modules列表进行比较。默认情况下,此列表包括 Transformer 层中的所有四个线性模块。

除了转换函数之外,LoRA 类还充当数据类,其中包含与 LoRA 相关的配置,例如 target_modules 列表、LoRA 维度、LoRA dropout 概率等。

设置 LoRA 训练运行#

例如,以下是如何设置 LoRA 训练运行。

  1. 首先,指定您要运行的 LoRA 配置,例如适配器的秩、要应用 LoRA 的目标线性层、任何 dropout 等。

from nemo.collections import llm
lora = llm.peft.LoRA(target_modules=['linear_qkv', 'linear_proj'], dim=32, dropout=0.0)
  1. 然后,将初始化的 lora 对象作为 ModelTransform 回调传递到模型和训练器中

model = llm.Mistral7BModel(model_transform=lora)
trainer = nl.Trainer(..., callbacks=[lora])

您现在可以启动 LoRA 训练了!

trainer.fit(model, data)