PEFT documentation

模型合并

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.21.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

模型合并

为每个任务单独训练模型可能成本高昂、占用大量存储空间,且模型无法学习新信息以提升性能。多任务学习可以通过训练一个模型来学习多个任务,从而克服其中一些局限性,但其训练成本高昂,且为其设计数据集颇具挑战。模型合并通过将多个预训练模型整合为一个模型,提供了应对这些挑战的解决方案,使其具备各个独立模型的综合能力,且无需任何额外训练。

PEFT 提供了多种模型合并方法,例如线性组合或 SVD 组合。本指南重点介绍两种通过消除冗余参数来更高效地合并 LoRA 适配器的方法:

  • TIES - TrIm, Elect, and Merge (TIES) is a three-step method for merging models. First, redundant parameters are trimmed, then conflicting signs are resolved into an aggregated vector, and finally the parameters whose signs are the same as the aggregate sign are averaged. This method takes into account that some values (redundant and sign disagreement) can degrade performance in the merged model.
  • DARE - Drop And REscale 是一种可用于为 TIES 等其他模型合并方法做准备的方法。它通过根据丢弃率随机丢弃参数,并对剩余参数进行重新缩放来工作。这有助于减少多个模型之间冗余且可能相互干扰的参数数量。

模型通过 add_weighted_adapter() 方法进行合并,具体的模型合并方法由 combination_type 参数指定。

合并方法

使用 TIES 和 DARE 时,通过设置 combination_type 和 density 为要保留的单个模型权重的值,即可启用合并。例如,让我们合并三个经过微调的 TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T 模型:tinyllama_lora_nobots、tinyllama_lora_sql 和 tinyllama_lora_adcopy。

当您尝试使用 TIES 合并完全训练好的模型时,需要注意每个模型可能已添加到嵌入层中的特殊标记,这些标记不属于原始检查点词汇表的一部分。这可能会引发问题,因为每个模型可能将特殊标记添加到了相同的嵌入位置。如果存在这种情况,您应使用 resize_token_embeddings 方法,以避免在相同的嵌入索引处合并特殊标记。


如果你只是合并从同一基础模型训练得到的 LoRA 适配器,这通常不会成为问题。

加载基础模型,并使用 load_adapter() 方法加载适配器并为每个适配器指定名称:

from peft import PeftConfig, PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

config = PeftConfig.from_pretrained("smangrul/tinyllama_lora_norobots")
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path, load_in_4bit=True, device_map="auto").eval()
tokenizer = AutoTokenizer.from_pretrained("smangrul/tinyllama_lora_norobots")

model.config.vocab_size = 32005
model.resize_token_embeddings(32005)

model = PeftModel.from_pretrained(model, "smangrul/tinyllama_lora_norobots", adapter_name="norobots")
_ = model.load_adapter("smangrul/tinyllama_lora_sql", adapter_name="sql")
_ = model.load_adapter("smangrul/tinyllama_lora_adcopy", adapter_name="adcopy")

使用 add_weighted_adapter() 方法设置适配器、权重、adapter_name、combination_type 和 density。

TIES
DARE

大于 1.0 的权重值通常能产生更好的结果,因为它们能保留正确的尺度。权重的良好默认起始值是将所有值设置为 1.0。

adapters = ["norobots", "adcopy", "sql"]
weights = [2.0, 1.0, 1.0]
adapter_name = "merge"
density = 0.2
model.add_weighted_adapter(adapters, weights, adapter_name, combination_type="ties", density=density)

使用 set_adapter() 方法将新合并的模型设置为活动模型。

model.set_adapter("merge")

现在,您可以将合并后的模型作为经过指令微调的模型,用于撰写广告文案或 SQL 查询!

instruct
广告文案
SQL
device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
messages = [
    {"role": "user", "content": "Write an essay about Generative AI."},
]
text = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
inputs = tokenizer(text, return_tensors="pt")
inputs = {k: v.to(device) for k, v in inputs.items()}
outputs = model.generate(**inputs, max_new_tokens=256, do_sample=True, top_p=0.95, temperature=0.2, repetition_penalty=1.2, eos_token_id=tokenizer.eos_token_id)
print(tokenizer.decode(outputs[0]))

合并 (IA)³ 模型

(IA)³ 模型支持对适配器进行线性合并。要在 (IA)³ 模型中合并适配器,请使用 IA3Model 类中的 add_weighted_adapter 方法。该方法与 LoraModel 中使用的 add_weighted_adapter 方法类似,主要区别在于没有 combination_type 参数。例如,要将三个 (IA)³ 适配器合并到一个 PEFT 模型中,操作如下:

adapters = ["adapter1", "adapter2", "adapter3"]
weights = [0.4, 0.3, 0.3]
adapter_name = "merge"
model.add_weighted_adapter(adapters, weights, adapter_name)

建议权重之和为 1.0,以保持模型的尺度。然后可以使用 set_adapter 方法将合并后的模型设置为活动模型:

model.set_adapter("merge")
Update on GitHub