在 Hugging Face 的 PEFT(Parameter-Efficient Fine-Tuning)库中,get_peft_model()
函数是用于将基础模型(通常是 Hugging Face Transformers 模型)转换为支持参数高效微调(PEFT)的模型的关键函数。它通过应用指定的 PEFT 配置(如 LoraConfig
、PromptTuningConfig
等)为模型添加适配器(adapters),从而实现高效微调。以下是对 get_peft_model()
函数的详细讲解,包括其功能、参数、用法、代码示例和注意事项。
1. get_peft_model() 功能概述
get_peft_model()
函数的主要作用是将一个预训练模型(base model)与 PEFT 配置结合,生成一个新的 PeftModel
实例。这个实例包含了基础模型和附加的 PEFT 适配器(如 LoRA 矩阵、Prompt Tuning 提示、IA3 缩放向量等)。适配器只包含少量可训练参数,而基础模型的权重通常保持冻结,从而实现高效微调。
核心功能:
- 根据指定的 PEFT 配置(如
LoraConfig
、VeraConfig
等)为模型添加适配器。 - 自动冻结基础模型的权重,仅允许适配器参数可训练(除非配置中指定了
modules_to_save
)。 - 支持多任务适配器(通过
adapter_name
参数)。 - 返回一个
PeftModel
实例,兼容 Hugging Face 的Trainer
和推理流程。
2. get_peft_model() 函数签名
以下是 get_peft_model()
函数的签名(基于 PEFT 最新版本):
def get_peft_model(
model: torch.nn.Module,
peft_config: PeftConfig,
adapter_name: str = "default",
mixed: bool = False
) -> PeftModel
参数说明:
-
model
(torch.nn.Module
,必填)- 基础模型,通常是 Hugging Face Transformers 模型(如
AutoModelForCausalLM
、AutoModelForSequenceClassification
等)。 - 示例:
model = AutoModelForCausalLM.from_pretrained("gpt2")
。
- 基础模型,通常是 Hugging Face Transformers 模型(如
-
peft_config
(PeftConfig
,必填)- PEFT 配置对象,指定使用的微调方法及其参数。
- 支持的配置类包括:
LoraConfig
(低秩适配)PromptTuningConfig
(提示微调)PrefixTuningConfig
(前缀微调)P-tuningConfig
(P-Tuning)IA3Config
(缩放向量微调)LoftQConfig
(量化低秩适配)VeraConfig
(向量基随机矩阵适配)AdaLoraConfig
(自适应低秩适配)
- 示例:
peft_config = LoraConfig(task_type="CAUSAL_LM", r=8, target_modules=["c_attn"])
。
-
adapter_name
(字符串,默认:"default"
)- 指定适配器的名称,用于支持多任务或多适配器场景。
- 示例:
adapter_name="task1"
。 - 如果需要添加多个适配器,可以后续通过
peft_model.add_adapter()
使用不同的adapter_name
。
-
mixed
(布尔值,默认:False
)- 是否启用混合精度(mixed precision)支持。
- 如果为
True
,适配器将支持混合精度训练(需要 PyTorch 和适当的硬件支持)。 - 通常保持默认值
False
,除非需要优化内存或性能。
返回值:
PeftModel
:- 一个
PeftModel
实例,包含基础模型和 PEFT 适配器。 - 该实例支持 Hugging Face 的
Trainer
、generate()
(生成任务)以及标准 PyTorch 训练流程。 - 提供方法如
print_trainable_parameters()
查看可训练参数。
- 一个
3. 使用 get_peft_model() 的基本流程
以下是一个使用 get_peft_model()
微调 GPT-2 模型(用于因果语言建模任务)的完整示例,展示如何结合 LoraConfig
:
步骤 1:安装和导入库
pip install peft transformers torch datasets
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
步骤 2:加载模型和数据集
# 加载预训练模型和分词器
model_name = "gpt2"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token # 为 GPT-2 设置 pad token
# 加载数据集(以 wikitext 为例)
dataset = load_dataset("wikitext", "wikitext-2-raw-v1")
# 数据预处理
def tokenize_function(examples):
return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=128)
tokenized_dataset = dataset.map(tokenize_function, batched=True)
步骤 3:配置 PEFT(以 LoraConfig 为例)
# 配置 LoRA
lora_config = LoraConfig(
task_type="CAUSAL_LM", # 因果语言模型任务
r=8, # 低秩矩阵的秩
lora_alpha=16, # 缩放因子
lora_dropout=0.1, # Dropout 概率
target_modules=["c_attn"], # 应用 LoRA 的模块(GPT-2 的注意力层)
modules_to_save=["lm_head"] # 全量微调语言模型头
)
# 使用 get_peft_model() 创建 PEFT 模型
peft_model = get_peft_model(model, lora_config, adapter_name="default")
# 查看可训练参数
peft_model.print_trainable_parameters()
输出示例:
trainable params: 294,912 || all params: 124,747,008 || trainable%: 0.236
这表明只有约 0.24% 的参数需要训练(LoRA 权重 + 语言模型头参数)。
步骤 4:训练模型
# 配置训练参数
training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
weight_decay=0.01,
)
# 初始化 Trainer
trainer = Trainer(
model=peft_model,
args=training_args,
train_dataset=tokenized_dataset["train"].select(range(1000)), # 选取子集以加速示例
eval_dataset=tokenized_dataset["validation"].select(range(200)),
)
# 开始训练
trainer.train()
步骤 5:保存和加载 PEFT 模型
# 保存 PEFT 适配器
peft_model.save_pretrained("./lora_model")
# 加载 PEFT 模型
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(model_name)
loaded_model = PeftModel.from_pretrained(base_model, "./lora_model")
步骤 6:推理
# 准备输入
inputs = tokenizer("Once upon a time", return_tensors="pt").to("cuda")
# 推理
loaded_model.eval()
outputs = loaded_model.generate(**inputs, max_length=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
4. 支持的 PEFT 配置
get_peft_model()
支持以下 PEFT 配置类,每种配置对应一种微调方法:
LoraConfig
:低秩适配(LoRA),通过低秩矩阵更新权重。AdaLoraConfig
:自适应 LoRA,动态调整秩。PromptTuningConfig
:提示微调,添加可训练的虚拟 token。PrefixTuningConfig
:前缀微调,为每层添加前缀向量。P-tuningConfig
:P-Tuning,使用 LSTM 或 MLP 建模提示。IA3Config
:(IA)^3,通过缩放向量调整激活。LoftQConfig
:量化 LoRA,结合量化初始化。VeraConfig
:VeRA,使用共享低秩矩阵和缩放向量。
选择配置的建议:
- 生成任务:
LoraConfig
,VeraConfig
,PrefixTuningConfig
,P-tuningConfig
或IA3Config
更适合(如 GPT、LLaMA)。 - 分类任务:
LoraConfig
或PromptTuningConfig
更通用(如 BERT)。 - 量化场景:
LoftQConfig
或LoraConfig
结合 4-bit 量化。 - 存储受限:
VeraConfig
(可不保存共享矩阵)或IA3Config
(参数量极少)。
5. 进阶用法
以下是一些 get_peft_model()
的高级用法,展示其灵活性:
多任务适配器
支持为不同任务创建多个适配器,并动态切换:
# 配置两个 LoRA 适配器
lora_config_task1 = LoraConfig(
task_type="CAUSAL_LM",
r=8,
target_modules=["c_attn"],
lora_alpha=16
)
lora_config_task2 = LoraConfig(
task_type="CAUSAL_LM",
r=16,
target_modules=["c_attn"],
lora_alpha=32
)
# 创建第一个适配器
peft_model = get_peft_model(model, lora_config_task1, adapter_name="task1")
# 添加第二个适配器
peft_model.add_adapter("task2", lora_config_task2)
# 切换适配器
peft_model.set_adapter("task1") # 使用 task1 适配器
peft_model.set_adapter("task2") # 切换到 task2 适配器
结合量化
结合 bitsandbytes
进行 4-bit 量化以节省内存:
from transformers import BitsAndBytesConfig
# 加载量化模型
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=quantization_config)
# 配置 LoRA
lora_config = LoraConfig(
task_type="CAUSAL_LM",
r=8,
target_modules=["c_attn"],
lora_alpha=16
)
# 创建 PEFT 模型
peft_model = get_peft_model(model, lora_config)
检查可训练参数
使用 print_trainable_parameters()
查看参数分布:
peft_model.print_trainable_parameters()
输出示例:
trainable params: 294,912 || all params: 124,747,008 || trainable%: 0.236
合并适配器权重
将适配器权重合并到基础模型以消除推理延迟:
merged_model = peft_model.merge_and_unload()
merged_model.save_pretrained("./merged_model")
保存到 Hugging Face Hub
将适配器上传到 Hugging Face Hub:
peft_model.push_to_hub("your-username/peft-model")
6. 常见问题与解答
-
Q1:如何选择合适的
peft_config
?- 根据任务和资源选择:
- 生成任务:
LoraConfig
,VeraConfig
,PrefixTuningConfig
。 - 分类任务:
LoraConfig
,PromptTuningConfig
。 - 量化微调:
LoftQConfig
或LoraConfig
结合 4-bit 量化。 - 存储受限:
VeraConfig
(最小检查点)或IA3Config
(最少参数)。
- 生成任务:
- 参考 PEFT 文档中的基准测试或实验不同配置。
- 根据任务和资源选择:
-
Q2:为什么
get_peft_model()
报错?- 原因 1:
target_modules
配置错误:- 检查
target_modules
是否与模型结构匹配(使用model.named_modules()
查看)。 - 示例:LLaMA 使用
["q_proj", "v_proj"]
,GPT-2 使用["c_attn"]
。
- 检查
- 原因 2:模型不兼容:
- 确保
model
是 Hugging Face Transformers 模型,且支持 PEFT。
- 确保
- 原因 3:内存不足:
- 启用量化(4-bit 或 8-bit)或减少
r
(LoRA 秩)。
- 启用量化(4-bit 或 8-bit)或减少
- 原因 1:
-
Q3:如何添加多个适配器?
- 使用
get_peft_model()
创建第一个适配器,然后通过peft_model.add_adapter(adapter_name, peft_config)
添加更多适配器。 - 示例见“多任务适配器”部分。
- 使用
-
Q4:
mixed=True
有什么作用?- 启用混合精度训练(FP16/BF16),减少内存占用并加速训练。
- 需要 GPU 支持和 PyTorch 的
torch.cuda.amp
。
-
Q5:如何调试性能不佳?
- 检查
peft_config
参数(例如,增加r
或扩展target_modules
)。 - 调整学习率(LoRA 推荐 2e-5,Prompt Tuning 推荐 1e-3)。
- 确保数据集质量和预处理正确。
- 尝试其他 PEFT 方法(例如,从
PromptTuningConfig
切换到LoraConfig
)。
- 检查
7. 注意事项
-
模型兼容性:
get_peft_model()
要求输入模型是torch.nn.Module
的子类,且通常是 Hugging Face Transformers 模型。- 非 Transformer 模型可能需要自定义适配器配置。
-
冻结权重:
- 默认情况下,基础模型的权重被冻结,仅适配器参数可训练。
- 如果需要微调特定模块(如分类头),在
peft_config
中设置modules_to_save
。
-
内存管理:
- 对于大型模型,建议结合
bitsandbytes
的 4-bit 或 8-bit 量化。 - 使用梯度检查点(
model.gradient_checkpointing_enable()
)以进一步节省内存。
- 对于大型模型,建议结合
-
适配器切换:
- 多任务场景下,确保通过
set_adapter()
切换到正确的adapter_name
。 - 每次推理或训练前检查当前激活的适配器(
peft_model.active_adapter
)。
- 多任务场景下,确保通过