Learnly
LLM Fine Tuning/Глава 2/Урок 4

LoRA и PEFT

LoRA и PEFT: Эффективная

Parameter-Efficient Fine-Tuning (PEFT) позволяет адаптировать крупные модели, обучая небольшое количество дополнительных параметров, сохраняя при этом базовую модель неизменной. Наиболее широко используемым методом PEFT является LoRA (Low-Rank Adaptation), которая внедряет обучаемые low-rank обновления в линейные слои. В результате количество обучаемых параметров часто сокращается примерно на 90%, сохраняя при этом производительность.

Когда использовать PEFT

  • У вас ограниченный бюджет вычислительных ресурсов или памяти
  • Вам нужно быстро адаптировать базовую модель к нескольким задачам/областям
  • Вам нужны быстрые итерации и небольшие артефакты (веса адаптеров обычно составляют несколько МБ)

Понимание LoRA

LoRA стала самым распространенным методом PEFT. Она работает путем добавления небольших матриц разложения по рангу к весам внимания, что обычно сокращает количество обучаемых параметров примерно на 90%.

LoRA (Low-Rank Adaptation) - это метод эффективной по параметрам, который замораживает предобученные веса модели и внедряет обучаемые матрицы разложения по рангу в слои модели. Вместо обучения всех параметров модели во время, LoRA разлагает обновления весов на меньшие матрицы через low-rank decomposition, что значительно уменьшает количество обучаемых параметров, сохраняя при этом производительность модели. Например, при применении к GPT-3 175B, LoRA сократила количество обучаемых параметров в 10,000 раз и требования к оперативной памяти GPU в 3 раза по сравнению с полным fine-tuning. Подробнее о LoRA можно прочитать в документе LoRA.

LoRA работает путем добавления пар матриц разложения по рангу к слоям трансформера, обычно сосредотачиваясь на весах внимания. Во время инференса эти веса адаптера можно объединить с базовой моделью, что не приводит к дополнительной задержке. LoRA особенно полезна для адаптации больших языковых моделей к определенным задачам или областям, сохраняя при этом управляемые требования к ресурсам.

Загрузка адаптеров LoRA

Адаптеры можно загрузить в предобученную модель с помощью load_adapter(), что удобно для использования различных адаптеров, чьи веса не объединяются. Активные веса адаптера можно задать с помощью функции set_adapter(). Чтобы вернуться к базовой модели, можно использовать unload(), чтобы выгрузить все модули LoRA. Это упрощает переключение между различными специфическими для задачи весами.

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("<base_model_name>")
peft_model_id = "<peft_adapter_id>"
model = PeftModel.from_pretrained(base_model, peft_model_id)

lora_load_adapter

Объединение адаптеров LoRA

После обучения с LoRA вы можете захотеть объединить веса адаптера обратно в базовую модель для более удобного развёртывания. Это создает единую модель с объединенными весами, устраняя необходимость отдельно загружать адаптеры во время инференса.

Процесс слияния требует внимательного управления памятью и точностью. Поскольку вам необходимо загрузить одновременно базовую модель и веса адаптера, убедитесь, что доступно достаточное количество оперативной памяти GPU/CPU. Использование device_map="auto" в transformers поможет с автоматическим управлением памятью. Сохраняйте непостоянную точность (например, float16) на протяжении всего процесса, соответствуя точности, используемой во время обучения, и сохраняйте объединенную модель в том же формате для развёртывания. Перед развёртыванием всегда проверяйте объединенную модель, сравнивая её выходные данные и показатели производительности с версией на основе адаптеров.

Адаптеры также удобны для переключения между различными задачами или доменами. Вы можете загрузить базовую модель и веса адаптера по-отдельности. Это позволяет быстро переключаться между различными специфичными для задачи весами.

При реализации методов PEFT начинайте с небольших значений ранга (4-8) для LoRA и отслеживайте потерю во время обучения. Используйте валидационные наборы для предотвращения переобучения и сравнивайте результаты с полным дообучением, если возможно. Эффективность различных методов может варьироваться в зависимости от задачи, поэтому эксперименты играют ключевую роль.

OLoRA

OLoRA использует декомпозицию QR для инициализации адаптеров LoRA. OLoRA транслирует базовые веса модели с помощью факторов их QR-разложений, т.е. мутирует веса перед выполнением любого обучения на них. Этот подход значительно улучшает стабильность, ускоряет скорость сходимости и в конечном итоге обеспечивает более высокое производительность.

Использование TRL с PEFT

Методы PEFT можно комбинировать с TRL (Transformers Reinforcement Learning) для эффективного дообучения. Это интеграция особенно полезна для RLHF (Reinforcement Learning from Human Feedback), так как она снижает требования к памяти.

from peft import LoraConfig
from trl import SFTTrainer

# Загрузка модели с конфигурацией PEFT
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

trainer = SFTTrainer(
    model="your-model-name",
    train_dataset=dataset["train"]
    peft_config=lora_config
)

Базовая реализация слияния

После обучения адаптера LoRA вы можете объединить веса адаптера обратно в базовую модель. Вот как это сделать:

import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel

# 1. Загрузка базовой модели
base_model = AutoModelForCausalLM.from_pretrained(
    "base_model_name",
    dtype=torch.bfloat16,
    device_map="auto"
)

# 2. Загрузка модели PEFT с адаптером
peft_model = PeftModel.from_pretrained(
    base_model,
    "path/to/adapter",
    dtype=torch.bfloat16
)

# 3. Слияние весов адаптера с базовой моделью
try:
    merged_model = peft_model.merge_and_unload()
except RuntimeError as e:
    print(f"Слияние не удалось: ")
    # Реализуйте стратегию откат или оптимизацию памяти

# 4. Сохранение объединенной модели
merged_model.save_pretrained("path/to/save/merged_model")

При возникновении несоответствий размеров в сохраненной модели убедитесь, что также сохраняете токенайзер:

# Save both model and tokenizer
tokenizer = AutoTokenizer.from_pretrained("base_model_name")
merged_model.save_pretrained("path/to/save/merged_model")
tokenizer.save_pretrained("path/to/save/merged_model")

Быстрый запуск с TRL + LoRA

trl-тренер SFTTrainer работает штатно с PEFT. Подготовьте LoraConfig, передайте трениру, и обучайте только веса адаптера.

from peft import LoraConfig
from trl import SFTTrainer, SFTConfig

# 1) Configure LoRA
peft_config = LoraConfig(
    r=8,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# 2) Create trainer (example)
trainer = SFTTrainer(
    model=model,
    args=SFTConfig(output_dir="lora-adapter", num_train_epochs=1, per_device_train_batch_size=2, packing=True),
    train_dataset=dataset["train"],
    peft_config=peft_config,
)
trainer.train()

После обучения у вас есть два варианта:

  • Загружайте адаптеры во время инференса вместе с базовой моделью, или
  • Объединяйте адаптеры с базовой моделью для упрощения развёртывания.

Ресурсы

AI-тест
1 / 5

Какую область Памяти увеличивает LoRA при обучении?