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

Техотчёт DeepSeekMoE (2024): мелкие эксперты и общий эксперт

Конспект статьи DeepSeekMoE: почему привычный top-2 MoE мешает экспертам специализироваться, как помогают дробление экспертов и выделенный общий эксперт, что показали абляции и до каких масштабов идею довели — 2B, 16B и 145B.

  • В обычном MoE (GShard, Switch) эксперт — это целый FFN, и на токен включаются 1–2 эксперта из 8–64. Такой эксперт вынужденно учит «всего понемногу»: специализации не получается.
  • DeepSeekMoE предлагает две идеи. Дробление экспертов (fine-grained expert segmentation): каждый эксперт режется на mm более узких, а включается в mm раз больше экспертов — вычисления те же, а комбинаций в сотни миллионов раз больше. Выделение общего эксперта (shared expert isolation): KsK_s экспертов включаются всегда, они берут на себя общие знания, и остальные перестают их дублировать.
  • Результат на 2B параметров: DeepSeekMoE почти догоняет плотную модель с тем же числом всех параметров (это потолок для MoE) и равен GShard, у которого в 1,5 раза больше параметров и вычислений в экспертах.
  • На 16B (2,8B активных, 2 трлн токенов) модель сравнима с LLaMA 2 7B примерно при 40% вычислений. Предварительный прогон на 145B показал уровень плотной DeepSeek 67B при 28,5% вычислений.
  • Абляции доказывают, что обе идеи работают по отдельности, а общий эксперт незаменим: если его выключить и добавить взамен ещё один маршрутизируемый, loss на Pile прыгает с 1,808 до 2,414.
  • Балансировка — два вспомогательных лосса: на уровне экспертов (против коллапса маршрутизации) и на уровне устройств (против простоя GPU). В V3 от них откажутся в пользу балансировки смещениями, но это уже другая статья.
Раздел отчётаО чёмКуда в курсе
§2 Preliminariesкак устроен обычный MoE-слой: роутер, softmax, top-K5.3.1 «Основы MoE»
§3.1–3.2две главные идеи и их формулы5.3.2 «DeepSeekMoE»
§3.3 Load Balanceвспомогательные лоссы на уровне экспертов и устройств5.3.1 и 5.4.3
§4.2–4.5сравнения и абляции — самая поучительная частьметодика экспериментов, 5.1.1
§5–7масштабирование до 16B и 145B, выравнивание чат-версииchina/06 «Читаем техотчёт V3»

Новичку: читайте §3 и §4.5 (анализ специализации). Таблицы бенчмарков можно пролистать.

Задача: почему эксперт не специализируется

Заголовок раздела «Задача: почему эксперт не специализируется»

Напомним устройство MoE-слоя. Вместо одного FFN стоят NN экспертов-FFN. Для токена с вектором utu_t роутер считает совместимость с каждым экспертом, берёт softmax и включает KK экспертов с наибольшими значениями; их выходы складываются с весами gi,tg_{i,t}.

Беда в том, что при N=16N = 16 и K=2K = 2 эксперт получает очень разнородный поток токенов: и код, и стихи, и формулы. Значит, внутри одного эксперта лежат знания обо всём сразу, и использовать их по отдельности нельзя. Плюс несколько экспертов неизбежно учат одно и то же общее знание (как устроен язык, пунктуация, частые слова) — параметры тратятся на дубликаты.

Режем каждый эксперт на mm частей: промежуточная размерность FFN уменьшается в mm раз. Чтобы вычисления не изменились, включаем в mm раз больше экспертов. Было: NN экспертов, включаем KK. Стало: mNmN экспертов, включаем mKmK.

Параметров столько же, вычислений столько же — что изменилось? Число комбинаций. При N=16N = 16, K=2K = 2 их (162)=120\binom{16}{2} = 120. Разрежем каждого на 4 (m=4m = 4): mN=64mN = 64, mK=8mK = 8, комбинаций (648)=4 426 165 368\binom{64}{8} = 4\,426\,165\,368 — около 4,4 миллиарда. Роутер получает несравнимо более точный «набор инструментов» для каждого токена, и каждому эксперту достаётся более узкий поток, то есть более узкая специализация.

flowchart LR
subgraph A["Обычный MoE: 16 экспертов, top-2"]
  T1["токен"] --> R1["роутер"] --> E1["эксперт 3"] & E2["эксперт 11"]
end
subgraph B["Дробление m = 4: 64 эксперта, top-8"]
  T2["токен"] --> R2["роутер"] --> F1["3"] & F2["11"] & F3["17"] & F4["26"] & F5["31"] & F6["40"] & F7["52"] & F8["63"]
end
Те же вычисления, но в 4,4 млрд раз больше возможных сочетаний (схема по §3.1 отчёта)

KsK_s экспертов объявляются общими: они обрабатывают каждый токен без всякого роутера. Чтобы вычисления не выросли, число включаемых маршрутизируемых экспертов уменьшают на KsK_s. Выход слоя становится суммой «общие эксперты + выбранные маршрутизируемые + остаточная связь»:

ht=∑i=1KsFFNi(ut)  +  ∑i=Ks+1mNgi,t FFNi(ut)  +  ut,h_t = \sum_{i=1}^{K_s}\mathrm{FFN}_i(u_t) \;+\; \sum_{i=K_s+1}^{mN} g_{i,t}\,\mathrm{FFN}_i(u_t) \;+\; u_t,

где gi,tg_{i,t} отлично от нуля только для mK−KsmK - K_s маршрутизируемых экспертов с наибольшими значениями softmax от произведения utTeiu_t^{T} e_i (eie_i — вектор-«центроид» эксперта ii).

Смысл: общее знание концентрируется в общем эксперте, и маршрутизируемым не нужно его повторять. Авторы честно отмечают, что идею общего эксперта до них описали в работе про DeepSpeed-MoE (Rajbhandari et al., 2022), но там она была инженерным приёмом, а здесь — архитектурным решением с проверкой.

Итого в DeepSeekMoE: KsK_s общих экспертов, mN−KsmN - K_s маршрутизируемых, активны mK−KsmK - K_s из них.

Без принуждения роутер склонен к коллапсу маршрутизации (routing collapse): он всегда выбирает несколько любимых экспертов, остальные не учатся. Второй вред от перекоса — вычислительный: если эксперты лежат на разных GPU, перегруженная GPU задерживает всех.

  • Лосс на уровне экспертов LExpBal=α1∑ifiPi\mathcal{L}_\text{ExpBal} = \alpha_1 \sum_i f_i P_i, где fif_i — доля токенов, попавших к эксперту ii (нормированная так, что при идеальном балансе равна 1), а PiP_i — средняя вероятность, которую роутер даёт этому эксперту. Произведение «сколько досталось × насколько уверенно выбирали» минимально, когда нагрузка ровная.
  • Лосс на уровне устройств LDevBal=α2∑ifi′Pi′\mathcal{L}_\text{DevBal} = \alpha_2 \sum_{i} f'_i P'_i: то же самое, но эксперты сгруппированы по DD устройствам. Выравнивать строго на уровне экспертов вредно для качества, а вот между устройствами выравнивать нужно.

Практика авторов: маленький коэффициент на уровне экспертов (только чтобы не было коллапса) и больший на уровне устройств. Конкретно: 0,01 в проверочных экспериментах на 2B, 0,001 для 16B (вся модель на одном устройстве конвейера — балансировать по устройствам не нужно), 0,003 плюс 0,05 для 145B, где включили параллелизм экспертов.

Чтобы сравнение было честным, все модели учили на одном корпусе (100 млрд токенов), с одинаковыми гиперпараметрами, одинаковым числом всех и активных параметров.

Конфигурация: 9 слоёв, dmodel=1280d_\text{model} = 1280, 10 голов внимания по 128. Все FFN заменены MoE-слоями; суммарные параметры экспертов равны 16 FFN, активные — 2 FFN. Выходит около 2,0 млрд всех параметров и ~0,3 млрд активных. У DeepSeekMoE здесь 1 общий эксперт и 63 маршрутизируемых размером по 0,25 обычного FFN, активны 7 из 63.

Кого сравнивали: плотную модель 0,2B; Hash Layer (top-1 по хешу); Switch Transformer (top-1 обучаемый); GShard (top-2); DeepSeekMoE. Вывод: при равных вычислениях DeepSeekMoE лучше всех, причём разрыв с GShard заметный.

Два ориентира-потолка:

  • GShard×1.5 — тот же GShard, но эксперты в 1,5 раза больше (и параметров, и вычислений в экспертах в 1,5 раза больше). DeepSeekMoE примерно равен ему. На большем масштабе (13,3B против 19,8B) DeepSeekMoE уже уверенно впереди.
  • Dense×16 — плотная модель, у которой параметров столько же, сколько у MoE всего (1,89 млрд в «экспертной» части, и все они активны). Это естественный потолок для MoE: при равных параметрах плотная модель использует их все. DeepSeekMoE подходит к этому потолку вплотную — при вычислениях в разы меньше (по таблице отчёта: 5,8 триллиона FLOPs на 2 тыс. токенов против 24,6 триллиона).

Все модели в абляциях имеют одинаковое число всех и активных параметров.

  1. Только общий эксперт. Берём GShard и выделяем из него одного эксперта как общего — качество растёт на большинстве бенчмарков.
  2. Только дробление. Режем экспертов на 2 (32 эксперта) и на 4 (64 эксперта) — качество растёт монотонно с ростом дробности.
  3. Сколько общих экспертов? При 64 экспертах всего пробовали 1, 2 и 4 общих: loss на Pile 1,808 / 1,806 / 1,811 — разница в пределах шума. Выбрали соотношение «общих к активным маршрутизируемым = 1 : 3» и дальше его держали.
  • Меньше дублирования. Если у каждого токена отключить верхние по вероятности маршрутизируемые эксперты (замаскировать их и взять top-K из оставшихся), DeepSeekMoE портится сильнее, чем GShard×1.5 при равном исходном loss. Звучит как недостаток, но смысл обратный: у GShard эксперты взаимозаменяемы, то есть избыточны, а у DeepSeekMoE каждый эксперт делает свою работу, и заменить его некем.
  • Общий эксперт незаменим. Выключаем общего эксперта, добавляем взамен ещё одного маршрутизируемого (вычисления те же) — loss на Pile растёт с 1,808 до 2,414. Это огромный скачок: общий эксперт хранит базовое знание, которое маршрутизируемые не воспроизводят.
  • Нужно меньше активных экспертов. Меняя число активных маршрутизируемых с 7 до 3, авторы видят, что уже при 4 активных DeepSeekMoE даёт loss на уровне GShard с полным набором. А модель, обученная с нуля с 1 общим и 3 активными из 63 (то есть вдвое меньше активных параметров в экспертах), всё равно обгоняет GShard.

DeepSeekMoE 16B. 28 слоёв, dmodel=2048d_\text{model} = 2048, 16 голов по 128, словарь 100K, 2 трлн токенов. MoE стоит во всех слоях, кроме первого (в первом слое баланс сходится особенно медленно). В каждом MoE-слое 2 общих и 64 маршрутизируемых эксперта по 0,25 FFN; токен идёт к 2 общим и 6 из 64. Всего ~16,4 млрд параметров, активных ~2,8 млрд. Батч 4,5 тыс. последовательностей по 4 тыс. токенов = 18 млн токенов на шаг, 106 449 шагов, максимальный learning rate 4,2e-4, расписание со ступеньками ×0,316 на 80% и 90% шагов (как в отчёте DeepSeek LLM). Dropout не используется — данных и так много.

Итог: сравнимо с LLaMA 2 7B примерно при 40% вычислений. Для сравнения на бенчмарках авторы берут бит на байтбит на байт (BPB)EN bits per byte (BPB)Loss, пересчитанный на байт исходного текста; в отличие от perplexity, его можно сравнивать между моделями с разными токенизаторами. вместо перплексии, потому что токенизаторы разные.

DeepSeekMoE 145B (предварительно). 62 слоя, dmodel=4096d_\text{model} = 4096, 32 головы; 4 общих и 128 маршрутизируемых экспертов по 0,125 FFN, активны 4 общих и 12 из 128. Всего ~144,6 млрд параметров, активных ~22,2 млрд. Обучено на 245 млрд токенов (предварительный прогон), расписание LR — разогрев и константа. Эксперты каждого слоя разложены на 4 устройства (параллелизм экспертов вместе с параллелизмом по данным), поэтому включён лосс балансировки устройств с коэффициентом 0,05.

Результат предварительного прогона: уровень плотной DeepSeek 67B при 28,5% вычислений (а по осторожной оценке авторов — возможно, и при 18,2%).

  1. Посчитайте комбинации. Проверьте в Python: math.comb(16, 2) и math.comb(64, 8). Прикиньте, сколько комбинаций даёт конфигурация V3 (math.comb(256, 8)).
  2. Соберите игрушечный MoE-слой. По формуле из раздела «Идея 2» реализуйте слой с Ks=1K_s = 1, mN=8mN = 8, активных 2 из 7 на NumPy или PyTorch (CPU). Проверьте, что выход при равных весах роутера совпадает со средним по включённым экспертам плюс общий эксперт плюс вход.
  3. Проверьте баланс. Прогоните через роутер случайные векторы и посчитайте fif_i и PiP_i; добавьте вспомогательный лосс с α1=0,01\alpha_1 = 0{,}01 и посмотрите, как меняется распределение нагрузки за несколько шагов.
  4. Абляция «выключим общего эксперта». На игрушечной модели из урока 5.3.1 обучите два варианта — с общим экспертом и без (с лишним маршрутизируемым) — и сравните loss. Направление эффекта должно совпасть со статьёй.
ENRU
Mixture-of-Experts (MoE)смесь экспертов
expert specializationспециализация экспертов
fine-grained expert segmentationмелкозернистое дробление экспертов
shared expert isolationвыделение общего эксперта
routed expertмаршрутизируемый эксперт
routing collapseколлапс маршрутизации
expert-level / device-level balance lossвспомогательный лосс баланса на уровне экспертов / устройств
combinatorial flexibilityгибкость сочетаний (число комбинаций)
parameter redundancyизбыточность параметров (дублирование)
bits per byte (BPB)битов на байт
upper bound of MoEпотолок для MoE (плотная модель с тем же числом параметров)