PEFT documentation
Слияние моделей
Слияние моделей
Обучение отдельной модели для каждой задачи может быть дорогостоящим, занимать много места на диске, а модели не способны усваивать новую информацию для улучшения своих показателей. Многозадачное обучение способно преодолеть некоторые из этих ограничений, обучая модель нескольким задачам, однако его обучение обходится дорого, а проектирование набора данных для него представляет сложную задачу. Слияние моделей предлагает решение этих проблем, объединяя несколько предварительно обученных моделей в одну, наделяя её совокупными возможностями каждой отдельной модели без какого-либо дополнительного обучения.
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")Установите адаптеры, веса, adapter_name, combination_type и density с помощью метода add_weighted_adapter().
Значения весов, превышающие 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)adapters = ["norobots", "adcopy", "sql"]
weights = [2.0, 0.3, 0.7]
adapter_name = "merge"
density = 0.2
model.add_weighted_adapter(adapters, weights, adapter_name, combination_type="dare_ties", density=density)Установите недавно объединённую модель в качестве активной с помощью метода set_adapter().
model.set_adapter("merge")Теперь вы можете использовать объединенную модель как модель, настроенную на выполнение инструкций, для написания рекламных текстов или 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]))device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
messages = [
{"role": "system", "content": "Create a text ad given the following product and description."},
{"role": "user", "content": "Product: Sony PS5 PlayStation Console\nDescription: The PS5 console unleashes new gaming possibilities that you never anticipated."},
]
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=128, 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]))device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
text = """Table: 2-11365528-2
Columns: ['Team', 'Head Coach', 'President', 'Home Ground', 'Location']
Natural Query: Who is the Head Coach of the team whose President is Mario Volarevic?
SQL Query:"""
inputs = tokenizer(text, return_tensors="pt")
inputs = {k: v.to(device) for k, v in inputs.items()}
outputs = model.generate(**inputs, max_new_tokens=64, repetition_penalty=1.1, eos_token_id=tokenizer("</s>").input_ids[-1])
print(tokenizer.decode(outputs[0]))Объединение моделей (IA)³
Модели (IA)³ обеспечивают линейное слияние адаптеров. Чтобы объединить адаптеры в модели (IA)³, используйте метод add_weighted_adapter из класса IA3Model. Этот метод аналогичен методу add_weighted_adapter, используемому в LoraModel, с ключевым отличием в отсутствии параметра 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")