Решения
LoRA/QLoRA для LLM: экономия VRAM и практики батчинга
Задача страницы. Дать готовые схемы и сниппеты для дообучения LLM с минимальной памятью и временем простоя: LoRA‑адаптеры, 4‑битная загрузка базовой модели (QLoRA), грамотный батчинг и быстрый вывод в прод.
Когда LoRA, а когда QLoRA
- LoRA — дообучаем только низкоранговые адаптеры, базовые веса заморожены. Резко сокращает число обучаемых параметров и требования к VRAM, почти без падения качества для задач адаптации.
- QLoRA — базовые веса загружаются в 4‑битном представлении (NF4 + double quantization + paged оптимизаторы), а градиенты идут в LoRA‑адаптеры. Позволяет дообучать даже 65B на одной 48 GB GPU (как в оригинальной работе).
Правило большого пальца: если хватает VRAM, начните с классической LoRA (bf16/fp16). Если VRAM мало либо модель велика (≥13B/34B/70B), используйте QLoRA (4‑бит) с NF4 и paged‑оптимизаторами.
Бюджет VRAM и батчинг: ориентиры
- Что ест VRAM: (а) базовые веса (16‑бит для LoRA или 4‑бит для QLoRA), (б) активации, (в) LoRA‑адаптеры, (г) KV‑кэш (зависит от длины контекста), (д) оптимизатор/градиенты (минимальны при LoRA).
- Уменьшаем пик: смешанная точность (bf16/fp16), gradient checkpointing, grad accumulation, компактные токенайзированные примеры, packing коротких примеров в фиксированную длину, отключение use_cache при обучении, FlashAttention для экономии I/O‑обращений в attention.
Практика батчинга:
- Поднимайте micro‑batch до порога OOM → затем увеличивайте grad accumulation, чтобы выйти на целевой effective batch.
- Следите за sequence length: удвоение контекста кратно увеличивает память под активации/кэш.
Для QLoRA выбирайте NF4 и paged‑оптимизаторы (чтобы сглаживать VRAM‑пики).

Мини‑сетап: LoRA (bf16/fp16)

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model
model_id = "mistralai/Mistral-7B-v0.1"
tok = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16, device_map="auto")
model.config.use_cache = False # при обучении
model.gradient_checkpointing_enable()
peft_cfg = LoraConfig(
r=16, lora_alpha=32, lora_dropout=0.05, bias="none",
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
task_type="CAUSAL_LM"
)
model = get_peft_model(model, peft_cfg)
model.print_trainable_parameters()
Пояснения: LoRA добавляет низкоранговые матрицы к выбранным слоям (обычно Q/K/V/О и MLP‑проекции). Обучаемых параметров на порядки меньше, чем при full‑finetune.
Стратегии параллелизма (когда и что включать)
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
model_id = "meta-llama/Llama-2-13b-hf"
bnb_cfg = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # 4-битный NF4
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
tok = AutoTokenizer.from_pretrained(model_id, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(model_id,
quantization_config=bnb_cfg, device_map="auto")
model = prepare_model_for_kbit_training(model) # включает нужные флаги для k‑bit
model.config.use_cache = False
model.gradient_checkpointing_enable()
peft_cfg = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05, bias="none",
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
task_type="CAUSAL_LM")
model = get_peft_model(model, peft_cfg)
Почему NF4: рекомендованный 4‑бит формат в QLoRA/Transformers для весов с нормальным распределением; снижает потребление памяти, сохраняя качество.


Оптимизаторы и обучение
- Для обычной LoRA: AdamW/Lion/AdaFactor (fused‑версии приветствуются).
- Для QLoRA: используйте paged‑оптимизаторы из стека bitsandbytes/Transformers (снимают пики VRAM при градиентных шагах).
Мини‑пример (Trainer/Accelerate опускаем для краткости): по сути, достаточно передать model и tokenized_dataset, выбрать scheduler и включить grad‑клиппинг (0.3–1.0 как отправная точка для стабильности).
Гиперпараметры LoRA: от чего плясать
- r (rank): 8–16 для лёгких задач, 16–32 для сложнее; выше — качественнее, но больше VRAM/время.
- lora_alpha: 16–64; обычно ставят 2×–4× от r.
- lora_dropout: 0–0.1; на малых датасетах 0.05–0.1.
- Модули: для семейств LLaMA/Mistral — как в примерах выше; для других архитектур имя проекций может отличаться (уточняйте в model.named_modules()).
Проверка качества и защита от деградации
- Разделите train/val, считайте perplexity и метрики по целевым задачам; отслеживайте раннюю остановку.
- Не забывайте про катастрофическую забывчивость: если база важна, смешивайте часть исходного корпуса (regularization‑микс).
- Для длинных контекстов включите FlashAttention‑2/3 при доступности в стеке — выигрыш в скорости и утилизации памяти.
Сохранение, мердж и инференс
- Сохранить как адаптер: быстро, экономно по диску, на инференсе грузите базу + адаптер.
- Смержить в базу: model.merge_and_unload() — получаете «плоские» веса без внешнего адаптера (удобно для деплоя без PEFT), затем сохранение.
Для массового деплоя нескольких адаптеров на одну базу храните одну базовую модель и много маленьких чекпоинтов адаптеров.
Типичные проблемы и быстрые решения
- OOM на 4‑бит QLoRA: уменьшите μ (micro‑batch), поднимите grad_accum, включите gradient checkpointing; проверьте, что use_cache=False.
- NaN‑лосс/нестабильность: снизьте LR, включите grad‑клиппинг, переход на bf16 вместо fp16.
- Качество «переучилось»: увеличьте lora_dropout, сократите эпохи/эффективный батч, добавьте регуляризацию (смешивание базового корпуса).
- Медленно считает attention: включите FlashAttention‑2/3 и фиксируйте размерность/пэдинг батчей.
Куда дальше
Предобучение/масштабирование: /solutions/llm-training/pretraining/, /solutions/multi-gpu/, /solutions/llm-training/fsdp-deepspeed/
Точность/память/оптимизация: /solutions/llm-training/mixed-precision/, /solutions/llm-training/memory-opt/, /solutions/performance-tuning/
Данные/I/O/чекпоинты: /solutions/llm-training/datasets/, /solutions/llm-training/distributed-io/, /solutions/llm-training/checkpointing/