ЧТО ТАКОЕ LoRA И ПОЧЕМУ ОНА ПОБЕДИЛА
Full fine-tuning LLM — это переобучение всех весов модели. Для 7B параметров в fp16 нужно держать в памяти сами веса, градиенты и состояния оптимизатора Adam. По грубой прикидке это 14 GB на веса плюс ещё столько же на градиенты плюс вдвое больше на моменты Adam — суммарно за 80 GB. То есть A100 на 80 GB, и то впритык. Дорого, медленно, для большинства команд недоступно.
LoRA (Low-Rank Adaptation) решает проблему иначе. Идея из статьи Microsoft 2021 года: изменение весов при дообучении имеет низкий эффективный ранг. Значит вместо того чтобы двигать всю матрицу весов W размером d×d, можно заморозить её и добавить рядом две маленькие матрицы: A размером d×r и B размером r×d, где r (ранг) — маленькое число, обычно 8–64. Обучаем только A и B. Финальный forward: h = Wx + BAx, где BA — это и есть выученная поправка.
Математика простая, а эффект огромный. Для той же 7B модели обучаемых параметров становится не 7 миллиардов, а несколько миллионов. Памяти под оптимизатор — копейки, потому что Adam хранит моменты только для обучаемых весов. Это и есть PEFT — Parameter-Efficient Fine-Tuning, зонтичный термин для целого семейства методов, где LoRA — самый популярный представитель.
ПОЧЕМУ ЭТО ДЁШЕВО: ЦИФРЫ
Главная экономия — не только на памяти обучения, но и на инференсе и хранении. Один базовый чекпоинт + десятки адаптеров под разные задачи вместо десятков полных копий модели.
- Память. QLoRA (LoRA поверх 4-битной квантованной базы) позволяет тюнить 7–13B модель на потребительской карте с 16–24 GB VRAM. 70B влезает в 48 GB, что раньше звучало как фантастика.
- Размер артефакта. Адаптер для 7B при ранге 16 весит примерно 30–80 MB против 14 GB полного чекпоинта. Его можно закоммитить в репозиторий, гонять по CI, раздавать команде.
- Время. На датасете в несколько тысяч примеров тюнинг 7B укладывается в 1–3 часа на одной современной GPU. Аренда такой карты — считанные доллары за прогон.
- Переключение задач. Меняешь адаптер за миллисекунды без перезагрузки базовой модели. Один сервер обслуживает много «специализаций».
QLoRA, DoRA И ДРУГИЕ ВАРИАНТЫ — ЧТО ВЫБРАТЬ
За несколько лет LoRA обросла модификациями. Свежие релизы и форки инструментов удобно отслеживать в каталоге REDDYX, но базовый выбор в 2026 такой:
| Метод | Суть | VRAM (7B) | Когда брать |
|---|---|---|---|
| Full FT | Все веса | ~80 GB+ | Много данных, есть кластер, нужен максимум качества |
| LoRA | Адаптеры на fp16 базе | ~24–40 GB | Есть 1 карта уровня A100/4090, скорость важна |
| QLoRA | Адаптеры на 4-бит базе | ~10–16 GB | Потребительская GPU, бюджет минимальный |
| DoRA | Разделяет магнитуду и направление | ~как LoRA | Хочешь ближе к full FT при том же ранге |
По замерам сообщества QLoRA теряет минимум качества относительно обычной LoRA при кратно меньшей памяти — поэтому для большинства прикладных задач это разумный дефолт. DoRA часто даёт небольшой прирост на низких рангах, но добавляет накладных расходов; берите её, если LoRA упирается в потолок качества, а поднимать ранг не хочется.
РАБОЧИЙ ПРИМЕР: QLoRA НА СВОИХ ДАННЫХ
Ниже минимальный, но полноценный скрипт на связке transformers + peft + trl + bitsandbytes. Формат данных — JSONL, где каждая строка имеет поле text с готовым промптом в chat-шаблоне модели.
from datasets import load_dataset
from transformers import (AutoModelForCausalLM, AutoTokenizer,
BitsAndBytesConfig)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer, SFTConfig
import torch
model_id = "meta-llama/Llama-3.1-8B-Instruct"
# 4-битная загрузка базы — это и есть QLoRA
bnb = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
tok = AutoTokenizer.from_pretrained(model_id)
tok.pad_token = tok.eos_token
model = AutoModelForCausalLM.from_pretrained(
model_id, quantization_config=bnb, device_map="auto"
)
model = prepare_model_for_kbit_training(model)
lora = LoraConfig(
r=16, lora_alpha=32, lora_dropout=0.05,
bias="none", task_type="CAUSAL_LM",
# вешаем адаптеры на все линейные слои внимания и MLP
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
)
model = get_peft_model(model, lora)
model.print_trainable_parameters() # ~0.5% параметров обучаемы
ds = load_dataset("json", data_files="train.jsonl", split="train")
cfg = SFTConfig(
output_dir="out-adapter",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=8, # эффективный батч = 16
learning_rate=2e-4,
warmup_ratio=0.03,
lr_scheduler_type="cosine",
bf16=True,
logging_steps=10,
save_strategy="epoch",
dataset_text_field="text",
max_seq_length=2048,
)
trainer = SFTTrainer(model=model, args=cfg, train_dataset=ds)
trainer.train()
trainer.save_model("out-adapter") # сохранится ТОЛЬКО адаптер, ~50 MB
После обучения адаптер подгружается к базовой модели за секунду:
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
model = PeftModel.from_pretrained(base, "out-adapter")
# при желании слить в один вес для продакшена:
merged = model.merge_and_unload()
merged.save_pretrained("llama-my-task")
ГИПЕРПАРАМЕТРЫ: ЧТО РЕАЛЬНО ВЛИЯЕТ
Ранг r и alpha
Ранг — размерность адаптера. Начинайте с r=16. Для простых стилистических задач хватает 8, для сложных доменных знаний имеет смысл 32–64. Выше 64 отдача обычно падает. Про alpha есть железное практическое правило: держите lora_alpha равным 2×r либо задавайте нормировку через rslora — тогда изменение ранга не ломает эффективный learning rate.
target_modules
Ранние гайды вешали LoRA только на q_proj и v_proj. Практика 2026: цепляйте адаптеры на все линейные слои, включая MLP (gate/up/down). Это заметно поднимает качество при копеечном росте параметров.
Learning rate
Для LoRA рабочий диапазон 1e-4 … 3e-4 — на порядок выше, чем при full fine-tuning, потому что обучаемых весов мало и их не жалко двигать резко. Cosine-расписание с коротким warmup — надёжный дефолт.
ДАННЫЕ РЕШАЮТ БОЛЬШЕ, ЧЕМ МЕТОД
Главная ошибка новичков — крутить гиперпараметры на плохом датасете. LoRA не вытянет мусорные данные. Приоритеты именно такие:
- Качество важнее количества. 500–2000 вычищенных, разнообразных примеров часто бьют 50 000 шумных. Дубликаты, противоречивые ответы и кривой формат — прямой путь к деградации.
- Единый chat-шаблон. Промпты в обучении должны точь-в-точь совпадать с тем, как модель будет вызываться в проде. Разошёлся шаблон — потеряли качество на ровном месте.
- Маскирование промпта. Считайте loss только по ответу ассистента, а не по всему тексту. Иначе модель тратит ёмкость на запоминание ваших инструкций вместо генерации ответов.
- Честный holdout. Держите отложенную выборку и смотрите на неё, а не только на train loss.
КОГДА LoRA НЕ НУЖНА
Fine-tuning — не серебряная пуля. Прежде чем тюнить, честно ответьте: не решается ли задача дешевле?
- Нужны свежие факты и знания — берите RAG, а не дообучение. LoRA учит форме и поведению, а не заучиванию фактов, которые устаревают.
- Задача формулируется в промпте — сначала выжмите максимум из few-shot и системного промпта. Часто этого достаточно.
- Данных совсем мало (десятки примеров) — риск переобучения выше пользы.
LoRA выигрывает там, где нужен устойчивый стиль, специфический формат вывода, доменный жаргон, следование строгому протоколу ответов или сжатие большого системного промпта в веса ради экономии токенов и латентности.
Частые вопросы
Чем LoRA отличается от полного дообучения?
При полном fine-tuning обновляются все веса модели, что требует десятков гигабайт памяти и мощного железа. LoRA замораживает базовые веса и обучает маленькие low-rank адаптеры — обычно 0.1–2% параметров. Результат по качеству на узких задачах сопоставим, но памяти и денег нужно в разы меньше.
Сколько данных нужно для LoRA?
Для стилистических и форматных задач хватает 500–2000 качественных примеров. Для сложных доменных навыков — от нескольких тысяч. Чистота и разнообразие данных важнее их объёма: 1000 вычищенных примеров обычно бьют 50 000 шумных.
Что такое QLoRA и когда её использовать?
QLoRA — это LoRA поверх базовой модели, загруженной в 4-битной квантизации. Она снижает потребление VRAM в несколько раз почти без потери качества, позволяя тюнить 7–13B модели на потребительской видеокарте с 16–24 GB памяти. Это разумный дефолт при ограниченном бюджете.
Можно ли слить адаптер обратно в модель?
Да. Метод merge_and_unload() из библиотеки PEFT встраивает выученную поправку BA прямо в веса и отдаёт обычную модель без накладных расходов на инференс. Удобно для продакшена, но тогда теряется возможность быстро переключать адаптеры.
LoRA и PEFT в 2026 — это дефолтный, а не экзотический навык прикладного разработчика. Инструменты вокруг них обновляются буквально каждую неделю: новые квантизаторы, форматы адаптеров, обёртки для serving. Чтобы не пропустить свежие релизы — подписывайтесь на Telegram-канал REDDYX AI — новые репозитории каждые 30-60 минут.