PEFT 文档
Adapter 注入
并获得增强的文档体验
开始使用
Adapter 注入
使用 PEFT,您可以将可训练的 Adapter 注入到任何 torch
模块中,这使您无需依赖 PEFT 中的模型类即可使用 Adapter 方法。这适用于除基于提示学习(例如前缀调优或 p-tuning)之外的所有 Adapter。
查看下表,了解何时应注入 Adapter。
优点 | 缺点 |
---|---|
模型被原地修改,保留所有原始属性和方法 | 从 Hugging Face 手动编写 from_pretrained 和 save_pretrained 实用程序函数来保存和加载 Adapter |
适用于任何 torch 模块和模态 | 不适用于 PeftModel 提供的任何实用程序方法,例如禁用和合并 Adapter |
创建一个新的 PEFT 模型
要执行 Adapter 注入,请使用 inject_adapter_in_model() 方法。此方法接受 3 个参数:PEFT 配置、模型和一个可选的 Adapter 名称。如果使用不同的 Adapter 名称多次调用 inject_adapter_in_model(),还可以将多个 Adapter 附加到模型中。
例如,要将 LoRA Adapter 注入到 DummyModel
模块的 linear
子模块中:
import torch
from peft import inject_adapter_in_model, LoraConfig
class DummyModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.embedding = torch.nn.Embedding(10, 10)
self.linear = torch.nn.Linear(10, 10)
self.lm_head = torch.nn.Linear(10, 10)
def forward(self, input_ids):
x = self.embedding(input_ids)
x = self.linear(x)
x = self.lm_head(x)
return x
lora_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
target_modules=["linear"],
)
model = DummyModel()
model = inject_adapter_in_model(lora_config, model)
dummy_inputs = torch.LongTensor([[0, 1, 2, 3, 4, 5, 6, 7]])
dummy_outputs = model(dummy_inputs)
打印模型以查看 Adapter 是否已正确注入。
DummyModel( (embedding): Embedding(10, 10) (linear): Linear( in_features=10, out_features=10, bias=True (lora_dropout): ModuleDict( (default): Dropout(p=0.1, inplace=False) ) (lora_A): ModuleDict( (default): Linear(in_features=10, out_features=64, bias=False) ) (lora_B): ModuleDict( (default): Linear(in_features=64, out_features=10, bias=False) ) (lora_embedding_A): ParameterDict() (lora_embedding_B): ParameterDict() ) (lm_head): Linear(in_features=10, out_features=10, bias=True) )
基于 state_dict 的注入
有时,可能会有一个 PEFT Adapter 检查点,但由于某种原因不知道相应的 PEFT 配置。要为此检查点注入 PEFT 层,通常需要基于检查点的 state_dict
对相应的 PEFT 配置进行逆向工程,最主要的是 target_modules
参数。这可能很繁琐且容易出错。为避免这种情况,也可以调用 inject_adapter_in_model() 并将加载的 state_dict
作为参数传递:
from safetensors.torch import load_file
model = ...
state_dict = load_file(<path-to-safetensors-file>)
lora_config = LoraConfig(...)
model = inject_adapter_in_model(lora_config, model, state_dict=state_dict)
在这种情况下,PEFT 将使用 state_dict
作为目标层的参考,而不是使用 PEFT 配置。作为用户,您不必为 PEFT 配置设置确切的 target_modules
也能使其工作。但是,您仍应传递正确类型的 PEFT 配置,在此示例中为 LoraConfig
,您可以将 target_modules
设置为 None
。
请注意,这仍然只创建未初始化的 PEFT 层,state_dict
中的值不会用于填充模型权重。要填充权重,请继续调用如下所述的 set_peft_model_state_dict()
。
⚠️ 请注意,如果 PEFT 配置中的配置与 state_dict
中发现的内容不匹配,PEFT 会警告您。如果您知道 PEFT 配置没有正确指定,可以忽略该警告。
如果原始 PEFT Adapter 使用的是 target_parameters
而不是 target_modules
,那么从 state_dict
注入将无法正常工作。在这种情况下,必须使用正确的 PEFT 配置进行注入。
保存模型
要仅保存 Adapter,请使用 get_peft_model_state_dict() 函数:
from peft import get_peft_model_state_dict
peft_state_dict = get_peft_model_state_dict(model)
print(peft_state_dict)
否则,model.state_dict()
返回模型的完整状态字典。
加载模型
加载已保存的 state_dict
后,可以使用 set_peft_model_state_dict()
函数应用它:
from peft import set_peft_model_state_dict
model = DummyModel()
model = inject_adapter_in_model(lora_config, model)
outcome = set_peft_model_state_dict(model, peft_state_dict)
# check that there were no wrong keys
print(outcome.unexpected_keys)
如果注入 Adapter 的速度很慢,或者您需要加载大量的 Adapter,您可以使用一种优化方法,该方法允许在元设备上创建一个“空” Adapter,并且仅在调用 set_peft_model_state_dict()
时才用真实权重填充权重。为此,请将 low_cpu_mem_usage=True
传递给 inject_adapter_in_model() 和 set_peft_model_state_dict()
。
model = DummyModel()
model = inject_adapter_in_model(lora_config, model, low_cpu_mem_usage=True)
print(model.linear.lora_A["default"].weight.device.type == "meta") # should be True
set_peft_model_state_dict(model, peft_state_dict, low_cpu_mem_usage=True)
print(model.linear.lora_A["default"].weight.device.type == "cpu") # should be True