Transformers 文档
参数高效微调
并获得增强的文档体验
开始使用
参数高效微调 (Parameter-efficient fine-tuning)
参数高效微调 (PEFT) 方法仅在预训练模型之上微调少量额外的模型参数(适配器/adapters)。由于仅更新适配器参数,优化器跟踪的梯度和状态大幅减少,从而显著降低了内存使用量。适配器轻量且易于共享、存储和加载。
Transformers 通过 PeftAdapterMixin 直接集成了 PEFT 库,该 mixin 已添加到所有的 PreTrainedModel 类中。你可以在无需将模型包装在单独的 PeftModel 中的情况下,加载、添加、训练、切换和删除适配器。支持所有非提示学习 (non-prompt-learning) 的 PEFT 方法(LoRA, IA3, AdaLoRA)。基于提示的方法(如 prompt tuning 和 prefix tuning)需要直接使用 PEFT 库。
安装 PEFT 即可开始。该集成要求 peft >= 0.18.0。
pip install -U peft
添加适配器
创建一个 PEFT 配置(例如 LoraConfig),并通过 add_adapter() 将其附加到模型上。
from peft import LoraConfig, TaskType
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("google/gemma-2-2b")
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
inference_mode=False,
r=8,
lora_alpha=32,
lora_dropout=0.1,
)
model.add_adapter(lora_config, adapter_name="my_adapter")完全微调特定层
若要与适配器一起训练其他模块(例如语言模型头部),请在 modules_to_save 中指定它们。modules_to_save 指定了与适配器一起进行完全微调的层,因此它们的所有参数都会被更新。这在某些层需要更新时非常有用,例如将因果语言模型 (causal LM) 用于序列分类任务时的语言模型头部 (lm_head)。
lora_config = LoraConfig(
modules_to_save=["lm_head"],
...
)
model.add_adapter(lora_config)选择需要适配的层
对于常见的架构(Llama、Gemma、Qwen 等),PEFT 具有预定义的默认目标层(如 q_proj 和 v_proj),因此你无需指定 target_modules。如果你想指定不同的层,或者模型没有预定义的适配目标,请显式传递 target_modules 作为模块名称列表或正则表达式模式。
lora_config = LoraConfig(
target_modules=["q_proj", "k_proj"],
...
)
model.add_adapter(lora_config)训练
将带有已附加适配器的模型传递给 Trainer 并调用 train()。Trainer 仅更新适配器参数(那些 requires_grad=True 的参数),因为基础模型被冻结了。
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=4,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
)
trainer.train()在训练过程中,Trainer 的检查点仅包含适配器权重 (adapter_model.safetensors) 和配置 (adapter_config.json),从而保持检查点文件体积较小。基础模型不包含在内。
训练完成后,使用 save_pretrained() 保存最终的适配器。
model.save_pretrained("./my_adapter")从检查点恢复训练
Trainer 在恢复训练时会自动检测适配器检查点。Trainer 会扫描检查点目录中包含适配器权重的子目录,并以正确的训练状态重新加载每个适配器。
trainer.train(resume_from_checkpoint="./output/checkpoint-1000")分布式训练
PEFT 适配器可直接支持分布式训练。
对于 ZeRO-3,Trainer 在保存带有 PEFT 模型的检查点时会传递 exclude_frozen_parameters=True。被冻结的基础模型权重将被跳过。仅保存可训练的适配器参数,从而减少检查点大小并缩短保存时间。
对于 FSDP,Trainer 会更新 FSDP 自动封装 (auto-wrap) 策略以正确处理 LoRA 层。对于 QLoRA(量化基础模型 + LoRA),Trainer 还会调整混合精度策略以匹配量化存储数据类型。
加载适配器
要加载适配器,Hub 仓库或本地目录中必须包含 adapter_config.json 文件和适配器权重。
from_pretrained() 会自动检测适配器。当它找到 adapter_config.json 时,会读取 base_model_name_or_path 字段以加载正确的基础模型,然后在之上加载适配器。
from transformers import AutoModelForCausalLM
# Automatically loads the base model and attaches the adapter
model = AutoModelForCausalLM.from_pretrained("klcsp/gemma7b-lora-alpaca-11-v1")对于大型模型,可以使用 bitsandbytes 以 8-bit 或 4-bit 精度加载量化版本来节省内存。添加 device_map="auto" 以将模型分布在可用的硬件上。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
model = AutoModelForCausalLM.from_pretrained(
"klcsp/gemma7b-lora-alpaca-11-v1",
quantization_config=BitsAndBytesConfig(load_in_8bit=True),
device_map="auto",
)管理多个适配器
一个模型可以同时持有多个适配器。使用唯一的名称添加适配器,并根据需要进行切换。
from peft import LoraConfig
model.add_adapter(LoraConfig(r=8, lora_alpha=32), adapter_name="adapter_1")
model.add_adapter(LoraConfig(r=16, lora_alpha=64), adapter_name="adapter_2")使用 set_adapter() 来激活特定的适配器。其他适配器将被禁用,但仍保留在内存中。
model.set_adapter("adapter_2")enable_adapters() 启用所有已附加的适配器,而 disable_adapters() 则禁用所有适配器。
# Disable all adapters for base model inference
model.disable_adapters()
# Re-enable all adapters
model.enable_adapters()使用 active_adapters() 查看当前活跃的适配器。
model.active_adapters()
# ["adapter_1"]使用 delete_adapter() 移除不再需要的适配器以释放内存。
model.delete_adapter("adapter_1")热切换 (Hotswapping) 适配器
每次处理请求时加载新适配器都会分配新的内存。如果模型使用 torch.compile 进行编译,每个新适配器都会触发重新编译。热切换(Hotswapping)可以在原地替换适配器权重,从而避免这两个问题。目前仅支持 LoRA 适配器。
加载 LoRA 适配器时传递 hotswap=True,将其权重交换到现有的适配器插槽中。将 adapter_name 设置为要替换的适配器名称("default" 是默认的适配器名称)。
model = AutoModel.from_pretrained(...)
# Load the first adapter normally
model.load_adapter(adapter_path_1)
# Generate outputs with adapter 1
...
# Hotswap the second adapter in-place
model.load_adapter(adapter_path_2, hotswap=True, adapter_name="default")
# Generate outputs with adapter 2torch.compile
对于编译后的模型,请在加载第一个适配器以及编译之前调用 enable_peft_hotswap()。
model = AutoModel.from_pretrained(...)
max_rank = ... # highest rank among all LoRAs you'll load
model.enable_peft_hotswap(target_rank=max_rank)
model.load_adapter(adapter_path_1, adapter_name="default")
model = torch.compile(model, ...)
output_1 = model(...)
# Hotswap without recompilation
model.load_adapter(adapter_path_2, adapter_name="default")
output_2 = model(...)target_rank 参数设置你将要加载的所有 LoRA 适配器中的最大秩 (rank)。如果你有秩为 8 和 16 的适配器,请传递 target_rank=16。默认值为 128。
调用 enable_peft_hotswap 后,所有后续的 load_adapter 调用默认都会进行热切换。显式传递 hotswap=False 可禁用热切换。
如果热切换的适配器目标层比初始适配器多,仍可能发生重新编译。请先加载目标层最多的适配器,以避免重新编译。
将代码包裹在
with torch._dynamo.config.patch(error_on_recompile=True)中以检测意外的重新编译。如果你在遵循上述步骤后仍检测到重新编译,请在 PEFT 中通过可复现的示例提交 issue。