Transformers documentation

Параметрически эффективная дообучение

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

and get access to the augmented documentation experience

to get started

Параметрически эффективная дообучение

Методы Parameter-efficient fine-tuning (PEFT) обучают лишь небольшое количество дополнительных параметров модели (адаптеров) поверх предобученной модели. Поскольку обновляются только параметры адаптеров, оптимизатор отслеживает значительно меньше градиентов и состояний, что существенно снижает потребление памяти. Адаптеры легковесны, что делает их удобными для обмена, хранения и загрузки.

Transformers напрямую интегрируется с библиотекой PEFT через PeftAdapterMixin, который добавлен во все классы PreTrainedModel. Вы можете загружать, добавлять, обучать, переключать и удалять адаптеры, не оборачивая модель в отдельный PeftModel. Поддерживаются все методы PEFT, не основанные на обучении промптов (LoRA, IA3, AdaLoRA). Для методов, основанных на промптах, таких как prompt tuning и prefix tuning, необходимо использовать библиотеку PEFT напрямую.

Установите PEFT, чтобы начать работу. Для интеграции требуется peft >= 0.20.0.

pip install -U peft

Добавить адаптер

Создайте конфигурацию PEFT, например LoraConfig, и привяжите её к модели с помощью add_adapter().

from peft import LoraConfig, TaskType
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("google/gemma-2-2b")

lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    inference_mode=False,
    r=8,
    lora_alpha=32,
    lora_dropout=0.1,
)

model.add_adapter(lora_config, adapter_name="my_adapter")

Полная дообучение конкретных слоёв

Чтобы обучать дополнительные модули вместе с адаптером (например, головную часть языковой модели), укажите их в modules_to_save. modules_to_save задаёт слои, которые полностью дообучаются вместе с адаптером, поэтому все их параметры обновляются. Это полезно, когда определённые слои требуют обновления, например головная часть языковой модели (lm_head), при адаптации каузальной LM для классификации последовательностей.

lora_config = LoraConfig(
    modules_to_save=["lm_head"],
    ...
)
model.add_adapter(lora_config)

Выбор слоев для адаптации

Для распространённых архитектур (Llama, Gemma, Qwen и др.) в PEFT заданы предопределённые целевые модули по умолчанию (например, q_proj и v_proj), поэтому указывать target_modules не требуется. Если нужно выбрать другие слои или у модели нет предопределённых целей, явно передайте target_modules в виде списка имён модулей или регулярного выражения.

lora_config = LoraConfig(
    target_modules=["q_proj", "k_proj"],
    ...
)
model.add_adapter(lora_config)

Обучение

Передайте модель с подключенным адаптером в Trainer и вызовите train(). Trainer обновляет только параметры адаптера (те, у которых requires_grad=True), так как базовая модель заморожена.

from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
)

trainer.train()

В процессе обучения контрольные точки Trainer содержат только веса адаптера (adapter_model.safetensors) и конфигурацию (adapter_config.json), что позволяет сохранять контрольные точки небольшого размера. Базовая модель в них не включается.

После обучения сохраните итоговый адаптер с помощью save_pretrained().

model.save_pretrained("./my_adapter")

Возобновление из контрольной точки

Trainer автоматически обнаруживает контрольные точки адаптеров при возобновлении обучения. Trainer просматривает каталог контрольной точки в поисках подкаталогов, содержащих веса адаптеров, и перезагружает каждый адаптер с правильным обучаемым состоянием.

trainer.train(resume_from_checkpoint="./output/checkpoint-1000")

Распределённое обучение

Адаптеры PEFT работают с распределённым обучением из коробки.

Для ZeRO-3 Trainer передаёт exclude_frozen_parameters=True при сохранении контрольных точек с моделью PEFT. Замороженные веса базовой модели пропускаются. Сохраняются только обучаемые параметры адаптера, что уменьшает размер контрольной точки и время сохранения.

Для FSDP Trainer обновляет политику автообёртки FSDP, чтобы корректно обрабатывать слои LoRA. Для QLoRA (квантованная базовая модель + LoRA) Trainer также настраивает политику смешанной точности в соответствии с типом данных хранения квантования.

Вы можете загрузить адаптеры PEFT на базовую модель с тензорным параллелизмом и позволить PEFT самостоятельно распределять веса адаптеров. Для загрузки адаптера требуется peft >= 0.21.1. О тренировке с TP см. Тензорный параллелизм.

Загрузка адаптера

Для загрузки адаптера репозиторий на Hub или локальный каталог должны содержать файл adapter_config.json и веса адаптера.

from_pretrained
load_adapter

from_pretrained() автоматически обнаруживает адаптеры. При обнаружении adapter_config.json метод читает поле base_model_name_or_path, чтобы загрузить нужную базовую модель, а затем загружает адаптер поверх неё.

from transformers import AutoModelForCausalLM

# Automatically loads the base model and attaches the adapter
model = AutoModelForCausalLM.from_pretrained("klcsp/gemma7b-lora-alpaca-11-v1")

Для больших моделей загрузите квантованную версию с точностью 8 бит или 4 бита с помощью bitsandbytes, чтобы сэкономить память. Добавьте device_map="auto", чтобы распределить модель по доступному оборудованию.

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

model = AutoModelForCausalLM.from_pretrained(
    "klcsp/gemma7b-lora-alpaca-11-v1",
    quantization_config=BitsAndBytesConfig(load_in_8bit=True),
    device_map="auto",
)

Управление несколькими адаптерами

Модель может одновременно содержать несколько адаптеров. Добавляйте адаптеры с уникальными именами и переключайтесь между ними по мере необходимости.

from peft import LoraConfig

model.add_adapter(LoraConfig(r=8, lora_alpha=32), adapter_name="adapter_1")
model.add_adapter(LoraConfig(r=16, lora_alpha=64), adapter_name="adapter_2")

Используйте set_adapter() для активации конкретного адаптера. Остальные адаптеры отключаются, но остаются в памяти.

model.set_adapter("adapter_2")

enable_adapters() включает все подключенные адаптеры, а disable_adapters() отключает их все.

# Disable all adapters for base model inference
model.disable_adapters()

# Re-enable all adapters
model.enable_adapters()

Используйте active_adapters(), чтобы посмотреть, какие адаптеры активны в данный момент.

model.active_adapters()
# ["adapter_1"]

Удалите ненужные адаптеры с помощью delete_adapter(), чтобы освободить память.

model.delete_adapter("adapter_1")

Горячая замена адаптеров

Загрузка нового адаптера при каждой обработке запроса приводит к выделению новой памяти. Если модель скомпилирована с помощью torch.compile, каждый новый адаптер вызывает повторную компиляцию. Hotswapping заменяет веса адаптера на месте, что позволяет избежать обеих проблем. Поддерживаются только LoRA-адаптеры.

Передайте hotswap=True при загрузке адаптера LoRA, чтобы заменить его веса в существующем слоте адаптера. Установите adapter_name равным имени заменяемого адаптера (по умолчанию используется имя "default").

model = AutoModel.from_pretrained(...)
# Load the first adapter normally
model.load_adapter(adapter_path_1)
# Generate outputs with adapter 1
...
# Hotswap the second adapter in-place
model.load_adapter(adapter_path_2, hotswap=True, adapter_name="default")
# Generate outputs with adapter 2

torch.compile

Для скомпилированных моделей вызовите enable_peft_hotswap() до загрузки первого адаптера и до компиляции.

model = AutoModel.from_pretrained(...)
max_rank = ...  # highest rank among all LoRAs you'll load
model.enable_peft_hotswap(target_rank=max_rank)
model.load_adapter(adapter_path_1, adapter_name="default")
model = torch.compile(model, ...)
output_1 = model(...)

# Hotswap without recompilation
model.load_adapter(adapter_path_2, adapter_name="default")
output_2 = model(...)

Аргумент target_rank задаёт максимальный ранг среди всех загружаемых адаптеров LoRA. Если у вас есть адаптеры с рангом 8 и рангом 16, передайте target_rank=16. По умолчанию значение равно 128.

После вызова enable_peft_hotswap все последующие вызовы load_adapter по умолчанию используют hotswap. Чтобы отключить hotswap, явно передайте hotswap=False.

Повторная компиляция всё ещё может произойти, если подменяемый адаптер охватывает больше слоёв, чем начальный адаптер. Загрузите сначала адаптер, охватывающий наибольшее количество слоёв, чтобы избежать повторной компиляции.

Оберните код в with torch._dynamo.config.patch(error_on_recompile=True), чтобы обнаруживать неожиданную перекомпиляцию. Если перекомпиляция обнаруживается, несмотря на выполнение описанных выше шагов, создайте issue в PEFT с воспроизводимым примером.

Дальнейшие шаги

Update on GitHub