使用 🤗 PEFT 加载适配器
参数高效微调 (PEFT) 方法在微调期间冻结预训练模型参数,并在其之上添加少量可训练参数(适配器)。适配器经过训练以学习特定于任务的信息。这种方法已被证明在内存效率方面非常高,计算使用量较低,同时产生的结果与完全微调的模型相当。
使用 PEFT 训练的适配器通常也比完整模型小一个数量级,这使得共享、存储和加载它们变得很方便。
如果您有兴趣了解更多关于 🤗 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 库支持的适配器权重的函数的类。有关适配器及其在基于 Transformer 的模型上的注入的更多详细信息,请查看 PEFT 库的文档:https://huggingface.co/docs/peft/index
目前支持的 PEFT 方法都是非前缀微调方法。以下是任何人都可以使用此混合类加载、训练和运行的支持的 PEFT 方法列表
- 低秩适配器 (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 库的使用指南。
使用此混合类,如果安装了正确的 PEFT 版本,就可以
- 加载存储在本地路径或远程 Hub 仓库中的适配器,并将其注入到模型中
- 在模型中附加新的适配器,并使用 Trainer 或您自己的方式对其进行训练。
- 附加多个适配器,并迭代地激活/停用它们
- 激活/停用模型中的所有适配器。
- 获取活动适配器的
state_dict
。
load_adapter
< 源代码 >( peft_model_id: 可选 = None adapter_name: 可选 = None revision: 可选 = None token: 可选 = None device_map: 可选 = 'auto' max_memory: 可选 = None offload_folder: 可选 = None offload_index: 可选 = None peft_config: 字典 = None adapter_state_dict: 可选 = None adapter_kwargs: 可选 = None )
参数
- peft_model_id (
str
, 可选) — 要在 Hub 上查找的模型的标识符,或本地保存的适配器配置文件和适配器权重的路径。 - adapter_name (
str
, 可选) — 要使用的适配器名称。如果没有设置,将使用默认适配器。 - revision (
str
, 可选,默认值为"main"
) — 要使用的特定模型版本。它可以是分支名称、标签名称或提交 ID,因为我们使用基于 git 的系统在 huggingface.co 上存储模型和其他工件,因此revision
可以是 git 允许的任何标识符。要测试您在 Hub 上创建的拉取请求,可以传递
revision=“refs/pr/
“。 - token (
str
,可选
) — 是否使用身份验证令牌来加载远程文件夹。在加载 HuggingFace Hub 上的私有仓库时非常有用。您可能需要调用huggingface-cli login
并粘贴您的令牌以将其缓存。 - device_map (
str
或Dict[str, Union[int, str, torch.device]]
或int
或torch.device
, 可选) — 指定每个子模块应该放置位置的映射。它不需要细化到每个参数/缓冲区名称,只要给定的模块名称在内,它的每个子模块都将被发送到同一个设备。如果我们只传递模型将被分配到的设备(例如,"cpu"
、"cuda:1"
、"mps"
或 GPU 序数排名,如1
),则设备映射将把整个模型映射到此设备。传递device_map = 0
意味着将整个模型放在 GPU 0 上。要让 Accelerate 自动计算最优化的
device_map
,请设置device_map="auto"
。有关每个选项的更多信息,请参见 设计设备映射。 - max_memory (
Dict
, 可选) — 设备标识符到最大内存的字典。如果未设置,将默认为每个 GPU 的可用最大内存和可用的 CPU RAM。 - offload_folder (
str
或os.PathLike
,可选
) — 如果device_map
包含任何值为"disk"
的值,则为我们将卸载权重的文件夹。 - offload_index (
int
,可选
) — 传递给accelerate.dispatch_model
方法的offload_index
参数。 - peft_config (
Dict[str, Any]
, 可选) — 要添加的适配器的配置,支持的适配器是非前缀调整和自适应提示方法。 如果用户直接传递 PEFT 状态字典,则使用此参数 - adapter_state_dict (
Dict[str, torch.Tensor]
, 可选) — 要加载的适配器的状态字典。 如果用户直接传递 PEFT 状态字典,则使用此参数 - adapter_kwargs (
Dict[str, Any]
, 可选) — 传递给适配器配置的from_pretrained
方法和find_adapter_config_file
方法的额外关键字参数。
从文件或远程 Hub 文件夹加载适配器权重。 如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
需要 peft 作为后端来加载适配器权重。
如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
为当前模型添加一个全新的适配器,用于训练目的。 如果没有传递适配器名称,则为适配器分配默认名称以遵循 PEFT 库的约定(在 PEFT 中,我们使用“default”作为默认适配器名称)。
set_adapter
< 源代码 >( adapter_name: Union )
如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
禁用附加到模型的所有适配器。这会导致仅使用基础模型进行推理。
如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
启用附加到模型的适配器。模型将使用 self.active_adapter()
如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
获取模型当前活动的适配器。在多适配器推理(组合多个适配器进行推理)的情况下,返回所有活动适配器的列表,以便用户可以相应地处理它们。
对于之前的 PEFT 版本(不支持多适配器推理),module.active_adapter
将返回单个字符串。
get_adapter_state_dict
< 源代码 >( adapter_name: Optional = None )
如果您不熟悉适配器和 PEFT 方法,我们邀请您在 PEFT 官方文档中了解更多信息: https://huggingface.co/docs/peft
获取适配器状态字典,该字典应仅包含指定 adapter_name
适配器的权重张量。如果未传递 adapter_name
,则使用活动适配器。