TRL documentation

PEFT 集成

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

PEFT 集成

TRL 支持 PEFT(参数高效微调)方法,以实现内存高效的模型训练。PEFT 通过仅训练少量额外参数并保持基础模型冻结,从而实现对大型语言模型的微调,显著降低了计算成本和内存需求。

本指南介绍了如何将 PEFT 与不同的 TRL 训练器配合使用,包括 LoRA、QLoRA 和提示调优技术。

完整的可运行示例,请参阅 SFT with LoRA/QLoRA notebook。

安装

要在 TRL 中使用 PEFT,请安装所需的依赖项:

pip install trl[peft]

如需支持 QLoRA(4 位和 8 位量化),请同时安装:

pip install bitsandbytes

快速入门

所有 TRL 训练器都通过 peft_config 参数支持 PEFT。启用 PEFT 最简单的方法是使用命令行界面并加上 --use_peft 标志:

python trl/scripts/sft.py \
    --model_name_or_path Qwen/Qwen2-0.5B \
    --dataset_name trl-lib/Capybara \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16 \
    --output_dir Qwen2-0.5B-SFT-LoRA

或者,您可以在 Python 代码中直接传入 PEFT 配置:

from peft import LoraConfig
from trl import SFTTrainer

# Configure LoRA
peft_config = LoraConfig(
    r=32,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# Configure training - note the higher learning rate for LoRA (10x base rate)
training_args = SFTConfig(
    learning_rate=2.0e-4,  # 10x the base rate (2.0e-5) for LoRA
    ...
)

# Create trainer with PEFT
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=peft_config,
)

配置 PEFT 的三种方式

TRL 提供了三种不同的方法来配置 PEFT,每种方法都适用于不同的使用场景:

1. 使用 CLI 标志(最简单)

启用 PEFT 最简单的方法是在命令行界面中使用 --use_peft 标志。此方法非常适合快速实验和标准配置:

python trl/scripts/sft.py \
    --model_name_or_path Qwen/Qwen2-0.5B \
    --dataset_name trl-lib/Capybara \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16 \
    --lora_dropout 0.05 \
    --output_dir Qwen2-0.5B-SFT-LoRA

优点:快速设置,无需编写代码

缺点:仅限于 LoRA,自定义选项较少

2. 将 peft_config 传递给 Trainer(推荐)

如需更多控制,请将 PEFT 配置直接传递给 trainer。这是大多数使用场景下的推荐方法:

from peft import LoraConfig
from trl import SFTConfig, SFTTrainer

peft_config = LoraConfig(
    r=32,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
)

trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    peft_config=peft_config,  # Pass config here
)

优点:完全可控,支持所有 PEFT 方法(LoRA、Prompt Tuning 等)

缺点:需要 Python 代码

3. 将 PEFT 直接应用于模型(高级)

为了获得最大的灵活性,您可以在将模型传递给训练器之前,先对模型应用 PEFT:

from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
from trl import SFTConfig, SFTTrainer

# Load base model
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B")

# Apply PEFT configuration
peft_config = LoraConfig(
    r=32,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)
model = get_peft_model(model, peft_config)

# Pass PEFT-wrapped model to trainer
trainer = SFTTrainer(
    model=model,  # Already has PEFT applied
    args=training_args,
    train_dataset=dataset,
    # Note: no peft_config needed here
)

优点:控制力最强,适用于自定义模型架构或复杂配置

缺点:代码更冗长,需要理解 PEFT 的内部机制

学习率考量

在使用 LoRA 或其他 PEFT 方法时,与全量微调相比,你通常需要使用更高的学习率(大约 10 倍)。这是因为 PEFT 方法仅训练一小部分参数,需要更大的学习率才能实现类似的参数更新。

推荐的学习率:

Trainer全量微调使用 LoRA(10 倍)
SFT2.0e-52.0e-4
DPO5.0e-75.0e-6
GRPO1.0e-61.0e-5
提示词调整N/A1.0e-2 到 3.0e-2

为什么是 10 倍? LoRA 适配器的可训练参数远少于完整模型。更高的学习率可以弥补这种参数数量的减少,从而确保有效的训练。有关详细说明,请参阅这篇博客文章。

有关有效使用 LoRA 的更多最佳实践,请参阅 LoRA Without Regret 文档。

使用不同训练器的 PEFT

TRL 的训练器支持各种训练范式的 PEFT 配置。以下是每个主要训练器的详细示例。

sft
dpo
grpo

监督微调(SFT)

SFTTrainer 用于在指令数据集上进行监督微调。

使用 LoRA

python trl/scripts/sft.py \
    --model_name_or_path Qwen/Qwen2-0.5B \
    --dataset_name trl-lib/Capybara \
    --learning_rate 2.0e-4 \
    --num_train_epochs 1 \
    --per_device_train_batch_size 2 \
    --gradient_accumulation_steps 8 \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16 \
    --output_dir Qwen2-0.5B-SFT-LoRA

Python 示例

from peft import LoraConfig
from trl import SFTConfig, SFTTrainer

# Configure LoRA
peft_config = LoraConfig(
    r=32,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=["q_proj", "v_proj"],  # optional: specify target modules
)

# Configure training with higher learning rate for LoRA
training_args = SFTConfig(
    learning_rate=2.0e-4,  # 10x the base rate for LoRA
    ...
)

# Create trainer with PEFT config
trainer = SFTTrainer(
    model="Qwen/Qwen2-0.5B",  # can pass model name or loaded model
    args=training_args,
    train_dataset=dataset,
    peft_config=peft_config,  # pass PEFT config here
)
trainer.train()

QLoRA:量化低秩适应

QLoRA 将 4 位量化与 LoRA 相结合,使得在消费级硬件上微调超大模型成为可能。与标准 LoRA 相比,该技术可将内存需求降低多达 4 倍。

QLoRA 的工作原理

  1. 4 位量化:使用 bitsandbytes 以 4 位精度加载基础模型
  2. 冻结权重:量化模型的权重在训练过程中保持冻结
  3. LoRA 适配器:仅以更高精度训练 LoRA 适配器参数
  4. 内存效率:支持在单个消费级 GPU 上微调 Llama-70B 等模型

使用 QLoRA 与 TRL

只需将 load_in_4bit=True 与 PEFT 配置结合使用即可:

命令行

python trl/scripts/sft.py \
    --model_name_or_path meta-llama/Llama-2-7b-hf \
    --dataset_name trl-lib/Capybara \
    --load_in_4bit \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16 \
    --per_device_train_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --output_dir Llama-2-7b-QLoRA

Python 示例

将 quantization_config 与 peft_config 一起直接传递给 trainer——trainer 会为您加载并量化模型。SFTTrainer、DPOTrainer、GRPOTrainer 和 RLOOTrainer 也提供相同的 quantization_config 参数。

import torch

from peft import LoraConfig
from transformers import BitsAndBytesConfig
from trl import SFTConfig, SFTTrainer

# Configure 4-bit quantization
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

# Configure LoRA
peft_config = LoraConfig(
    r=32,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# Configure training with higher learning rate for LoRA
training_args = SFTConfig(
    learning_rate=2.0e-4,  # 10x the base rate for QLoRA
    ...
)

# Create trainer with quantization and PEFT config
trainer = SFTTrainer(
    model="meta-llama/Llama-2-7b-hf",
    args=training_args,
    train_dataset=dataset,
    quantization_config=bnb_config,
    peft_config=peft_config,
)

trainer.train()

QLoRA 配置选项

BitsAndBytesConfig 提供了多个选项以优化内存和性能:

import torch

from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",  # or "fp4"
    bnb_4bit_compute_dtype=torch.bfloat16,  # Compute dtype for 4-bit base models
    bnb_4bit_use_double_quant=True,  # Nested quantization for additional memory savings
)

配置参数:

  • bnb_4bit_quant_type:量化数据类型("nf4" 或 "fp4")。建议使用 NF4。
  • bnb_4bit_compute_dtype:用于计算的 dtype。使用 bfloat16 以获得更好的训练稳定性。
  • bnb_4bit_use_double_quant:启用嵌套量化,以额外节省每个参数约 0.4 位。

8 位量化

若需以牺牲部分内存节省为代价换取略高的精度,您可以使用 8 位量化:

from transformers import BitsAndBytesConfig, AutoModelForCausalLM

bnb_config = BitsAndBytesConfig(load_in_8bit=True)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-2-7b-hf",
    quantization_config=bnb_config,
    device_map="auto",
)

或通过命令行:

python trl/scripts/sft.py \
    --model_name_or_path meta-llama/Llama-2-7b-hf \
    --load_in_8bit \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16

预量化检查点

部分检查点以量化形式发布,例如 gpt-oss 采用 MXFP4,或 Mistral Medium 3.5 采用 FP8。这些权重无法就地训练,因此当通过名称传入此类检查点时,训练器会以反量化形式加载它,无论是否提供 peft_config。随后,模型将占用其反量化权重所需的内存,例如 gpt-oss-20b 在 bfloat16 下约为 42 GB,而其 MXFP4 检查点仅为 13 GB。要在 bfloat16 下加载它,与其他模型一样:

from trl import SFTConfig

training_args = SFTConfig(model_init_kwargs={"dtype": "bfloat16"})

FP8 检查点需要 transformers 5.0.0 或更高版本。

提示词调整

Prompt tuning 是另一种 PEFT 技术,它学习附加在输入前面的软提示(连续嵌入),同时保持整个模型冻结。这对于大型模型尤其有效。

Prompt Tuning 的工作原理

  1. 虚拟令牌:向输入添加可学习的连续嵌入(虚拟令牌)
  2. 冻结模型:整个基础模型保持冻结
  3. 特定任务提示:每个任务学习自己的提示嵌入
  4. 极致高效:仅训练提示嵌入(通常为 8-20 个 token)

使用 TRL 进行 Prompt Tuning

from peft import PromptTuningConfig, PromptTuningInit, TaskType
from trl import SFTConfig, SFTTrainer

# Configure Prompt Tuning
peft_config = PromptTuningConfig(
    task_type=TaskType.CAUSAL_LM,
    prompt_tuning_init=PromptTuningInit.TEXT,
    num_virtual_tokens=8,
    prompt_tuning_init_text="Classify if the tweet is a complaint or not:",
    tokenizer_name_or_path="Qwen/Qwen2-0.5B",
)

# Configure training with higher learning rate for Prompt Tuning
training_args = SFTConfig(
    learning_rate=2.0e-2,  # Prompt Tuning typically uses 1e-2 to 3e-2
    ...
)

# Create trainer with PEFT config
trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    peft_config=peft_config,  # pass PEFT config here
)

trainer.train()

Prompt Tuning 配置

from peft import PromptTuningConfig, PromptTuningInit, TaskType

peft_config = PromptTuningConfig(
    task_type=TaskType.CAUSAL_LM,  # Task type
    prompt_tuning_init=PromptTuningInit.TEXT,  # Initialize from text
    num_virtual_tokens=8,  # Number of virtual tokens
    prompt_tuning_init_text="Your initialization text here",
    tokenizer_name_or_path="model_name",
)

配置参数:

  • task_type:任务类型(语言建模为 TaskType.CAUSAL_LM)
  • prompt_tuning_init:初始化方法(TEXT、RANDOM)
  • num_virtual_tokens:要前置的虚拟 token 数量(通常为 8-20)
  • prompt_tuning_init_text:用于初始化虚拟令牌的文本(当使用 TEXT 初始化时)
  • tokenizer_name_or_path:用于从文本初始化的分词器

Prompt Tuning 与 LoRA

功能提示词调整LoRA
已训练参数~0.001%~0.1-1%
内存使用情况最小低
训练速度最快快速
模型修改无Adapter 层
适用场景大型模型,多种任务通用微调
学习率更高(1e-2 到 3e-2)标准(1e-4 到 3e-4)

高级 PEFT 配置

LoRA 配置参数

from peft import LoraConfig

peft_config = LoraConfig(
    r=16,  # LoRA rank
    lora_alpha=32,  # LoRA scaling factor
    lora_dropout=0.05,  # Dropout probability
    bias="none",  # Bias training strategy
    task_type="CAUSAL_LM",  # Task type
    target_modules=["q_proj", "v_proj"],  # Modules to apply LoRA
    modules_to_save=None,  # Additional modules to train
)

关键参数:

  • r:LoRA 秩(典型值:8、16、32、64)。秩越高,参数越多,但性能可能更好。
  • lora_alpha:缩放因子(通常为秩的 2 倍)。控制 LoRA 更新的幅度。
  • lora_dropout:LoRA 层的 Dropout 概率(典型值:0.05-0.1)。
  • target_modules: 要应用 LoRA 的模块。常见选择:
    • ["q_proj", "v_proj"]:注意力查询和值(内存高效)
    • ["q_proj", "k_proj", "v_proj", "o_proj"]:所有注意力投影
    • ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]:所有线性层
  • modules_to_save:需要完全训练的其他模块(例如 ["embed_tokens", "lm_head"])

目标模块选择

您可以指定要将 LoRA 应用于哪些模块。常见模式:

# Minimal (most memory efficient)
target_modules=["q_proj", "v_proj"]

# Attention only
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"]

# All linear layers (best performance, more memory)
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]

使用命令行参数

TRL 脚本通过命令行接受 PEFT 参数:

python trl/scripts/sft.py \
    --model_name_or_path Qwen/Qwen2-0.5B \
    --dataset_name trl-lib/Capybara \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16 \
    --lora_dropout 0.05 \
    --lora_target_modules q_proj v_proj \
    --output_dir output

可用标志:

  • --use_peft:启用 PEFT
  • --lora_r:LoRA 秩(默认值:16)
  • --lora_alpha:LoRA alpha(默认值:32)
  • --lora_dropout:LoRA dropout(默认值:0.05)
  • --lora_target_modules:目标模块(以空格分隔)
  • --lora_modules_to_save:需要额外训练的模块
  • --use_rslora:启用秩稳定 LoRA
  • --use_dora:启用 Weight-Decomposed LoRA (DoRA)
  • --load_in_4bit:启用 4 位量化(QLoRA)
  • --load_in_8bit:启用 8 位量化

保存和加载 PEFT 模型

保存

训练完成后,保存您的 PEFT 适配器:

# Save the adapters
trainer.save_model("path/to/adapters")

# Or manually
model.save_pretrained("path/to/adapters")

这仅保存适配器权重(约几 MB),而非完整模型(约几 GB)。

加载

加载 PEFT 模型以进行推理:

from transformers import AutoModelForCausalLM
from peft import PeftModel

# Load base model
base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B")

# Load PEFT adapters
model = PeftModel.from_pretrained(base_model, "path/to/adapters")

# Optionally merge adapters into base model for faster inference
model = model.merge_and_unload()

推送到 Hub

您可以轻松地在 Hugging Face Hub 上共享您的 PEFT 适配器:

# Push adapters to Hub
model.push_to_hub("username/model-name-lora")

# Load from Hub
from peft import PeftModel
model = PeftModel.from_pretrained(base_model, "username/model-name-lora")

多 GPU 训练

PEFT 与 TRL 的多 GPU 支持无缝配合:

torchrun --nproc_per_node 8 trl/scripts/sft.py \
    --model_name_or_path Qwen/Qwen2-0.5B \
    --dataset_name trl-lib/Capybara \
    --use_peft \
    --lora_r 32 \
    --lora_alpha 16

对于使用多 GPU 的 QLoRA,基础模型会自动进行分片:

torchrun --nproc_per_node 8 trl/scripts/sft.py \
    --model_name_or_path meta-llama/Llama-2-70b-hf \
    --load_in_4bit \
    --use_peft \
    --lora_r 32

用于大模型的朴素流水线并行(NPP)

对于非常大的模型(>60B 参数),TRL 支持 Naive Pipeline Parallelism (NPP),可将模型和适配器分布在多个 GPU 上。激活值和梯度会在 GPU 之间进行通信,支持 int8 及其他数据类型。

NPP

如何使用 NPP

使用自定义的 device_map 加载模型,将其拆分到多个设备上:

from transformers import AutoModelForCausalLM
from peft import LoraConfig

# Create custom device map (see accelerate documentation)
device_map = {
    "model.embed_tokens": 0,
    "model.layers.0": 0,
    # ... distribute layers across GPUs
    "lm_head": 0,  # Must be on GPU 0
}

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-2-70b-hf",
    device_map=device_map,
    peft_config=lora_config,
)
  • 将 lm_head 模块保留在第一块 GPU(设备 0)上,以避免错误
  • 请参阅此设备映射教程以进行正确配置
  • 直接运行训练脚本(不使用 torchrun):python script.py
  • NPP 尚不支持数据并行

资源

TRL 示例和笔记本

文档

研究论文

Update on GitHub