Эпоха 5 · Эра LLM · 2021

41 LoRA

LoRA: Low-Rank Adaptation of Large Language Models · Hu, Shen, Wallis, Allen-Zhu и др. · Microsoft · ICLR 2022
🟧 оригинал выборочно~1 чоригинал ↗
Суть за 20 секунд. Замораживаем веса и вставляем обучаемое НИЗКОРАНГОВОЕ обновление в каждый слой: ~10000× меньше обучаемых параметров без прироста латентности инференса. Дешёвый модульный fine-tune, демократизировавший дообучение больших моделей.

Контекст

Дообучать большую модель целиком дорого по памяти/хранению — своя копия всех весов под каждую задачу. Ху и др. делают fine-tune дешёвым.

Идея и механизм

Замораживаем веса W и для адаптации добавляем низкоранговое обновление ΔW = BA, где A, B — маленькие матрицы ранга r ≪ d. Учим только A, B. Обоснование: полезное обновление весов под задачу имеет низкий «внутренний ранг».

линейная алгебра Низкоранговое обновление и экономия параметров

Полный fine-tune обновляет всю матрицу W ∈ ℝd×k (dk параметров). LoRA замораживает W и параметризует обновление произведением двух «тонких» матриц:

h = Wx + αr BAx,   B ∈ ℝd×r, A ∈ ℝr×k

Число обучаемых параметров r(d+k) вместо dk. Например d=k=4096, r=8:

8·8192 ≈ 65k  vs  4096² ≈ 16.7M  (в ~256× меньше)

Нулевая латентность на инференсе. В отличие от 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
x W (заморож.) A B + h учим только маленькие A, B (ранг r)
Большая матрица W заморожена; обучается лишь дешёвая низкоранговая добавка BA. На деплое её вливают в W — никакой лишней латентности.
Аналогия. Не переписывать всю энциклопедию ради новой темы, а вложить в неё тонкую вкладку с поправками. Энциклопедия (W) остаётся как есть; под каждую задачу — своя лёгкая вкладка (A, B). Нужно переключить тему — меняешь вкладку, а не печатаешь том заново. И при «чтении» вкладку можно вклеить намертво — листать не дольше.

Почему это важно

Дефолтный метод parameter-efficient fine-tuning (PEFT); демократизировал дообучение больших моделей — реально на одной GPU. Тысячи специализированных LoRA-адаптеров на одной базовой LLM — стандарт современной кастомизации.

Связи

← применяется к38. GPT-3

Именно гиганты вроде GPT-3 сделали полный fine-tune непрактичным — отсюда и LoRA. На 175B-модели LoRA сокращает обучаемые параметры в ~10000× и память в разы, не теряя в качестве.

↔ перекликается28. Knowledge Distillation

Два способа удешевить большие модели: дистилляция сжимает модель в маленькую, LoRA адаптирует большую дёшево, не трогая её веса. Часто комбинируют: дистиллированную базу дообучают LoRA под конкретные задачи.

→ инструмент для50. LLaMA

Открытые веса LLaMA + LoRA = взрыв кастомных моделей: сообщество дообучает базовую LLaMA под тысячи задач лёгкими адаптерами на потребительском железе. LoRA — ключевая причина, почему open-экосистема смогла так быстро итерировать.

Вопросы пытливого ума

Почему обновление весов под задачу вообще должно иметь низкий ранг?

Эмпирическая гипотеза статьи: адаптация под конкретную задачу «живёт» в маленьком подпространстве — большая предобученная модель уже умеет почти всё, дообучение лишь слегка её разворачивает. Авторы показали, что даже ранг 1–2 часто работает. Строгой теории нет, но низкоранговость обновлений подтверждается на практике на многих задачах.

Почему B инициализируют нулём, а A — случайно?

Чтобы в начале обучения ΔW = BA = 0 и модель стартовала ровно с предобученного поведения, не «дёргаясь». A случайна (иначе градиент по B был бы нулевым — симметрия), B нулевая (чтобы старт был чистым). Так дообучение начинается с известной хорошей точки и плавно отходит от неё.

Раз BA вливается в веса без латентности — в чём подвох?

Подвох в гибкости на инференсе. Если вы влили адаптер, модель стала специализированной — чтобы держать много задач одновременно (мульти-LoRA в одном сервисе), адаптеры приходится применять динамически, и тогда лёгкая накладка появляется. «Ноль латентности» верно для одного зафиксированного адаптера; мультиплекс — отдельная инженерная задача.

Что читать в оригинале

Читать ключевое — низкоранговая идея и почему нет латентности; эксперименты по выбору ранга r полезны для интуиции.