Перейти к содержимому
ПереводыDeepSeek

Техотчёт DeepSeek-V2 (2024): MLA и экономика инференса

Конспект техотчёта DeepSeek-V2: как низкоранговое сжатие KV-кэша (MLA) и отделённый RoPE уменьшили кэш в 15 раз, зачем нужны маршрутизация с ограничением по устройствам и три лосса баланса, и откуда взялись 42,5% экономии обучения и ×5,76 пропускной способности.

  • DeepSeek-V2 — MoE на 236 млрд параметров, из них 21 млрд активны на токен; контекст 128 тыс. токенов; 8,1 трлн токенов претрейна.
  • Главная новинка — многоголовое латентное вниманиемногоголовое латентное внимание (MLA)EN multi-head latent attention (MLA)Предложено DeepSeek в DeepSeek-V2 (2024). (Multi-head Latent Attention): ключи и значения всех голов сжимаются в один латентный вектор размера 512, и в KV-кэше хранится только он (плюс 64 измерения для позиций).
  • Чтобы сжатие ужилось с ротационные позиционные эмбеддингиротационные позиционные эмбеддинги (RoPE)EN rotary position embedding (RoPE)RoPE предложен в Китае (Су Цзяньлинь и соавторы, компания Zhuiyi). Сейчас используется почти во всех LLM., позиции вынесли в отдельные измерения (отделённый RoPE): обычная часть ключа сжата и «впитывается» в матрицы запросов, позиционная считается отдельно.
  • Вторая половина архитектуры — DeepSeekMoE: 2 общих эксперта и 160 маршрутизируемых, активны 6; добавлены маршрутизация с ограничением по устройствам и три вспомогательных лосса баланса.
  • Эффект: против плотной DeepSeek 67B — экономия обучения 42,5% (172,8 тыс. GPU-часов на триллион токенов против 300,6 тыс.), KV-кэш меньше на 93,3%, максимальная пропускная способность генерации выше в 5,76 раза (больше 50 тыс. токенов в секунду на узле из 8 H800).
  • Выравнивание: SFT на 1,5 млн примеров, затем двухэтапный RL на GRPO — сначала рассуждения (код и математика), потом человеческие предпочтения с тремя моделями наград. Честно описан «налог на выравнивание».
Раздел отчётаО чёмКуда в курсе
§2.1.1напоминание про обычное многоголовое внимание4.4, 5.2.1
§2.1.2–2.1.4низкоранговое сжатие KV, отделённый RoPE, таблица размеров кэша5.2.2 «MLA»
§2.2DeepSeekMoE в V2, маршрутизация по устройствам, три лосса, отбрасывание токенов5.3.2
§3.1данные (8,1 трлн), гиперпараметры, инфраструктура, расширение до 128K через YaRN5.1.2, 5.5.1
§3.2.3стоимость обучения и пропускная способность инференса7.1.1
§4SFT, двухэтапный RL на GRPO, обсуждение6.4.1

При генерации модель хранит ключи и значения всех прошлых токенов — KV-кэшKV-кэшEN KV cache. Его размер прямо определяет, сколько запросов влезет в память GPU одновременно, то есть себестоимость сервиса. Для обычного многоголового внимания на токен нужно 2nhdhl2 n_h d_h l чисел (nhn_h голов, dhd_h на голову, ll слоёв).

Для V2 (nh=128n_h = 128, dh=128d_h = 128, l=60l = 60) это 2⋅128⋅128⋅60=1,972 \cdot 128 \cdot 128 \cdot 60 = 1{,}97 млн чисел на токен. При bf16 — почти 4 МБ на один токен контекста. На 128 тыс. токенов — сотни гигабайт. Так сервис не построишь.

внимание с группами запросоввнимание с группами запросов (GQA)EN grouped-query attention (GQA)Головы запросов делятся на G групп, у каждой группы своя пара K/V. G = H — это MHA, G = 1 — MQA. Стандарт Llama 3 и Qwen (Ainslie и др., 2023). уменьшает это в nh/ngn_h / n_g раз (несколько голов делят один набор ключей), MQA — в nhn_h раз, но за качество приходится платить. MLA решает задачу иначе.

Вместо того чтобы хранить ключи и значения, храним один сжатый вектор, из которого они восстанавливаются:

ctKV=WDKVht,ktC=WUKctKV,vtC=WUVctKV,c^{KV}_t = W^{DKV} h_t, \qquad k^{C}_t = W^{UK} c^{KV}_t, \qquad v^{C}_t = W^{UV} c^{KV}_t,

где ctKV∈Rdcc^{KV}_t \in \mathbb{R}^{d_c}, а dc≪dhnhd_c \ll d_h n_h. «DKV» — проекция вниз (down), «UK», «UV» — проекции вверх (up) для ключей и значений. В кэше лежит только ctKVc^{KV}_t: dc ld_c\, l чисел на токен.

Ключевой трюк не в самом сжатии, а в поглощении матриц (matrix absorption). Запишем оценку внимания: qTkC=(WUQcQ)T(WUKcKV)=(cQ)T((WUQ)TWUK)cKVq^{T} k^{C} = (W^{UQ}c^{Q})^{T}(W^{UK}c^{KV}) = (c^{Q})^{T}\big((W^{UQ})^{T}W^{UK}\big)c^{KV}. Произведение (WUQ)TWUK(W^{UQ})^{T}W^{UK} не зависит от токена, его можно посчитать один раз. То есть WUKW^{UK} «впитывается» в матрицу запросов, а WUVW^{UV} — в выходную матрицу WOW^{O}, и восстанавливать ключи и значения на инференсе вообще не нужно.

Запросы тоже сжимают (ctQ=WDQhtc^{Q}_t = W^{DQ}h_t, размерность dc′d'_c), хотя на KV-кэш это не влияет: это экономит память под активации во время обучения.

Проблема: ротационные позиционные эмбеддингиротационные позиционные эмбеддинги (RoPE)EN rotary position embedding (RoPE)RoPE предложен в Китае (Су Цзяньлинь и соавторы, компания Zhuiyi). Сейчас используется почти во всех LLM. поворачивает запросы и ключи на угол, зависящий от позиции. Если применить RoPE к сжатым ключам ktCk^{C}_t, то между WQW^{Q} и WUKW^{UK} оказывается матрица поворота, зависящая от позиции текущего токена. Матрицы не коммутируют — поглощение ломается, и ключи всех прошлых токенов приходится пересчитывать на каждом шаге. Вся экономия пропадает.

Решение: разделить обязанности. Добавляются отдельные «позиционные» части размером dhRd^{R}_h на голову:

qtR=RoPE(WQRctQ),ktR=RoPE(WKRht),q^{R}_t = \mathrm{RoPE}(W^{QR} c^{Q}_t), \qquad k^{R}_t = \mathrm{RoPE}(W^{KR} h_t), qt,i=[ qt,iC; qt,iR ],kt,i=[ kt,iC; ktR ].q_{t,i} = [\,q^{C}_{t,i};\, q^{R}_{t,i}\,], \qquad k_{t,i} = [\,k^{C}_{t,i};\, k^{R}_t\,].

Запрос и ключ — это склейка двух частей: «содержательной» (сжатой, без позиции) и «позиционной» (с RoPE). Внимание нормируется на dh+dhR\sqrt{d_h + d^{R}_h}. Позиционный ключ ktRk^{R}_t один на все головы (как в MQA), поэтому в кэш добавляется всего dhRd^{R}_h чисел.

Итого кэш MLA: (dc+dhR) l(d_c + d^{R}_h)\, l чисел на токен.

flowchart LR
H["h_t (скрытое состояние)"] --> D1["W_DKV: сжатие"] --> C["c_KV (512)"]
H --> D2["W_KR + RoPE"] --> KR["k_R (64), общий для всех голов"]
C -. "хранится в кэше" .-> KV[("KV-кэш: 512 + 64 = 576 чисел на токен на слой")]
KR -. "хранится в кэше" .-> KV
C --> U1["W_UK, W_UV: поглощаются в W_Q и W_O на инференсе"]
Что реально попадает в KV-кэш у MLA (схема по §2.1 отчёта)

Конфигурация V2: dc=512d_c = 512 (это 4dh4 d_h), dhR=64d^{R}_h = 64 (это dh/2d_h/2), l=60l = 60. На токен: (512+64)⋅60=34 560(512 + 64)\cdot 60 = 34\,560 чисел.

МеханизмЧисел на токенДля V2Качество (оценка авторов)
MHA2nhdhl2 n_h d_h l1 966 080сильное
GQA (ngn_g групп)2ngdhl2 n_g d_h lзависит от ngn_gсреднее
MQA2dhl2 d_h l15 360слабое
MLA(dc+dhR) l(d_c + d^{R}_h)\, l34 560сильнее, чем MHA

34 560 ÷ (2 · 128 · 60) = 2,25: кэш MLA равен кэшу GQA всего с 2,25 группами — и при этом, по замерам авторов, качество выше, чем у полного MHA.

MoE в V2: три лосса и ограничение по устройствам

Заголовок раздела «MoE в V2: три лосса и ограничение по устройствам»

Архитектура экспертов — та же, что в DeepSeekMoE, но крупнее: все слои, кроме первого, содержат 2 общих эксперта и 160 маршрутизируемых с промежуточной размерностью 1536; на токен включаются 6 маршрутизируемых.

Маршрутизация с ограничением по устройствам. При мелких экспертах активных экспертов много, и токен может «разъехаться» по всем узлам кластера — связь станет дороже вычислений. Поэтому сначала выбирают MM устройств с самыми подходящими экспертами, и только внутри них берут top-K. На практике при M≥3M \ge 3 качество почти не отличается от неограниченного выбора; в V2 стоит M=3M = 3 при D=8D = 8 устройствах.

Три вспомогательных лосса баланса:

  1. На уровне экспертов (α1=0,003\alpha_1 = 0{,}003) — против коллапса маршрутизации.
  2. На уровне устройств (α2=0,05\alpha_2 = 0{,}05) — чтобы вычисления были равномерны по GPU.
  3. На уровне связи (α3=0,02\alpha_3 = 0{,}02) — новый по сравнению со статьёй DeepSeekMoE. Ограничение по устройствам гарантирует, что каждое устройство отправляет ограниченный объём, но ничто не мешает одному устройству получать намного больше токенов, чем другие. Этот лосс выравнивает приём.

Плюс отбрасывание токенов (token dropping) во время обучения для ускорения: устройство с переполненной очередью выбрасывает токены с наименьшими оценками сродства. На оценке качества токены не отбрасывают.

Обучение: данные, гиперпараметры, инфраструктура

Заголовок раздела «Обучение: данные, гиперпараметры, инфраструктура»
  • Данные. 8,1 трлн токенов, тот же токенизатор BBPE со словарём 100K, что и у DeepSeek 67B. Китайских токенов примерно на 12% больше, чем английских. Улучшены фильтры качества, восстановлена часть ошибочно удалённых данных, отфильтрован спорный контент.
  • Модель. 60 слоёв, dmodel=5120d_\text{model} = 5120, 128 голов по 128. Дополнительные слои RMSNorm после сжатых латентных векторов и масштабирующие множители в «узких местах» — иначе обучение нестабильно.
  • Обучение. AdamW, максимальный learning rate 2,4e-4, ступеньки ×0,316 после ~60% и ~90% токенов. Батч растёт с 2304 до 9216 последовательностей за первые 225 млрд токенов, длина 4K.
  • Параллелизм. 16-путевой конвейер (zero-bubble), 8-путевой параллелизм экспертов, ZeRO-1 по данным. Тензорного параллелизма нет — активных параметров мало, часть операторов перевычисляется, и без TP меньше связи. Вычисление общих экспертов накладывается на all-to-all маршрутизируемых. MLA оптимизирована на основе улучшенной версии FlashAttention-2. Кластер — узлы по 8 H800 с NVLink и NVSwitch внутри узла, InfiniBand между.
  • Длинный контекст. После основного претрейна контекст расширяют с 4K до 128K через YaRNYaRNEN YaRN (Yet another RoPE extensioN)NTK-by-parts (каждая пара частот масштабируется по числу оборотов за обучающую длину) плюс температура внимания 0.1·ln s + 1. Используется в DeepSeek-V3 и Qwen., применяя его только к отделённому ключу ktRk^{R}_t — ведь только он несёт позиции. Параметры: s=40s = 40, α=1\alpha = 1, β=32\beta = 32, целевая длина 160K; коэффициент длины подправлен как t=0,0707ln⁡s+1\sqrt{t} = 0{,}0707 \ln s + 1 для минимизации перплексии. Дообучение — 1000 шагов при длине 32K, батч 576, а работает модель и на 128K (проверено тестом «иголка в стоге сена»).

Обучение. На триллион токенов: DeepSeek 67B — 300,6 тыс. GPU-часов, DeepSeek-V2 — 172,8 тыс. Экономия 1−172,8/300,6=42,5%1 - 172{,}8/300{,}6 = 42{,}5\%, при том что V2 сильнее по качеству.

Инференс. Веса переводят в FP8, KV-кэш квантуют примерно до 6 бит на элемент. На одном узле из 8 H800 получается больше 50 тыс. токенов генерации в секунду (в 5,76 раза больше, чем у 67B) и больше 100 тыс. токенов в секунду на обработку промптов. Распределение длин промптов и ответов брали из реального сервиса 67B.

SFT. 1,5 млн примеров (1,2 млн «полезность», 0,3 млн «безопасность»), 2 эпохи, learning rate 5e-6. По сравнению с версией для DeepSeek 67B данные почищены: меньше галлюцинаций, лучше письмо.

RL на GRPO. Алгоритм взят из DeepSeekMath ради экономии: нет критика размером с политику, базовая линия — среднее по группе. Обучение разбито на два этапа, потому что на рассуждениях модель продолжает расти дольше, чем на предпочтениях:

  1. Выравнивание рассуждений. Отдельная модель наград для кода и математики. Предпочтения для кода получают из ответов компилятора, для математики — сверкой с правильным ответом.
  2. Выравнивание под предпочтения человека. Награда — взвешенная сумма трёх: ri=c1Rhelpful(oi)+c2Rsafety(oi)+c3Rrule(oi)r_i = c_1 R_\text{helpful}(o_i) + c_2 R_\text{safety}(o_i) + c_3 R_\text{rule}(o_i) — полезность, безопасность и правила.

Инженерия RL (её редко описывают, а она решает): гибридный движок с разными стратегиями параллелизма для обучения и для генерации, vLLM с большими батчами как бэкенд генерации, продуманное расписание выгрузки моделей на CPU и загрузки обратно.

  • Сколько нужно SFT-данных. Есть популярное мнение, что хватает менее 10 тыс. примеров (LIMA и подобные работы). В экспериментах DeepSeek на бенчмарке следования инструкциям IFEval при менее чем 10 тыс. примеров качество заметно падает. Чем больше модель, тем меньше данных нужно, но до нуля это не доходит.
  • Налог на выравнивание. После выравнивания под предпочтения открытая генерация становится лучше (и по оценке людей, и по оценке ИИ-судьи), но часть стандартных бенчмарков (например, BBH) проседает. Авторы долго подбирали данные и стратегии, чтобы компромисс был терпимым.
  • Онлайн против офлайна. Онлайновый RL (учимся на свежих ответах текущей модели) заметно лучше офлайнового — тот же вывод, что и в DeepSeekMath.
  1. Пересчитайте KV-кэш. Для MHA, GQA с 8 группами, MQA и MLA при параметрах V2 посчитайте числа на токен и размер кэша на 128 тыс. токенов в bf16 и в 6 битах. Убедитесь, что получается 93,3%.
  2. Проверьте поглощение матриц. На NumPy возьмите случайные WUQW^{UQ}, WUKW^{UK} и убедитесь, что (WUQcQ)T(WUKcKV)(W^{UQ}c^{Q})^{T}(W^{UK}c^{KV}) совпадает с (cQ)T((WUQ)TWUK)cKV(c^{Q})^{T}\big((W^{UQ})^{T}W^{UK}\big)c^{KV} с точностью до ошибок округления. Это ядро практики урока 5.2.2.
  3. Сломайте RoPE. Примените RoPE к сжатым ключам и покажите, что поглощение больше не работает: матрица поворота зависит от разности позиций и не выносится за скобки.
  4. Прикиньте свой сервис. Сколько одновременных запросов по 8 тыс. токенов поместится в 32 ГБ вашей RTX 4080, если кэш как у MHA, как у GQA-8 и как у MLA (считайте на модель с 32 слоями и 32 головами по 128)?
ENRU
Multi-head Latent Attention (MLA)многоголовое латентное внимание
low-rank joint compressionнизкоранговое совместное сжатие
latent vectorлатентный (сжатый) вектор
down-/up-projectionпроекция вниз / вверх
matrix absorptionпоглощение матриц
decoupled RoPEотделённый RoPE
device-limited routingмаршрутизация с ограничением по устройствам
communication balance lossлосс баланса связи
token-dropping strategyотбрасывание токенов
zero-bubble pipeline parallelismконвейер «без пузыря»
needle in a haystack (NIAH)«иголка в стоге сена» (тест длинного контекста)
alignment taxналог на выравнивание
generation throughputпропускная способность генерации