PEFT 文档
LoRA
并获取增强的文档体验
开始使用
LoRA
LoRA 是一种低秩分解方法,用于减少可训练参数的数量,从而加速大型模型的微调并减少内存使用。 在 PEFT 中,使用 LoRA 非常简单,只需设置 LoraConfig 并使用 get_peft_model() 包装它,即可创建一个可训练的 PeftModel。
本指南更详细地探讨了使用 LoRA 的其他选项和功能。
初始化
LoRA 权重的初始化由 LoraConfig 中的参数 init_lora_weights
控制。 默认情况下,PEFT 使用 Kaiming-uniform 初始化权重 A,并使用零初始化权重 B,从而产生恒等变换(与参考 实现 相同)。
也可以传递 init_lora_weights="gaussian"
。 顾名思义,这将使用高斯分布初始化权重 A,并使用零初始化权重 B(这是 Diffusers 初始化 LoRA 权重的方式)。
from peft import LoraConfig
config = LoraConfig(init_lora_weights="gaussian", ...)
还有一个选项可以设置 init_lora_weights=False
,这对于调试和测试很有用。 这应该是您唯一一次使用此选项。 选择此选项时,LoRA 权重的初始化方式使其不产生恒等变换。
from peft import LoraConfig
config = LoraConfig(init_lora_weights=False, ...)
PiSSA
PiSSA 使用主奇异值和奇异向量初始化 LoRA 适配器。 这种直接的修改使 PiSSA 比 LoRA 收敛得更快,并最终获得卓越的性能。 此外,与 QLoRA 相比,PiSSA 减少了量化误差,从而进一步增强了性能。
将初始化方法配置为“pissa”,这可能需要几分钟才能在预训练模型上执行 SVD
from peft import LoraConfig
config = LoraConfig(init_lora_weights="pissa", ...)
或者,执行快速 SVD,这只需要几秒钟。 迭代次数决定了误差和计算时间之间的权衡
lora_config = LoraConfig(init_lora_weights="pissa_niter_[number of iters]", ...)
有关使用 PiSSA 的详细说明,请遵循这些说明。
CorDA
CorDA 从权重分解构建任务感知型 LoRA 适配器,该分解由下游任务学习(指令预览模式,IPM)或维护世界知识(知识保留模式,KPM)的上下文定向。 KPM 不仅在微调任务上实现了比 LoRA 更好的性能,而且还减轻了预训练世界知识的灾难性遗忘。 当保留预训练知识不是问题时,IPM 是首选,因为它可以进一步加速收敛并提高微调性能。
您需要将初始化方法配置为“corda”,并指定 IPM 或 KPM 的模式以及用于收集协方差矩阵的数据集。
@torch.no_grad()
def run_model():
# Assume `model` and `dataset` is in context...
model.eval()
for batch in dataset:
model(**batch)
corda_config = CordaConfig(
corda_method="kpm",
)
lora_config = LoraConfig(
init_lora_weights="corda",
corda_config=corda_config,
)
preprocess_corda(model, lora_config, run_model=run_model)
peft_model = get_peft_model(model, lora_config)
有关使用 CorDA 的详细说明,请遵循这些说明。
OLoRA
OLoRA 利用 QR 分解来初始化 LoRA 适配器。 OLoRA 通过其 QR 分解的因子转换模型的基础权重,即在对其执行任何训练之前,它会改变权重。 这种方法显着提高了稳定性,加快了收敛速度,并最终实现了卓越的性能。
您只需要传递一个额外的选项即可使用 OLoRA
from peft import LoraConfig
config = LoraConfig(init_lora_weights="olora", ...)
有关更高级的用法,请参阅我们的文档。
EVA
EVA 对每层的输入激活执行 SVD,并使用右奇异向量来初始化 LoRA 权重。 因此,它是一种数据驱动的初始化方案。 此外,EVA 根据层级的“解释方差比”(一种从 SVD 分析得出的指标)自适应地跨层分配秩。
您可以通过在 LoraConfig 中设置 init_lora_weights="eva"
并定义 EvaConfig 来使用 EVA
from peft import LoraConfig, EvaConfig
peft_config = LoraConfig(
init_lora_weights = "eva",
eva_config = EvaConfig(rho = 2.0),
...
)
参数 rho
(≥ 1.0) 决定了允许多少重新分配。 当 rho=1.0
且 r=16
时,LoRA 适配器被限制为正好 16 个秩,从而阻止任何重新分配的发生。 建议 EVA 使用重新分配的值为 2.0,这意味着层允许的最大秩为 2r。
建议在 GPU 上执行 EVA 初始化,因为它速度更快。 为了优化 EVA 的可用内存量,您可以使用 get_peft_model() 中的 low_cpu_mem_usage
标志
peft_model = get_peft_model(model, peft_config, low_cpu_mem_usage=True)
然后,调用 initialize_lora_eva_weights() 来初始化 EVA 权重(在大多数情况下,用于 eva 初始化的数据加载器可以与用于微调的数据加载器相同)
initialize_lora_eva_weights(peft_model, dataloader)
EVA 可以与 bitsandbytes 开箱即用。 只需使用 quantization_config
初始化模型,并像往常一样调用 initialize_lora_eva_weights()。
有关使用 EVA 的更多说明,请参阅我们的文档。
LoftQ
标准方法
在量化用于 QLoRA 训练的基础模型时,请考虑使用 LoftQ 初始化,该初始化已显示出在训练量化模型时可提高性能。 其思想是初始化 LoRA 权重,以最大程度地减少量化误差。 要使用 LoftQ,请遵循这些说明。
一般来说,为了使 LoftQ 发挥最佳效果,建议尽可能多地使用 LoRA 定位层,因为未定位的层无法应用 LoftQ。 这意味着传递 LoraConfig(..., target_modules="all-linear")
最有可能获得最佳结果。 此外,在使用 4 位量化时,您应该在量化配置中使用 nf4
作为量化类型,即 BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")
。
更便捷的方法
应用 LoftQ 初始化的一种更简单但更有限的方法是使用便捷函数 replace_lora_weights_loftq
。 这会将量化的 PEFT 模型作为输入,并将 LoRA 权重就地替换为 LoftQ 初始化的对应项。
from peft import replace_lora_weights_loftq
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="loftq" or loftq_config!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_loftq(peft_model)
replace_lora_weights_loftq
还允许您传递 callback
参数,以便您可以更好地控制应修改哪些层,这在经验上可以大大改善结果。 要查看更详细的示例,请查看此笔记本。
replace_lora_weights_loftq
仅实现 LoftQ 的一个迭代步骤。 这意味着仅更新 LoRA 权重,而不是迭代更新 LoRA 权重和量化的基础模型权重。 这可能会导致性能降低,但优点是我们可以使用从基础模型派生的原始量化权重,而不必保留修改后的量化权重的额外副本。 这种权衡是否值得取决于用例。
目前,replace_lora_weights_loftq
具有以下其他限制
- 模型文件必须存储为
safetensors
文件。 - 仅支持 bitsandbytes 4 位量化。
在量化指南中了解有关 PEFT 如何与量化协同工作的更多信息。
秩稳定 LoRA
初始化 LoraConfig 的另一种方法是使用秩稳定 LoRA (rsLoRA) 方法。 LoRA 架构在每次前向传递期间按一个固定标量缩放每个适配器,该标量在初始化时设置,并且取决于秩 r
。 标量在原始实现中由 lora_alpha/r
给出,但 rsLoRA 使用 lora_alpha/math.sqrt(r)
,这稳定了适配器并提高了使用更高 r
的性能潜力。
from peft import LoraConfig
config = LoraConfig(use_rslora=True, ...)
权重分解低秩适配 (DoRA)
此技术将权重的更新分解为两个部分:幅度和方向。 方向由普通 LoRA 处理,而幅度由单独的可学习参数处理。 这可以提高 LoRA 的性能,尤其是在低秩时。 有关 DoRA 的更多信息,请参阅 https://arxiv.org/abs/2402.09353。
from peft import LoraConfig
config = LoraConfig(use_dora=True, ...)
如果模型或 DoRA 适配器的某些部分被卸载到 CPU,您可以通过在 config.runtime_config
中使用 ephemeral_gpu_offload=True
来显着提高速度,但代价是一些临时的(短暂的)VRAM 开销。
from peft import LoraConfig, LoraRuntimeConfig
config = LoraConfig(use_dora=True, runtime_config=LoraRuntimeConfig(ephemeral_gpu_offload=True), ...)
带有 DoRA 适配器的 PeftModel
也可以使用 from_pretrained
方法以及 load_adapter
方法加载 ephemeral_gpu_offload=True
标志。
from peft import PeftModel
model = PeftModel.from_pretrained(base_model, peft_model_id, ephemeral_gpu_offload=True)
DoRA 针对评估模式下的模型或 dropout 设置为 0 时进行了优化(计算速度更快,占用内存更少)。 我们在这些时候重复使用基本结果以获得加速。 在 4090 上运行 dora finetuning,梯度累积设置为 2,最大步数设置为 20,命令为 CUDA_VISIBLE_DEVICES=0 time python examples/dora_finetuning/dora_finetuning.py --quantize --lora_dropout 0 --batch_size 16 --eval_step 2 --use_dora
,结果观察如下
不优化 | 优化后 | |
---|---|---|
train_runtime | 359.7298 | 279.2676 |
train_samples_per_second | 1.779 | 2.292 |
train_steps_per_second | 0.056 | 0.072 |
注意事项
- 目前,DoRA 仅支持 embedding、linear 和 Conv2d 层。
- DoRA 引入的开销比纯 LoRA 更大,因此建议合并权重以进行推理,请参阅 LoraModel.merge_and_unload()。
- DoRA 应该可以与使用 bitsandbytes 量化的权重(“QDoRA”)一起使用。但是,据报告,将 QDoRA 与 DeepSpeed Zero2 一起使用时会出现问题。
QLoRA 风格的训练
PEFT 中的默认 LoRA 设置将可训练权重添加到每个注意力模块的 query 和 value 层。但是 QLoRA 将可训练权重添加到 transformer 模型的所有线性层,可以提供与完全微调模型相当的性能。要像 QLoRA 中那样将 LoRA 应用于所有线性层,请设置 target_modules="all-linear"
(比按名称指定各个模块更容易,模块名称可能因架构而异)。
config = LoraConfig(target_modules="all-linear", ...)
使用 LoRA 进行内存高效的层复制
一种用于提高模型性能的方法是通过复制模型中的层来扩展模型,从而从给定大小的预训练模型构建更大的模型。 例如,如 SOLAR 论文中所述,将 7B 模型增加到 10B 模型。 PEFT LoRA 以内存高效的方式支持这种扩展,这种方式支持使用连接到层复制后层的 LoRA 适配器进行进一步微调。 复制的层不占用额外的内存,因为它们共享底层权重,因此唯一需要的额外内存是适配器权重的内存。 要使用此功能,您需要创建一个带有 layer_replication
参数的配置。
config = LoraConfig(layer_replication=[[0,4], [2,5]], ...)
假设原始模型有 5 层 [0, 1, 2, 3, 4]
,这将创建一个具有 7 层的模型,排列为 [0, 1, 2, 3, 2, 3, 4]
。 这遵循 mergekit 传递合并约定,其中指定为起始包含和结束排除元组的层序列堆叠在一起以构建最终模型。 最终模型中的每一层都获得其自己独特的 LoRA 适配器集。
Fewshot-Metamath-OrcaVicuna-Mistral-10B 是一个使用此方法在 Mistral-7B 上训练并扩展到 10B 的模型的示例。 adapter_config.json 显示了一个应用此方法进行微调的 LoRA 适配器配置示例。
对秩和 alpha (缩放) 的细粒度控制
默认情况下,所有以 LoRA 为目标的层都将具有相同的秩 r
和相同的 lora_alpha
(它决定 LoRA 缩放),具体取决于 LoraConfig 中的指定。 但是,在某些情况下,您可能希望为不同的层指示不同的值。 这可以通过将 rank_pattern
和 alpha_pattern
参数传递给 LoraConfig 来实现。 这些参数应该是字典,键是层名称,值是秩/alpha 值。 键可以是 正则表达式 (regex)。 未在 rank_pattern
和 alpha_pattern
中显式提及的所有 LoRA 层将采用默认的 r
和 lora_alpha
值。
为了举例说明,假设我们有一个具有以下结构的模型
>>> print(model)
Outer(
(foo): Linear(...)
(module): Middle(
(foo): Linear(...)
(foobar): Linear(...)
(module): Inner(
(foo): Linear(...)
(barfoo): Linear(...)
)
)
)
rank_pattern={"foo": 42}
将匹配所有 3 个foo
层。foobar
和barfoo
均不匹配。rank_pattern={"^foo": 42}
将仅匹配模型的foo
层,但module.foo
和module.module.foo
均不匹配。 这是因为在使用正则表达式时,^
表示“字符串的开头”,并且只有foo
以"foo"
开头,其他层名称都有前缀。rank_pattern={"^module.foo": 42}
仅匹配module.foo
,但不匹配module.module.foo
,原因相同。rank_pattern={"module.foo": 42}
同时匹配module.foo
和module.module.foo
,但不匹配foo
。rank_pattern={"^foo": 42, "^module.module.foo": 55}
分别匹配foo
和module.module.foo
,但不匹配module.foo
。- 无需指示
$
来标记匹配的结尾,因为 PEFT 会自动添加。
相同的逻辑适用于 alpha_pattern
。 如果您有疑问,请不要尝试使用复杂的正则表达式,只需传递每个具有不同秩/alpha 的模块的完整名称,并在前面加上 ^
前缀,您就应该没问题了。
优化器
LoRA 训练可以选择性地包含专用优化器。 目前,唯一的此类优化器是 LoRA+。
LoRA+ 优化的 LoRA
LoRA 训练可以使用 LoRA+ 进行优化,后者对适配器矩阵 A 和 B 使用不同的学习率,经证明可将微调速度提高 2 倍,性能提高 1-2%。
from peft import LoraConfig, get_peft_model
from peft.optimizers import create_loraplus_optimizer
from transformers import Trainer
import bitsandbytes as bnb
base_model = ...
config = LoraConfig(...)
model = get_peft_model(base_model, config)
optimizer = create_loraplus_optimizer(
model=model,
optimizer_cls=bnb.optim.Adam8bit,
lr=5e-5,
loraplus_lr_ratio=16,
)
scheduler = None
...
trainer = Trainer(
...,
optimizers=(optimizer, scheduler),
)
与 LoRA 一起高效地训练 tokens
有时,不仅需要更改某些层的权重,还需要添加新的 tokens。 对于较大的模型,这可能是一项非常耗费内存的工作。 PEFT LoRA 适配器支持 trainable_token_indices
参数,该参数允许在微调具有 LoRA 的特定层的同时调整其他 tokens。 此方法仅训练您指定的 tokens,而保持所有其他 tokens 不受影响。 与训练整个 embedding 矩阵相比,这节省了内存,并且不会丢弃现有 token embeddings 的已学习上下文。 在底层,此方法使用 TrainableTokensModel 的层。
# for layer 'embed_tokens'
config = LoraConfig(trainable_token_indices=[idx_1, idx_2, ...], ...)
# specific embedding layer
config = LoraConfig(trainable_token_indices={'emb_tokens': [idx_1, idx_2, ...]}, ...)
在下面的代码片段中,我们展示了如何向模型添加新 tokens 以及如何在模型中的其他层旁边训练它。
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import get_peft_model, LoraConfig
base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
# we define our new tokens and add them to the tokenizer as special tokens
special_tokens = ['<|start_think|>', '<|stop_think|>']
tokenizer.add_special_tokens({'additional_special_tokens': special_tokens})
# make room for new tokens in the embedding matrix if it isn't big enough already
base_model.resize_token_embeddings(max(len(tokenizer), base_model.model.embed_tokens.num_embeddings)
# typical LoRA config with `trainable_token_indices` targeting embedding layer `embed_tokens`
# and specifically our new tokens we just added
lora_config = LoraConfig(
target_modules='all-linear',
trainable_token_indices={'embed_tokens': tokenizer.convert_tokens_to_ids(special_tokens)},
)
peft_model = get_peft_model(base_model, lora_config)
# proceed to train the model like normal
[...]
token 权重是您的适配器状态字典的一部分,并与 LoRA 权重一起保存。 如果我们使用 modules_to_save=['embed_tokens']
进行完全微调,我们将把完整的 embedding 矩阵存储在检查点中,从而导致文件更大。
为了稍微说明可以节省多少 VRAM,在完全训练 embedding 矩阵 (modules_to_save=["embed_tokens"]
)、使用 LoRA 用于 embedding 矩阵 (target_modules=[..., "embed_tokens"]
,秩 32) 和可训练 tokens (trainable_token_indices=[...]
,6 个 tokens) 之间对上述示例进行了初步比较。 可训练 tokens 使用的 VRAM 与 LoRA 大致相同(15,562MB vs. 15,581MB),同时特定于 tokens,并且比完全训练 embedding 矩阵节省了约 1GB 的 VRAM。
将 LoRA 权重合并到基础模型中
虽然 LoRA 训练速度明显更快且训练时间更短,但在推理期间,您可能会由于单独加载基础模型和 LoRA 适配器而遇到延迟问题。 为了消除延迟,请使用 merge_and_unload() 函数将适配器权重与基础模型合并。 这使您可以将新合并的模型用作独立模型。 merge_and_unload() 函数不会将适配器权重保留在内存中。
下面是一个图表,解释了 LoRA 适配器合并的直觉

我们在下面的代码片段中展示了如何使用 PEFT 运行它。
from transformers import AutoModelForCausalLM
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model.merge_and_unload()
如果您需要保留权重的副本,以便以后可以取消合并适配器或删除和加载不同的适配器,则应改为使用 merge_adapter() 函数。 现在,您可以选择使用 unmerge_adapter() 返回基础模型。
from transformers import AutoModelForCausalLM
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model.merge_adapter()
# unmerge the LoRA layers from the base model
model.unmerge_adapter()
add_weighted_adapter() 函数可用于根据用户在 weights
参数中提供的加权方案将多个 LoRA 合并到新的适配器中。 下面是一个端到端示例。
首先加载基础模型
from transformers import AutoModelForCausalLM
from peft import PeftModel
import torch
base_model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.1", torch_dtype=torch.float16, device_map="auto"
)
然后我们加载第一个适配器
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id, adapter_name="sft")
然后加载不同的适配器并将其与第一个适配器合并
weighted_adapter_name = "sft-dpo"
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")
model.add_weighted_adapter(
adapters=["sft", "dpo"],
weights=[0.7, 0.3],
adapter_name=weighted_adapter_name,
combination_type="linear"
)
model.set_adapter(weighted_adapter_name)
对于 combination_type
,有几种受支持的方法。 有关更多详细信息,请参阅 文档。 请注意,当使用 torch.float16
或 torch.bfloat16
作为数据类型时,不支持作为 combination_type
的“svd”。
现在,执行推理
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
prompt = "Hey, are you conscious? Can you talk to me?"
inputs = tokenizer(prompt, return_tensors="pt")
inputs = {k: v.to("cuda") for k, v in inputs.items()}
with torch.no_grad():
generate_ids = model.generate(**inputs, max_length=30)
outputs = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(outputs)
加载适配器
可以使用 load_adapter() 将适配器加载到预训练模型上,这对于尝试权重未合并的不同适配器非常有用。 使用 set_adapter() 函数设置活动适配器权重。
from transformers import AutoModelForCausalLM
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
# load different adapter
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")
# set adapter as active
model.set_adapter("dpo")
要返回基础模型,您可以使用 unload() 卸载所有 LoRA 模块,或使用 delete_adapter() 完全删除适配器。
# unload adapter
model.unload()
# delete adapter
model.delete_adapter("dpo")
在同一批次中使用不同的 LoRA 适配器进行推理
通常,每个推理批次都必须在 PEFT 中使用相同的适配器。 这有时会很烦人,因为我们可能有批次包含旨在与不同 LoRA 适配器一起使用的样本。 例如,我们可能有一个在英语中效果良好的基础模型和另外两个 LoRA 适配器,一个用于法语,一个用于德语。 通常,我们必须拆分批次,以便每个批次仅包含一种语言的样本,我们不能在同一批次中组合不同的语言。
值得庆幸的是,可以使用 adapter_name
参数在同一批次中混合不同的 LoRA 适配器。 下面,我们展示了一个示例,说明这在实践中是如何工作的。 首先,让我们加载基础模型、英语和两个适配器,法语和德语,如下所示
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
model_id = ...
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
# load the LoRA adapter for French
peft_model = PeftModel.from_pretrained(model, <path>, adapter_name="adapter_fr")
# next, load the LoRA adapter for German
peft_model.load_adapter(<path>, adapter_name="adapter_de")
现在,我们想在包含所有三种语言的样本上生成文本:前三个样本是英语,接下来的三个是法语,最后三个是德语。 我们可以使用 adapter_names
参数来指定要用于每个样本的适配器。 由于我们的基础模型用于英语,因此我们对这些样本使用特殊字符串 "__base__"
。 对于接下来的三个样本,我们指示法语 LoRA 微调的适配器名称,在本例中为 "adapter_fr"
。 对于最后三个样本,我们指示德语 LoRA 微调的适配器名称,在本例中为 "adapter_de"
。 这样,我们可以在一个批次中使用基础模型和两个适配器。
inputs = tokenizer(
[
"Hello, my dog is cute",
"Hello, my cat is awesome",
"Hello, my fish is great",
"Salut, mon chien est mignon",
"Salut, mon chat est génial",
"Salut, mon poisson est super",
"Hallo, mein Hund ist süß",
"Hallo, meine Katze ist toll",
"Hallo, mein Fisch ist großartig",
],
return_tensors="pt",
padding=True,
)
adapter_names = [
"__base__", "__base__", "__base__",
"adapter_fr", "adapter_fr", "adapter_fr",
"adapter_de", "adapter_de", "adapter_de",
]
output = peft_model.generate(**inputs, adapter_names=adapter_names, max_new_tokens=20)
请注意,这里的顺序无关紧要,即批次中的样本不需要像上面的示例中那样按适配器分组。 我们只需要确保 adapter_names
参数与样本正确对齐即可。
此外,相同的方法也适用于 modules_to_save
功能,该功能允许跨不同的 LoRA 适配器保存和重用特定的神经网络层,例如用于分类任务的自定义头。
注意事项
使用此功能有一些缺点,即
- 它仅适用于推理,不适用于训练。
- 使用
with model.disable_adapter()
上下文禁用适配器优先于adapter_names
。 - 当某些适配器权重使用
merge_adapter
方法与基础权重合并时,您无法传递adapter_names
。 请首先调用model.unmerge_adapter()
取消合并所有适配器。 - 出于显而易见的原因,这不能在调用
merge_and_unload()
之后使用,因为在这种情况下,所有 LoRA 适配器都将合并到基础权重中。 - 此功能当前不适用于 DoRA,因此如果您想使用它,请在您的
LoraConfig
中设置use_dora=False
。 modules_to_save
功能目前仅支持Linear
、Embedding
、Conv2d
和Conv1d
类型的层。- 使用
adapter_names
进行推理时,预计会有开销,尤其是在批次中不同适配器的数量很多时。 这是因为批次大小实际上减少到每个适配器的样本数。 如果运行时性能是您的首要任务,请尝试以下操作