使用 🤗 PEFT 加载适配器
Parameter-Efficient Fine Tuning (PEFT) 方法在微调期间冻结预训练模型参数,并在其基础上添加少量可训练参数(适配器)。适配器被训练以学习任务特定的信息。这种方法已被证明在计算使用较低的情况下非常节省内存,同时产生的结果与完全微调的模型相当。
使用PEFT训练的适配器通常也比完整模型小一个数量级,这使得它们便于共享、存储和加载。
![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/peft/PEFT-hub-screenshot.png)
如果您有兴趣了解更多关于🤗 PEFT库的信息,请查看文档。
设置
通过安装🤗 PEFT开始:
pip install peft
如果你想尝试全新的功能,你可能会对从源代码安装库感兴趣:
pip install git+https://github.com/huggingface/peft.git
支持的PEFT模型
🤗 Transformers 原生支持一些 PEFT 方法,这意味着您可以加载存储在本地或 Hub 上的适配器权重,并通过几行代码轻松运行或训练它们。支持以下方法:
如果你想使用其他PEFT方法,例如提示学习或提示调优,或者想了解🤗 PEFT库的更多信息,请参考文档。
加载一个PEFT适配器
要从🤗 Transformers加载并使用PEFT适配器模型,请确保Hub存储库或本地目录包含adapter_config.json
文件和适配器权重,如上图示例所示。然后,您可以使用AutoModelFor
类加载PEFT适配器模型。例如,要加载用于因果语言建模的PEFT适配器模型:
- 指定PEFT模型ID
- 将其传递给AutoModelForCausalLM类
from transformers import AutoModelForCausalLM, AutoTokenizer
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id)
你可以使用AutoModelFor
类或基础模型类如OPTForCausalLM
或LlamaForCausalLM
来加载PEFT适配器。
你也可以通过调用load_adapter
方法来加载一个PEFT适配器:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "facebook/opt-350m"
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(model_id)
model.load_adapter(peft_model_id)
查看下面的API文档部分以获取更多详细信息。
以8位或4位加载
bitsandbytes
集成支持8位和4位精度的数据类型,这对于加载大型模型非常有用,因为它可以节省内存(请参阅 bitsandbytes
集成 指南 以了解更多信息)。将 load_in_8bit
或 load_in_4bit
参数添加到 from_pretrained() 并设置 device_map="auto"
以有效地将模型分配到您的硬件上:
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id, quantization_config=BitsAndBytesConfig(load_in_8bit=True))
添加一个新的适配器
你可以使用~peft.PeftModel.add_adapter
向已经存在适配器的模型添加一个新的适配器,只要新适配器与当前适配器类型相同。例如,如果你已经有一个LoRA适配器附加到模型上:
from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import LoraConfig
model_id = "facebook/opt-350m"
model = AutoModelForCausalLM.from_pretrained(model_id)
lora_config = LoraConfig(
target_modules=["q_proj", "k_proj"],
init_lora_weights=False
)
model.add_adapter(lora_config, adapter_name="adapter_1")
添加一个新的适配器:
# attach new adapter with same config
model.add_adapter(lora_config, adapter_name="adapter_2")
现在你可以使用 ~peft.PeftModel.set_adapter
来设置使用哪个适配器:
# use adapter_1
model.set_adapter("adapter_1")
output_disabled = model.generate(**inputs)
print(tokenizer.decode(output_disabled[0], skip_special_tokens=True))
# use adapter_2
model.set_adapter("adapter_2")
output_enabled = model.generate(**inputs)
print(tokenizer.decode(output_enabled[0], skip_special_tokens=True))
启用和禁用适配器
一旦你将适配器添加到模型中,你可以启用或禁用适配器模块。要启用适配器模块:
from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import PeftConfig
model_id = "facebook/opt-350m"
adapter_model_id = "ybelkada/opt-350m-lora"
tokenizer = AutoTokenizer.from_pretrained(model_id)
text = "Hello"
inputs = tokenizer(text, return_tensors="pt")
model = AutoModelForCausalLM.from_pretrained(model_id)
peft_config = PeftConfig.from_pretrained(adapter_model_id)
# to initiate with random weights
peft_config.init_lora_weights = False
model.add_adapter(peft_config)
model.enable_adapters()
output = model.generate(**inputs)
要禁用适配器模块:
model.disable_adapters() output = model.generate(**inputs)
训练一个PEFT适配器
PEFT适配器由Trainer类支持,因此您可以为您的特定用例训练一个适配器。只需要添加几行代码即可。例如,要训练一个LoRA适配器:
- 使用任务类型和超参数定义您的适配器配置(有关超参数作用的更多详细信息,请参见
~peft.LoraConfig
)。
from peft import LoraConfig
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM",
)
- 将适配器添加到模型中。
model.add_adapter(peft_config)
- 现在你可以将模型传递给Trainer!
trainer = Trainer(model=model, ...) trainer.train()
保存您训练好的适配器并重新加载它:
model.save_pretrained(save_dir) model = AutoModelForCausalLM.from_pretrained(save_dir)
向PEFT适配器添加额外的可训练层
你也可以通过在PEFT配置中传递modules_to_save
来微调附加的可训练适配器,这些适配器附加在已经带有适配器的模型上。例如,如果你想在带有LoRA适配器的模型上微调lm_head:
from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import LoraConfig
model_id = "facebook/opt-350m"
model = AutoModelForCausalLM.from_pretrained(model_id)
lora_config = LoraConfig(
target_modules=["q_proj", "k_proj"],
modules_to_save=["lm_head"],
)
model.add_adapter(lora_config)
API 文档
一个包含所有用于加载和使用PEFT库支持的适配器权重的函数的类。有关适配器及其在基于变压器的模型上注入的更多详细信息,请查看PEFT库的文档:https://huggingface.co/docs/peft/index
目前支持的PEFT方法都是非前缀调优方法。以下是支持的PEFT方法列表,任何人都可以使用这个mixin类加载、训练和运行:
- 低秩适配器 (LoRA): https://huggingface.co/docs/peft/conceptual_guides/lora
- IA3: https://huggingface.co/docs/peft/conceptual_guides/ia3
- AdaLora: https://arxiv.org/abs/2303.10512
其他PEFT模型,如提示调优、提示学习不在范围内,因为这些适配器不能“注入”到torch模块中。要使用这些方法,请参考PEFT库的使用指南。
使用这个mixin,如果安装了正确的PEFT版本,可以实现以下功能:
- 加载存储在本地路径或远程Hub仓库中的适配器,并将其注入到模型中
- 在模型中附加新的适配器,并使用Trainer或自行训练它们。
- 附加多个适配器并迭代地激活/停用它们
- 激活/停用模型中的所有适配器。
- 获取活动适配器的
state_dict
。
load_adapter
< source >( peft_model_id: typing.Optional[str] = None adapter_name: typing.Optional[str] = None revision: typing.Optional[str] = None token: typing.Optional[str] = None device_map: typing.Optional[str] = 'auto' max_memory: typing.Optional[str] = None offload_folder: typing.Optional[str] = None offload_index: typing.Optional[int] = None peft_config: typing.Dict[str, typing.Any] = None adapter_state_dict: typing.Optional[typing.Dict[str, ForwardRef('torch.Tensor')]] = None low_cpu_mem_usage: bool = False is_trainable: bool = False adapter_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None )
参数
- peft_model_id (
str
, optional) — 在Hub上查找的模型标识符,或保存的适配器配置文件和适配器权重的本地路径。 - adapter_name (
str
, optional) — 使用的适配器名称。如果未设置,将使用默认适配器。 - revision (
str
, optional, defaults to"main"
) — The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a git-based system for storing models and other artifacts on huggingface.co, sorevision
can be any identifier allowed by git.要测试你在Hub上提交的拉取请求,你可以传递
revision="refs/pr/
。" - token (
str
,optional
) — 是否使用认证令牌来加载远程文件夹。对于加载HuggingFace Hub上的私有仓库非常有用。您可能需要调用huggingface-cli login
并粘贴您的令牌以缓存它。 - device_map (
str
orDict[str, Union[int, str, torch.device]]
orint
ortorch.device
, optional) — A map that specifies where each submodule should go. It doesn’t need to be refined to each parameter/buffer name, once a given module name is inside, every submodule of it will be sent to the same device. If we only pass the device (e.g.,"cpu"
,"cuda:1"
,"mps"
, or a GPU ordinal rank like1
) on which the model will be allocated, the device map will map the entire model to this device. Passingdevice_map = 0
means put the whole model on GPU 0.要让 Accelerate 自动计算最优化的
device_map
,请设置device_map="auto"
。有关每个选项的更多信息,请参阅 设计设备映射. - max_memory (
Dict
, 可选) — 一个字典设备标识符到最大内存。如果未设置,将默认为每个GPU的最大可用内存和可用的CPU RAM。 - offload_folder (
str
oros.PathLike
,optional
) — 如果device_map
包含任何值为"disk"
,我们将卸载权重的文件夹。 - offload_index (
int
,optional
) —offload_index
参数将传递给accelerate.dispatch_model
方法. - peft_config (
Dict[str, Any]
, 可选) — 要添加的适配器的配置,支持的适配器是非前缀调优和适配提示方法。此参数用于用户直接传递PEFT状态字典的情况 - adapter_state_dict (
Dict[str, torch.Tensor]
, optional) — 要加载的适配器的状态字典。此参数用于用户直接传递PEFT状态字典的情况 - low_cpu_mem_usage (
bool
, 可选, 默认为False
) — 在加载PEFT适配器时减少内存使用。这也应该会加快加载过程。 需要PEFT版本0.13.0或更高。 - is_trainable (
bool
, 可选, 默认为False
) — 适配器是否应该可训练。如果为False
,适配器将被冻结,只能用于推理。 - adapter_kwargs (
Dict[str, Any]
, 可选) — 传递给适配器配置的from_pretrained
方法和find_adapter_config_file
方法的额外关键字参数。
从文件或远程Hub文件夹加载适配器权重。如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档中的更多信息:https://huggingface.co/docs/peft
需要peft作为后端来加载适配器权重。
add_adapter
< source >( adapter_config adapter_name: typing.Optional[str] = None )
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
为当前模型添加一个新的适配器用于训练目的。如果没有传递适配器名称,则会为适配器分配一个默认名称,以遵循PEFT库的约定(在PEFT中,我们使用“default”作为默认适配器名称)。
set_adapter
< source >( adapter_name: typing.Union[typing.List[str], str] )
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
通过强制模型使用特定适配器并禁用其他适配器来设置特定适配器。
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
禁用所有附加到模型的适配器。这将导致仅使用基础模型进行推断。
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
启用附加到模型的适配器。
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
获取模型的当前活动适配器。在多适配器推理(组合多个适配器进行推理)的情况下,返回所有活动适配器的列表,以便用户可以相应地处理它们。
对于之前的PEFT版本(不支持多适配器推理),module.active_adapter
将返回一个单一的字符串。
get_adapter_state_dict
< source >( adapter_name: typing.Optional[str] = None )
如果您不熟悉适配器和PEFT方法,我们邀请您阅读PEFT官方文档以了解更多信息:https://huggingface.co/docs/peft
获取应仅包含指定adapter_name适配器的权重张量的适配器状态字典。 如果未传递adapter_name,则使用当前活动的适配器。