重要

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

NeMo 2.0 中的 PEFT#

模型定制#

定制模型使您能够将通用的预训练 LLM 适配到特定的用例或领域。此过程产生一个微调模型,该模型受益于广泛的预训练数据,同时为特定的下游任务产生更准确的输出。模型定制通过监督微调实现,并分为两个流行的类别

  • 全参数微调,在 NeMo 中称为监督微调 (SFT)

  • 参数高效微调 (PEFT)

在 SFT 中,所有模型参数都会更新,以产生适应任务的输出。

另一方面,PEFT 调整的参数数量要少得多,这些参数被插入到基础模型中的策略位置。当使用 PEFT 进行微调时,基础模型权重保持冻结,并且仅训练适配器模块。因此,可训练参数的数量显着减少,通常少于 1%。

虽然 SFT 通常产生最佳结果,但 PEFT 方法通常可以达到几乎相同的精度,同时显着降低计算成本。随着语言模型尺寸的持续增长,PEFT 因其对训练硬件的轻量级要求而越来越受欢迎。

NeMo 2.0 支持 SFT 和两种 PEFT 方法,这些方法可以与各种基于 Transformer 的模型一起使用。

SFT

LoRA

DoRA

Baichuan 2 7B

ChatGLM 3 6B

Gemma 2B/7B

Gemma 2 9B/27B

Llama 3 8B/70B

Llama 3.1 8B/70B/405B

Mistral 7B

Mixtral 8x7B/8x22B

Nemotron 3 4B/8B

Nemotron 4 15B/22B/340B

Qwen 2 0.5B/1.5B/7B/72B

Starcoder 15B

Starcoder 2 3B/7B/15B

在此处阅读有关支持的 PEFT 方法的更多信息

在 NeMo 2.0 中运行 PEFT 训练#

以下是使用 NeMo 2.0 运行 Llama 3.2 1B 模型的简单 PEFT 训练循环的三个示例。这些示例展示了 NeMo 框架提供的不同抽象级别。一旦您按照 安装 NeMo 框架 中的说明设置好环境,您就可以运行简单的 PEFT 调整脚本。

运行 PEFT 训练的最简单方法是使用配方文件。您可以在 此处 找到支持的模型列表及其预定义的配方。

注意

先决条件:在继续之前,请按照 NeMo-Run 快速入门 中的示例,首先熟悉 NeMo-Run。

from nemo.collections import llm
import nemo_run as run

nodes = 1
gpus_per_node = 1
recipe = llm.llama32_1b.finetune_recipe(
    dir="/checkpoints/llama3.2_1b", # Path to store checkpoints
    name="llama3_lora",
    num_nodes=nodes,
    num_gpus_per_node=gpus_per_node,
    peft_scheme="lora",
)
# Note: "lora" is the default peft_scheme.
# Supported values are "lora", "dora", "none"/None (full fine-tuning)

# Override your PEFT configuration here, if needed. For example:
recipe.peft.target_modules = ["linear_qkv", "linear_proj", "linear_fc1", "linear_fc2"]
recipe.peft.dim = 16
recipe.peft.alpha = 32

# Add other overrides here
...

run.run(recipe)

您可以通过 NeMo Run CLI 使用 PEFT 配方(有关更多详细信息,请参见 此处)。LoRA 和 DoRA 注册为工厂类,因此您可以在终端中直接指定 peft=<lora/dora/none>。当您不需要覆盖默认配方中的任何配置时,这提供了一种快速简便的启动训练作业的方法。

nemo llm finetune -f llama32_1b peft=lora  # acceptable values are lora/dora/none

此示例使用 NeMo 框架 LLM 集合中的 finetune API。这是一个较低级别的 API,允许您以 Pythonic 方式布置各种配置。这使您可以最大程度地控制每个配置。

import torch
from nemo import lightning as nl
from nemo.collections import llm
from megatron.core.optimizer import OptimizerConfig

if __name__ == "__main__":
    seq_length = 2048
    global_batch_size = 16

    ## setup a finetuning dataset
    data = llm.DollyDataModule(
        seq_length=seq_length,
        global_batch_size=global_batch_size
    )

    ## initialize a small Llama model
    llama_config = llm.Llama32Config1B()
    model = llm.LlamaModel(llama_config, tokenizer=data.tokenizer)

    ## initialize the strategy
    strategy = nl.MegatronStrategy(
        tensor_model_parallel_size=1,
        pipeline_model_parallel_size=1,
        pipeline_dtype=torch.bfloat16,
    )

    ## setup the optimizer
    opt_config = OptimizerConfig(
        optimizer='adam',
        lr=1e-4,
        bf16=True,
    )
    opt = nl.MegatronOptimizerModule(config=opt_config)

    trainer = nl.Trainer(
        devices=1, ## you can change the number of devices to suit your setup
        max_steps=50,
        accelerator="gpu",
        strategy=strategy,
        plugins=nl.MegatronMixedPrecision(precision="bf16-mixed"),
    )

    nemo_logger = nl.NeMoLogger(
        log_dir="test_logdir", ## logs and checkpoints will be written here
    )

    peft = llm.peft.LoRA(dim=8, alpha=16)

    resume = nl.AutoResume(
        restore_config=nl.RestoreConfig(path="nemo://meta-llama/Llama-3.2-1B"),
    )

    # only need to import the first time script is run
    llm.import_ckpt(model, "hf://meta-llama/Llama-3.2-1B")
    llm.finetune(
        model=model,
        data=data,
        trainer=trainer,
        peft=peft,
        log=nemo_logger,
        optim=opt,
        resume=resume,
    )

在 NeMo 2.0 中运行 PEFT 推理#

llm.generate API 原生支持使用适配器进行推理。只需将完整模型的路径替换为 PEFT 检查点的路径即可。NeMo 将从检查点推断运行推理所需的所有信息,包括模型类型、适配器类型、基础模型检查点路径等。有关更多详细信息,请参见 llm.generate API。

以下是一个示例脚本

from megatron.core.inference.common_inference_params import CommonInferenceParams
import nemo.lightning as nl
from nemo.collections.llm import api

strategy = nl.MegatronStrategy(
    tensor_model_parallel_size=1,
    pipeline_model_parallel_size=1,
    context_parallel_size=1,
    sequence_parallel=False,
    setup_optimizers=False,
)

trainer = nl.Trainer(
    accelerator="gpu",
    devices=1,
    num_nodes=1,
    strategy=strategy,
    plugins=nl.MegatronMixedPrecision(
        precision="bf16-mixed",
        params_dtype=torch.bfloat16,
        pipeline_dtype=torch.bfloat16,
    ),
)
prompts = [
    "Hello, how are you?",
    "How many r's are in the word 'strawberry'?",
    "Which number is bigger? 10.119 or 10.19?",
]

if __name__ == "__main__":
    adapter_checkpoint = "/path/to/nemo_ckpt"  # a folder that contains "weights" and "context" subfolders
    results = api.generate(
        path=adapter_checkpoint,
        prompts=prompts,
        trainer=trainer,
        inference_params=CommonInferenceParams(temperature=0.1, top_k=10, num_tokens_to_generate=512),
        text_only=True,
    )

提示

适配器检查点仅包含适配器权重,而不包含基础模型权重。那么为什么我们不需要提供基础模型的路径呢?

这是因为适配器检查点还包含对其训练所用基础模型路径的引用。每个适配器检查点都必须与其训练所用的精确基础模型配对,因此对其的引用与适配器权重一起存储在 weights/adapter_metadata.json 中。

因此,如果您在不同的文件系统上与某人共享适配器检查点,则必须确保接收者将 weights/adapter_metadata.json 更新为其文件系统上的有效路径。

提示

根据模型的大小,您可能需要调整 tensor_model_parallel_sizepipeline_model_parallel_sizenum_devicesnum_nodes。如果您不确定要设置什么并行配置,则该模型的 PEFT 训练配方将提供一个良好的上限。请参见 此处 以获取配方列表。

将 LoRA 权重与基础模型合并#

当您想要在不更改模型架构的情况下运行 PEFT 推理时,我们也支持将训练后的 LoRA 权重合并回基础模型。llm.peft.merge_lora API 支持此功能。

from nemo.collections import llm

if __name__ == '__main__':
    llm.peft.merge_lora(
        lora_checkpoint_path="path/to/lora_checkpoint",
        output_path="path/to/merged_checkpoint",
    )

将 LoRA 权重导出到 Hugging Face#

llm.export_ckpt API 支持导出 LoRA 检查点,前提是为模型实现了 PEFT 导出器 (hf-peft)。要为自己的模型类实现 PEFT 导出器,请按照 Llama 中的示例进行操作。

from nemo.collections import llm

if __name__ == '__main__':
    llm.export_ckpt(
        path=Path("path/to/lora_checkpoint"),
        target="hf-peft",
        output_path=Path("path/to/output_HF_checkpoint"),
    )

请注意,Hugging Face 实现等效于 NeMo 的 CanonicalLoRA,而不是 LoRA。但是两者都可以转换为 Hugging Face 实现。在此处阅读有关差异的更多信息

探索 NeMo 2.0 中的 PEFT 设计#

如果您正在为 NeMo PEFT 开发,我们邀请您在此处阅读有关 NeMo 2.0 中 PEFT 设计的更多信息: 此处