41 LoRA
Контекст
Дообучать большую модель целиком дорого по памяти/хранению — своя копия всех весов под каждую задачу. Ху и др. делают fine-tune дешёвым.
Идея и механизм
Замораживаем веса W и для адаптации добавляем низкоранговое обновление ΔW = BA, где A, B — маленькие матрицы ранга r ≪ d. Учим только A, B. Обоснование: полезное обновление весов под задачу имеет низкий «внутренний ранг».
линейная алгебра Низкоранговое обновление и экономия параметров
Полный fine-tune обновляет всю матрицу W ∈ ℝd×k (dk параметров). LoRA замораживает W и параметризует обновление произведением двух «тонких» матриц:
Число обучаемых параметров r(d+k) вместо dk. Например d=k=4096, r=8:
Нулевая латентность на инференсе. В отличие от adapter-слоёв, BA можно влить в веса: W′ = W + BA — и модель работает с обычной матрицей, без лишних операций. Плюс много маленьких LoRA-адаптеров живут на одной базе, переключаясь под задачи.
PyTorch LoRA-слой
import torch, torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, W, r=8, alpha=16):
super().__init__()
self.W = W # заморожен
d, k = W.shape
self.A = nn.Parameter(torch.randn(r, k) * 0.01)
self.B = nn.Parameter(torch.zeros(d, r)) # старт с нуля → ΔW=0
self.s = alpha / r
def forward(self, x):
return x @ self.W.T + (x @ self.A.T) @ self.B.T * self.s
Почему это важно
Дефолтный метод parameter-efficient fine-tuning (PEFT); демократизировал дообучение больших моделей — реально на одной GPU. Тысячи специализированных LoRA-адаптеров на одной базовой LLM — стандарт современной кастомизации.
Связи
Именно гиганты вроде GPT-3 сделали полный fine-tune непрактичным — отсюда и LoRA. На 175B-модели LoRA сокращает обучаемые параметры в ~10000× и память в разы, не теряя в качестве.
Два способа удешевить большие модели: дистилляция сжимает модель в маленькую, LoRA адаптирует большую дёшево, не трогая её веса. Часто комбинируют: дистиллированную базу дообучают LoRA под конкретные задачи.
Открытые веса LLaMA + LoRA = взрыв кастомных моделей: сообщество дообучает базовую LLaMA под тысячи задач лёгкими адаптерами на потребительском железе. LoRA — ключевая причина, почему open-экосистема смогла так быстро итерировать.
Вопросы пытливого ума
Почему обновление весов под задачу вообще должно иметь низкий ранг?
Эмпирическая гипотеза статьи: адаптация под конкретную задачу «живёт» в маленьком подпространстве — большая предобученная модель уже умеет почти всё, дообучение лишь слегка её разворачивает. Авторы показали, что даже ранг 1–2 часто работает. Строгой теории нет, но низкоранговость обновлений подтверждается на практике на многих задачах.
Почему B инициализируют нулём, а A — случайно?
Чтобы в начале обучения ΔW = BA = 0 и модель стартовала ровно с предобученного поведения, не «дёргаясь». A случайна (иначе градиент по B был бы нулевым — симметрия), B нулевая (чтобы старт был чистым). Так дообучение начинается с известной хорошей точки и плавно отходит от неё.
Раз BA вливается в веса без латентности — в чём подвох?
Подвох в гибкости на инференсе. Если вы влили адаптер, модель стала специализированной — чтобы держать много задач одновременно (мульти-LoRA в одном сервисе), адаптеры приходится применять динамически, и тогда лёгкая накладка появляется. «Ноль латентности» верно для одного зафиксированного адаптера; мультиплекс — отдельная инженерная задача.
Что читать в оригинале
Читать ключевое — низкоранговая идея и почему нет латентности; эксперименты по выбору ранга r полезны для интуиции.