Как работает QLoRA (Quantized LoRA) для training?
Краткий тезис
QLoRA (Quantized Low-Rank Adaptation) — это метод эффективного fine-tuning больших языковых моделей, который сочетает 4‑битную квантизацию весов модели с LoRA-адаптерами в половинной точности (FP16). Благодаря этому можно дообучать модели с 70 миллиардами параметров на одной видеокарте с 48 ГБ памяти (например, A6000) с потерей качества всего 1–2% по сравнению с обычным LoRA. QLoRA использует три ключевые техники: NormalFloat4 (NF4) — оптимальный 4‑битный формат, Double Quantization для дополнительной экономии памяти и Paged Optimizers для управления памятью при больших градиентах.
1. Проблема: fine-tuning больших моделей требует огромной памяти
Полный fine-tuning модели с 70B параметров в FP16 требует около 140 ГБ только для весов (70B × 2 байта). Плюс градиенты, состояния оптимизатора (Adam хранит два дополнительных значения на параметр) — итого более 300 ГБ. Это недоступно даже для топовых GPU (A100 80 ГБ). Даже LoRA (Low-Rank Adaptation), который обучает только маленькие адаптеры, требует загрузки всей модели в память, что для 70B в FP16 — 140 ГБ. QLoRA решает эту проблему, загружая модель в 4‑битном формате, что сокращает память для весов в 4 раза.
2. LoRA (Low-Rank Adaptation) — база для QLoRA
LoRA — это метод параметр-эффективного fine-tuning. Вместо обновления всей матрицы весов (W \in \mathbb{R}^{d \times k}) он добавляет две низкоранговые матрицы (B \in \mathbb{R}^{d \times r}) и (A \in \mathbb{R}^{r \times k}) (где (r \ll \min(d,k))). Прямой проход: (h = Wx + BAx). Обучаются только (B) и (A) (обычно в FP16), а исходные веса (W) заморожены. Это резко сокращает число обучаемых параметров и память для градиентов/оптимизатора, но веса модели всё равно должны быть загружены в память.
3. Квантизация (Quantization) — снижение точности весов
Квантизация — это процесс преобразования чисел с плавающей точкой (например, FP16) в целые числа с меньшей разрядностью (например, INT4). В QLoRA используется 4‑битная квантизация, которая уменьшает размер весов в 4 раза по сравнению с FP16. Однако простое округление до 4 бит сильно ухудшает качество. QLoRA вводит специальный формат — NormalFloat4 (NF4).
4. NormalFloat4 (NF4) — оптимальный 4‑битный формат
NF4 — это тип квантизации, который предполагает, что веса модели имеют нормальное распределение. Он использует нелинейное квантование: больше уровней квантования выделяется для значений около нуля (где плотность распределения выше), и меньше — для хвостов. Это минимизирует ошибку квантизации. Формат NF4 даёт почти такую же точность, как 8‑битная квантизация, но занимает вдвое меньше памяти.
5. Double Quantization — двойная квантизация
Даже после квантизации весов в NF4 остаются константы квантизации (scaling factors) для каждого блока (обычно 64 веса). Эти константы хранятся в FP32 и занимают дополнительную память. Double Quantization решает эту проблему: константы квантизации сами квантуются в 8‑битный формат. Это добавляет ещё ~0.5 бита на параметр, но экономит память, занимаемую константами.
6. Paged Optimizers — управление памятью
Во время обучения оптимизатор (Adam) хранит два состояния на каждый обучаемый параметр (моменты первого и второго порядка). Для LoRA-адаптеров это немного, но для больших моделей может возникнуть нехватка памяти при обработке длинных последовательностей. Paged Optimizers используют механизм page swapping: когда GPU-память заканчивается, состояния оптимизатора выгружаются на CPU и подгружаются обратно по мере необходимости. Это позволяет обучать модели с контекстом до 4096 токенов на одной GPU.
7. Архитектура QLoRA: как всё соединяется
Процесс обучения с QLoRA:
- Загрузка модели в 4‑битном формате NF4 с Double Quantization (используется библиотека bitsandbytes).
- Добавление LoRA-адаптеров в FP16 (или BF16) к выбранным слоям (обычно к attention проекциям Q, K, V, O).
- Заморозка всех исходных 4‑битных весов.
- Обучение только LoRA-адаптеров с помощью Paged Optimizer.
- Инференс: можно объединить LoRA-адаптеры с 4‑битной моделью (через дельта-веса) или оставить отдельно.
Важно: градиенты считаются относительно 4‑битных весов, но они не обновляются — обновляются только LoRA-адаптеры. При обратном проходе 4‑битные веса временно деквантуются в FP16 для вычисления градиентов (это происходит на лету).
8. Сравнение памяти: Full Fine-tuning vs LoRA vs QLoRA
| Метод | Размер весов (70B) | Память для градиентов/оптимизатора | Итого (приблизительно) |
|---|---|---|---|
| Full FP16 | 140 ГБ | ~200 ГБ (градиенты + Adam) | >340 ГБ |
| LoRA (модель в FP16) | 140 ГБ | ~2 ГБ (только адаптеры) | ~142 ГБ |
| QLoRA (модель в NF4) | 35 ГБ | ~2 ГБ (адаптеры) | ~37 ГБ |
QLoRA позволяет уместить 70B модель на одной GPU с 48 ГБ (A6000) с запасом.
9. Качество: насколько QLoRA хуже LoRA?
В оригинальной статье QLoRA (Dettmers et al., 2023) показано, что QLoRA с NF4 достигает качества, сопоставимого с LoRA (FP16). Разница составляет 1–2% по метрикам (например, MMLU, GSM8K). При использовании 4‑битной квантизации без NF4 (например, обычный INT4) падение качества может быть 5–10%. Таким образом, NF4 — ключевой компонент для сохранения точности.
10. Практические рекомендации
- Когда использовать QLoRA: когда у вас ограниченная GPU-память (одна карта 24–48 ГБ) и нужно дообучить модель 7B–70B. Для моделей до 7B можно обойтись LoRA, но QLoRA даёт запас.
- Выбор ранга LoRA: r=8–64. Для QLoRA ранг можно брать таким же, как для LoRA.
- Слои для адаптеров: обычно все линейные слои attention (q_proj, k_proj, v_proj, o_proj). Иногда добавляют MLP.
- Библиотеки: Hugging Face Transformers + bitsandbytes + PEFT (Parameter-Efficient Fine-Tuning).
- Ограничения: QLoRA медленнее LoRA из-за деквантизации на каждом шаге (примерно на 20–30%). Также не подходит для обучения с нуля — только для fine-tuning.
11. Пет-проект для закрепления
Задача: Дообучить модель LLaMA-2 7B на датасете инструкций (например, Alpaca) с помощью QLoRA на одной GPU с 8 ГБ (например, RTX 3070).
Инструменты: Python, PyTorch, Transformers, bitsandbytes, PEFT, Datasets.
Шаги:
- Установить библиотеки:
pip install transformers bitsandbytes peft datasets accelerate. - Загрузить модель и токенизатор с квантизацией NF4:
from transformers import AutoModelForCausalLM, BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", quantization_config=bnb_config) - Добавить LoRA-адаптеры через PEFT:
from peft import LoraConfig, get_peft_model lora_config = LoraConfig(r=8, lora_alpha=32, target_modules=["q_proj","v_proj"], lora_dropout=0.05) model = get_peft_model(model, lora_config) - Загрузить датасет Alpaca, подготовить промпты.
- Обучить с помощью Trainer или собственного цикла (используя Paged AdamW).
- Сохранить адаптеры:
model.save_pretrained("llama2-qlora-alpaca"). - Протестировать генерацию: загрузить базовую 4‑битную модель, затем загрузить адаптеры.
Ожидаемый результат: Модель научится отвечать на инструкции, при этом пиковое использование GPU-памяти не превысит 6–7 ГБ.
12. Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 481 | Как работает LoRA? |
| 480 | Что такое fine-tuning и PEFT? |
| 483 | Какие методы квантизации моделей вы знаете? |
| 484 | Как работает 4‑битная квантизация (GPTQ, AWQ)? |
| 485 | Как объединить LoRA-адаптеры с квантизованной моделью? |
Навигация
- Предыдущий: 481
- Следующий: 483
- Индекс: 00. Индекс разборов