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/llm-training/pretraining/), [/solutions/multi-gpu/](/solutions/multi-gpu/), [/solutions/llm-training/fsdp-deepspeed/](/solutions/llm-training/fsdp-deepspeed/)
**Точность/память/оптимизация:**[ /solutions/llm-training/mixed-precision/](/solutions/llm-training/mixed-precision/), [/solutions/llm-training/memory-opt/](/solutions/llm-training/memory-opt/), [/solutions/performance-tuning/](/solutions/performance-tuning/)
**Данные/I/O/чекпоинты:**[ /solutions/llm-training/datasets/](/solutions/llm-training/datasets/), [/solutions/llm-training/distributed-io/](/solutions/llm-training/distributed-io/), [/solutions/llm-training/checkpointing/](/solutions/llm-training/checkpointing/)
[**Оценка**](/solutions/llm-training/eval/)
Готовы запустить?
Запустить GPU-сервер