LoRA, QLoRA, Qwen2.5 — почему этот стек, а не другой
Если коротко
- SFT, PEFT, LoRA, QLoRA — это не четыре параллельных метода. Это матрёшка.
- Из шести PEFT-методов выбрана LoRA — и не за хайп, а потому что мерджится в базу.
- 7B на 8 ГБ домашней карты — арифметика, а не магия. И почему Qwen2.5, а не Llama.
Minimalist editorial illustration of a large translucent indigo cube (foundation model) with a small light-violet cube labeled "LoRA" attached to its side via two thin matrix grids labeled "A" and "B". Clean white background with a subtle grid. No harsh shadows, no logos, no text other than "LoRA", "A", "B". 16:9, 1600x900, professional editorial style.
Перед тем как нажать «Start training», я перебрал шесть PEFT-методов, три модели и поспорил сам с собой про SFT и RLHF.
Ниже — выбор и причины. Без хайпа и без «потому что так делают все».
Сначала — что во что вкладывается
В одной вакансии пишут «SFT / LoRA / QLoRA / PEFT», как будто это четыре равноправных метода. Это матрёшка:
SFT — парадигма обучения (supervised, размеченные input→output)
└── PEFT — стратегия: обновляем только небольшой кусок параметров
├── LoRA — низкоранговые матрицы на attention-проекциях
├── QLoRA — LoRA поверх 4-битной квантизированной базы
├── IA³ — мультипликативные векторы (~10× меньше LoRA)
├── Prefix tuning — обучаемые «виртуальные» токены K/V
├── Prompt tuning — обучаемый soft prompt на входе
└── Adapter-слои — bottleneck-MLP между transformer-блоками
SFT — это что мы учим. PEFT — это как распределяем градиенты. LoRA и соседи — конкретные реализации PEFT.
Кто запускает LoRA — по определению занимается PEFT. Если эти слова стоят в одной вакансии, значение простое: «знай, что PEFT — это семья, а не синоним LoRA».
Почему SFT, а не RLHF
RLHF требует пар «лучший / худший» — это совсем другой бюджет на разметку.
Для structured extraction у нас уже есть «правильный JSON», и SFT-loss на нём работает прекрасно. RLHF имеет смысл, когда задача про предпочтения и стиль («какой ответ кажется человеку лучше»). Для «достань три поля из контракта» — это лишняя ступень сложности и три месяца ради нулевого прироста.
Почему LoRA, а не пять других PEFT-методов
| Метод | Почему не взяли |
|---|---|
| LoRA (выбран) | Адаптер — мегабайты. Мерджится в базу при инференсе → 0 мс оверхеда. vLLM умеет --enable-lora. Самая зрелая тула. |
| IA³ | Адаптер ещё меньше, но по статье Liu 2022 хуже на генеративных задачах. |
| Prefix / Prompt tuning | Потолок качества ниже, чувствителен к длине промпта, дебажить — мучение. |
| Adapter-слои | Добавляют латентность на инференсе. LoRA после merge — не добавляет. |
| Full fine-tuning | Полная копия 7B-модели на каждую задачу. ~14× больше VRAM. Зачем. |
Главное преимущество — мерджится в базу. В проде модель ведёт себя как обычный single-checkpoint Qwen, без лишнего forward-прохода через адаптер. Для надёжного inference это критично.
Зачем QLoRA, если есть LoRA
Простая арифметика. Qwen2.5-7B в fp16 — это ~14 ГБ под одни веса. RTX 4060 — 8 ГБ. Не помещается.
QLoRA — это LoRA, но базу загружаем не в fp16, а в 4-битной квантизации nf4 с двойной квантизацией через bitsandbytes. Веса сжимаются до ~4 ГБ. LoRA-дельта остаётся в fp16. Оптимизатор — paged AdamW 8-bit (пейджится между CPU и GPU).
На обучении я видел пик ~7,6 ГБ — впритык, но влезает.
Это и есть основная заявка статьи QLoRA: «можно дообучать 65B-модели на одной 48GB GPU». В моём случае — «7B на 8GB домашней карте». Цифры повторяются.
Почему Qwen2.5, а не Llama 3 или Mistral
Три простых критерия:
- Лицензия Apache-2.0. У Llama 3 — community-лицензия с ограничениями для крупных пользователей. Для развёртывания в регулируемой среде это уже препятствие.
- Мультиязычность из коробки. Qwen2.5 нативно сильна в китайском, русском и английском. Llama 3 — английский в первую очередь. Mistral — европейские получше. Узбекский — ни у кого, и это требует адаптации в любом случае.
- Размерная лесенка. Qwen2.5 идёт линейкой 0.5B / 1.5B / 3B / 7B / 14B / 32B / 72B с одним токенайзером. Один скрипт обучения, разные точки на кривой цена/качество.
Я обучил две модели одним и тем же кодом: 0.5B LoRA — 20 секунд на RTX 4060, 7B QLoRA — 5 минут. Одна команда, разный --base-model.
Гиперпараметры — где не выпендривался
Взял дефолты из оригинальной статьи LoRA (Hu et al., 2021) и не делал sweep:
r=16, alpha=32, dropout=0.05- Target modules:
q_proj, k_proj, v_proj, o_proj(только attention, без MLP) - Learning rate 2e-4, AdamW (или paged-8bit для QLoRA)
- 3 эпохи, batch 1 + grad accumulation 8 → эффективный 8
На 95 примерах sweep — самообман: тюнить нечего. На датасете в 5 000 — да, делайте grid по r ∈ {8, 16, 32}, lr ∈ {1e-4, 2e-4, 5e-4} и числу эпох. И смотрите на eval-loss, а не train-loss.
Одно простое движение, которое часто пропускают
LoRA-адаптер можно смержить в базу перед сохранением:
merged = model.merge_and_unload()
merged.save_pretrained("./qwen-merged")
После этого на инференсе нет дополнительной матричной операции. Модель ведёт себя как обычный single-checkpoint. Это и есть «0 мс оверхеда», ради которого мы выбирали LoRA, а не adapter-слои.
Минус — теряется возможность держать несколько адаптеров на одной базе. В проде у нас лежат оба варианта: смерженный — для быстрого инференса под одну задачу; отдельный адаптер — для vLLM с --enable-lora --max-loras 4, чтобы переключаться между «извлеки поля» / «классифицируй» / «суммаризируй» без перезагрузки.
- Скачайте адаптеры и попробуйте сами: 0,5B LoRA, 7B QLoRA. Карточки — с воспроизводимым рецептом.
- RTX 4060 не под рукой — попробуйте QLoRA на бесплатной T4 в Colab. Команда обучения и параметры идентичные.
- Продуктовая сторона того же решения — «Зачем мы дообучили свою LLM для гос-документов».