December 4, 2024

Да кто такая эта ваша LoRA, или как эффективно дообучать LLM? 

Абстракт Обучать модельки долго и дорого. Чтобы обучить модельку на нашу задачу, не нужно обучать ее с нуля – можно просто скорректировать нужные параметры. Этим и занимается LoRA – Low-Rank Adaptation

Начнем
Итак, давайте спустимся на самый простой уровень. У нас есть один линейный слой без функции активации.

Если на вход мы подадим x, на выходе получим y = Wx, где W — матрица весов.
Мы хотим немного изменить принцип работы этого слоя, дообучив модель и скорректировав веса на dW (которые обычно ищут градиентным спуском), так, чтобы новый выход был:

y' = W'x = (W + dW)x = y + dWx

Как мы видим, новый y отличается от старого на dWx, что можно интерпретировать, как результат работы еще одного, отдельного, полносвязного слоя.

Таким образом, мы можем зафиксировать веса матрицы W и вместо этого учить dW — модель предсказывающую отличие результата обычной модели от дообученой. Это отдаленно напоминает градиентный бустинг, где мы учим каждое следующее решающее дерево исправлять ошибки прошлого.

А где выигрыш? Ведь размеры матриц W и dW должны быть одинаковыми, в них же должно быть одинаковое количество обучаемых параметров …
Вот тут и включается в игру слова Low-Rank: матрицу маленького ранга можно представить как произведение двух матриц меньшей размерности.

Наша матрица может быть размером 100 на 70, но ранг, то есть количество линейно независимых строк или столбцов (если совсем нестрого — таких столбцов, которые действительно содержат новую информацию о модели, а не действуют на вектор параметров аналогично соседям) может быть меньше, чем 70, например 4 или 20.

Так вот, мы можем представить матрицу dW как произведение двух матриц A и B, при это сильно выиграем в количестве обучаемых параметров, но немного потеряем в общности, так как теперь мы автоматический постулируем, что у dW низкий ранг.

Однако в этом нет ничего страшного, разработчики LoRA утверждают, что «внутренняя размерность» (intrinsic rank) больших текстовых моделей очень низкая, и большинство параметров, проще говоря, «не работают».

Таким образом, во время обучения нам необходимо хранить в памяти веса W исходной модели и dW=B*A дообучаемой, а считать градиенты только для «новых» маленьких матриц А и В.

Плюсы этого подхода:

1. Значительно менее ресурсозатратное дообучение. Теперь модель уровня LLaMA / GPT-3* / .... можно дообучить под свои задачи на обычной видеокарточке

2. Снижение числа обучаемых параметров понижают требования к датасету

3. LoRA модели занимают значительно меньше места на диске. Мы можем хранить одну «базовую» модель, которая действительно весит много, и большое количество LoRA-модулей (например, стилей для Stable Diffusion или дообучений под разные языки для Copilot), которые почти ничего не весят. Из-за этого такие модели проще хранить и распространять. Для GPT-3, с 350 ГБ, матрицы А и В для всех линейных слоев суммарно занимали 35 Мб!

4. Отсутствие задержки вывода. Перед использованием мы можем рассчитать
W' = W + B*A, таким образом новая модель будет требовать столько же вычислений, как и модель без файнтюна

5. Можно менять матрицы А и В прямо налету, посреди диалога, спрашивая у пользователя, например, в каком стиле ему ответить