LLM 课程文档

LoRA (低秩自适应)

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Ask a Question Open In Colab

LoRA (低秩适应)

微调大型语言模型是一个资源密集型过程。LoRA 是一种允许我们使用少量参数微调大型语言模型的技术。它通过向注意力权重添加和优化较小的矩阵来工作,通常可将可训练参数减少约 90%。

理解 LoRA

LoRA(低秩适应)是一种参数高效的微调技术,它冻结了预训练模型的权重,并将可训练的秩分解矩阵注入到模型的层中。LoRA 不是在微调期间训练所有模型参数,而是通过低秩分解将权重更新分解为更小的矩阵,从而显著减少可训练参数的数量,同时保持模型性能。例如,当应用于 GPT-3 175B 时,与完全微调相比,LoRA 将可训练参数减少了 10,000 倍,GPU 内存需求减少了 3 倍。您可以在 LoRA 论文中阅读更多关于 LoRA 的信息。

LoRA 通过向 Transformer 层添加成对的秩分解矩阵来工作,通常侧重于注意力权重。在推理过程中,这些适配器权重可以与基础模型合并,从而不会产生额外的延迟开销。LoRA 对于将大型语言模型适应特定任务或领域特别有用,同时保持资源需求可管理。

LoRA 的主要优势

  1. 内存效率:

    • 只有适配器参数存储在 GPU 内存中
    • 基础模型权重保持冻结,并可以以较低精度加载
    • 允许在消费级 GPU 上微调大型模型
  2. 训练功能:

    • PEFT/LoRA 本机集成,设置最少
    • 支持 QLoRA(量化 LoRA),以获得更好的内存效率
  3. 适配器管理:

    • 检查点期间适配器权重保存
    • 将适配器合并回基础模型的功能

使用 PEFT 加载 LoRA 适配器

PEFT 是一个提供统一接口来加载和管理 PEFT 方法(包括 LoRA)的库。它允许您轻松加载和切换不同的 PEFT 方法,从而更轻松地尝试不同的微调技术。

适配器可以通过 load_adapter() 加载到预训练模型上,这对于尝试未合并权重的不同适配器很有用。使用 set_adapter() 函数设置活动适配器权重。要返回基础模型,您可以使用 unload() 卸载所有 LoRA 模块。这使得在不同的特定任务权重之间切换变得容易。

from peft import PeftModel, PeftConfig

config = PeftConfig.from_pretrained("ybelkada/opt-350m-lora")
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
lora_model = PeftModel.from_pretrained(model, "ybelkada/opt-350m-lora")

lora_load_adapter

使用 trl 和 SFTTrainer 微调 LLM 与 LoRA

trl 中的 SFTTrainer 通过 PEFT 库提供了与 LoRA 适配器的集成。这意味着我们可以像使用 SFT 那样微调模型,但使用 LoRA 来减少我们需要训练的参数数量。

我们将在示例中使用 PEFT 的 LoRAConfig 类。设置只需要几个配置步骤

  1. 定义 LoRA 配置(秩、alpha、dropout)
  2. 创建带有 PEFT 配置的 SFTTrainer
  3. 训练并保存适配器权重

LoRA 配置

让我们来了解一下 LoRA 配置和关键参数。

参数 描述
r (秩) 用于权重更新的低秩矩阵的维度。通常在 4-32 之间。较低的值提供更高的压缩率,但表达能力可能较弱。
lora_alpha LoRA 层的缩放因子,通常设置为秩值的 2 倍。较高的值会导致更强的适应效果。
lora_dropout LoRA 层的 dropout 概率,通常为 0.05-0.1。较高的值有助于防止训练期间过拟合。
偏差 (bias) 控制偏差项的训练。“none”、“all”或“lora_only”选项。“none”对于内存效率而言最常见。
target_modules 指定要应用 LoRA 的模型模块。可以是“all-linear”或特定模块,如“q_proj,v_proj”。更多模块可实现更大的适应性,但会增加内存使用。
实施 PEFT 方法时,从 LoRA 的小秩值(4-8)开始,并监控训练损失。使用验证集来防止过拟合,并在可能的情况下将结果与完全微调基线进行比较。不同方法的有效性可能因任务而异,因此实验是关键。

将 TRL 与 PEFT 结合使用

PEFT 方法可以与 TRL 结合用于微调,以减少内存需求。我们可以在加载模型时将 LoraConfig 传递给模型。

from peft import LoraConfig

# TODO: Configure LoRA parameters
# r: rank dimension for LoRA update matrices (smaller = more compression)
rank_dimension = 6
# lora_alpha: scaling factor for LoRA layers (higher = stronger adaptation)
lora_alpha = 8
# lora_dropout: dropout probability for LoRA layers (helps prevent overfitting)
lora_dropout = 0.05

peft_config = LoraConfig(
    r=rank_dimension,  # Rank dimension - typically between 4-32
    lora_alpha=lora_alpha,  # LoRA scaling factor - typically 2x rank
    lora_dropout=lora_dropout,  # Dropout probability for LoRA layers
    bias="none",  # Bias type for LoRA. the corresponding biases will be updated during training.
    target_modules="all-linear",  # Which modules to apply LoRA to
    task_type="CAUSAL_LM",  # Task type for model architecture
)

上面,我们使用了 device_map="auto" 来自动将模型分配到正确的设备。您也可以使用 device_map={"": device_index} 手动将模型分配到特定设备。

我们还需要使用 LoRA 配置定义 SFTTrainer

# Create SFTTrainer with LoRA configuration
trainer = SFTTrainer(
    model=model,
    args=args,
    train_dataset=dataset["train"],
    peft_config=peft_config,  # LoRA configuration
    max_seq_length=max_seq_length,  # Maximum sequence length
    processing_class=tokenizer,
)

✏️ 试一试! 在上一节微调的模型基础上,使用 LoRA 对其进行微调。使用 HuggingFaceTB/smoltalk 数据集来微调 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B 模型,使用我们上面定义的 LoRA 配置。

合并 LoRA 适配器

使用 LoRA 训练后,您可能希望将适配器权重合并回基础模型,以便于部署。这会创建一个具有组合权重的单一模型,从而无需在推理期间单独加载适配器。

合并过程需要注意内存管理和精度。由于您需要同时加载基础模型和适配器权重,因此请确保有足够的 GPU/CPU 内存可用。在 transformers 中使用 device_map="auto" 将根据您的硬件为模型找到正确的设备。

在整个过程中保持一致的精度(例如,float16),与训练期间使用的精度匹配,并以相同的格式保存合并的模型以进行部署。

合并实现

训练 LoRA 适配器后,您可以将适配器权重合并回基础模型。操作方法如下:

import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel

# 1. Load the base model
base_model = AutoModelForCausalLM.from_pretrained(
    "base_model_name", torch_dtype=torch.float16, device_map="auto"
)

# 2. Load the PEFT model with adapter
peft_model = PeftModel.from_pretrained(
    base_model, "path/to/adapter", torch_dtype=torch.float16
)

# 3. Merge adapter weights with base model
merged_model = peft_model.merge_and_unload()

如果保存的模型出现大小不一致的情况,请确保您也保存了分词器

# Save both model and tokenizer
tokenizer = AutoTokenizer.from_pretrained("base_model_name")
merged_model.save_pretrained("path/to/save/merged_model")
tokenizer.save_pretrained("path/to/save/merged_model")

✏️ 试一试! 将适配器权重合并回基础模型。使用 HuggingFaceTB/smoltalk 数据集来微调 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B 模型,使用我们上面定义的 LoRA 配置。

资源

< > 在 GitHub 上更新