LoRA и QLoRA простыми словами: дообучение 7B-модели без 100 ГБ видеопамяти
Почему полное дообучение требует 80–100 ГБ, как низкоранговые адаптеры сокращают обучаемые веса до 1,6%, как выбрать ранг и целевые слои и что добавляет QLoRA.
LoRA становится понятной, только когда видно, где она находится между предобучением и дообучением, так что начнём с этого.
Предобучение и дообучение
Предобучение происходит, когда модель создают впервые. Она сама учится на последовательностях текста, без всякой разметки: обучающий текст сам даёт и входы, и цели, а в результате получается универсальная базовая модель.
Знаний у такой базовой модели много, но определённому формату, шаблону или инструкции она не следует. Довольно часто она просто продолжает то, что вы набрали, и дописывает в конец ещё слов. Это исправляет дообучение. Вы обучаете модель на размеченных примерах из инструкции, входных данных и желаемого ответа, и она узнаёт, как выглядят хорошие ответы.
Допустим, вам нужна модель для юридических запросов. Обучать с нуля незачем, если уже есть предобученная модель с большим запасом знаний о предметной области. Вы дообучаете её, чтобы она отвечала по делу.
Почему полное дообучение так тяжело
Обновление всех параметров съедает память. Возьмём 7B-модель Llama с такой конфигурацией:
Model size: 7 billion parameters
Training dtype: BF16 / FP16
Optimizer: AdamW
Sequence length: 2048
Одна только загрузка базовой модели занимает 14 ГБ. При полном дообучении обучается каждый параметр, значит, каждому нужен градиент, и если хранить градиенты в BF16 или FP16, это ещё 14 ГБ. Оптимизатор AdamW просит сверху примерно 56 ГБ и может держать копию параметров в FP32, а это ещё около 28 ГБ. Часть уходит и на активации. В сумме выходит 80–100 ГБ — слишком много для узкой прикладной задачи, которая к тому же не так уж сложна.
Что делает LoRA
LoRA расшифровывается как Low-Rank Adaptation, низкоранговая адаптация. Она дообучает модель, не обновляя каждый вес по отдельности. Все исходные веса заморожены, а учится пара небольших матриц.
Как маленькие матрицы могут управлять большой моделью? Подумайте, что предобученная модель уже знает: английский, грамматику, шаблоны рассуждений, программирование, факты. Если теперь нужно, чтобы она отвечала на юридические вопросы в определённом стиле, заново учить язык ей не надо. Достаточно направить то, что уже есть. LoRA делает ставку на то, что такое изменение обычно укладывается в структуру меньшей размерности:
ΔW = AB
Миллиарды выученных моделью весов остаются нетронутыми. LoRA не трогает W и добавляет поправку поверх:
W_new = W + ΔW
Разбираем на числах
Представьте трансформер с одним линейным слоем:
X -> W -> Output
Пусть W имеет размер 1000 на 1000. Тогда в ней:
1000 x 1000 = 1,000,000 parameters
Полное дообучение обучает все эти параметры, а в настоящих LLM такие матрицы повсюду, поэтому у 7B-модели обучать нужно около 7 млрд параметров.
С LoRA вы создаёте две узкие матрицы, A и B, и выбираете ранг, например r = 8:
A = [1000 x 8]
b = [8 x 1000]
Их произведение имеет ту же форму, что и W, поэтому сумма корректна:
W_new = W + AB
[1000×1000] + [1000×1000]
Экономия возникает из того, как мало параметров в двух узких матрицах:
A: 1000 × 8 = 8,000
B: 8 × 1000 = 8,000
Total = 16,000 parameters
Сравним два подхода:
Full fine-tuning:
1,000,000 parameters
LoRA:
16,000 parameters
Для этого слоя обучаемых параметров всего 1,6% от исходного числа.
Что значит ранг
Ранг — один из главных гиперпараметров LoRA, и он задаёт ёмкость адаптера. Низкий ранг, например 4 или 8, даёт адаптер поменьше: он расходует меньше памяти, но менее гибок. Сложным задачам может понадобиться 32, 64 или 128. Более высокий ранг стоит больше памяти и не означает автоматически лучшее качество, ведь он может добавлять шум. Попробуйте несколько рангов и оставьте тот, что работает лучше.
Куда ставить адаптеры
LoRA прикрепляет небольшие обучаемые матрицы к замороженному трансформеру, но матриц в трансформере много. В упрощённом блоке decoder-only их несколько, а модель может повторять этот блок 32, 40, 80 и более раз. Вопрос LoRA в том, каким из этих матриц W нужна обучаемая поправка BA. Три распространённые стратегии:
Стратегия 1: только q_proj и v_proj. Адаптер на q_proj может менять то, как представления формируют запросы к релевантному контексту, а адаптер на v_proj меняет информацию, которую передают токены, на которые направлено внимание.
Стратегия 2: все проекции внимания. Добавьте адаптеры на q_proj, k_proj, v_proj и o_proj, и LoRA сможет менять все основные обучаемые линейные преобразования во внимании. Гибкости больше, но и обучаемых параметров тоже.
Стратегия 3: проекции внимания плюс слои MLP. Это более крупная и сильная универсальная конфигурация:
ATTENTION
q_proj ✅
k_proj ✅
v_proj ✅
o_proj ✅
MLP
gate_proj ✅
up_proj ✅
down_proj ✅
Трансформер — это не только внимание. MLP выполняет огромную часть обучаемых преобразований признаков, так что, охватив и его, вы заметно расширяете свободу дообучения.
Решила ли LoRA проблему с памятью?
Нет, не полностью. Она сокращает число обучаемых параметров примерно на 99%, но видеопамять на 99% не уменьшается: базовую модель всё равно нужно загрузить, прямой проход всё равно выполняется, да ещё с небольшими дополнительными вычислениями. Настоящий выигрыш — в градиентах и состояниях оптимизатора. Хранить градиенты для 7 млрд параметров больше не нужно.
QLoRA
QLoRA, квантованная низкоранговая адаптация, развивает идею ещё на шаг. Раз базовые веса всё равно заморожены, их можно квантовать до 4 бит. 7B-модель, которой в BF16 нужно 14 ГБ, сжимается примерно до 3,5–5 ГБ. Поэтому 7B-модель можно дообучить через QLoRA на одной игровой видеокарте, тогда как обычное полное дообучение потребовало бы нескольких GPU с большим объёмом памяти.