Менша затримка та вища пропускна здатність завдяки багатопотоковому розгортанню DeepSeek

Розгортання на кількох GPU підвищує продуктивність MoE-моделі за швидкістю та масштабом

АвториPerplexity Research

У більшості систем затримка та пропускна здатність часто є суперечливими цілями, які вимагають компромісів під час проєктування та розгортання. Наприклад, у щільних великих мовних моделях збільшення розміру батча може покращити пропускну здатність, але також збільшує затримку; збільшення тензорного паралелізму в межах однієї машини може зменшити затримку, але зменшує кількість реплік, що призводить до нижчої пропускної здатності.

Моделі суміші експертів (MoE), такі як DeepSeek-V3/R1, нещодавно продемонстрували чудові можливості моделей та операційну ефективність. Наприклад, модель DeepSeek-V3/R1 має загалом 671 млрд параметрів, але під час інференсу кожен токен використовує лише 37 млрд параметрів. Така архітектура моделі створює як проблеми, так і можливості для систем інференсу.

Ця стаття демонструє, що, на відміну від звичайних систем, такі моделі MoE, як DeepSeek-V3/R1, у більшості сценаріїв можуть одночасно досягати вищої пропускної здатності та меншої затримки за умови використання більшої кількості графічних процесорів у багатопотокових (multi-node) розгортаннях.

Архітектури розгортання

Одновузлове розгортання через NVLink, де увага та експертні обчислення розподілені між GPU.
Багатовузлове розгортання через InfiniBand, де групи GPU з’єднані всередині вузлів і між ними.

Через велику кількість невеликих експертів у моделі розгортання мають бути розподілені між кількома пристроями. Ми розглянули як однопотокові (single-node) розгортання на одному вузлі з 8 графічними процесорами H200, так і багатопотокові (multi-node) розгортання на 8 графічних процесорах H100.

Обидві архітектури розгортання використовують паралелізм даних, оркестрований через наш власний планувальник запитів. Реалізація паралелізму даних передбачає запуск кількох екземплярів рушія інференсу, кожен з яких працює незалежно для обслуговування та підтримки запитів. Планувальник запитів, який взаємодіє з рушієм через GRPC, відповідає за рівномірний розподіл запитів і водночас сприяє повторному використанню кешу KV (KV re-use), надсилаючи запити з частково збіжними префіксами на сервери, що містять кеш. Екземпляри рушія не охоплюють кілька вузлів. Вони можуть опціонально використовувати тензорний паралелізм для шардування уваги (attention) між кількома пристроями. Екземпляри з'єднані між собою через NVLink в однопотоковому випадку або InfiniBand у багатопотоковому випадку, здійснюючи диспетчеризацію та збір експертів.

Однопотокова конфігурація розгортання забезпечує чудову затримку при невеликих розмірах батчів; однак продуктивність стрімко падає за умов підвищеного навантаження.

Щоб розгорнути рушій обслуговування, ми запускаємо один під (pod) на вузел, що містить кілька екземплярів рушія. PyTorch відповідає за налаштування розподіленого зв'язку та узгодження ініціалізації NVSHMEM. Для зв'язку ми покладаємося на спеціальні ядра CUDA, описані в попередній публікації в блозі. Реалізація обох розгортань практично ідентична, причому модель вибирає правильні ядра для використання на основі фабрики, що реалізує паралелізм експертів.

Методи розпаралелювання

Перш ніж занурюватися в порівняння продуктивності, важливо зрозуміти ключові стратегії розпаралелювання, які роблять можливим розгортання масивних моделей MoE, таких як DeepSeek-V3/R1.

Тензорний паралелізм

Під час інференсу LLM тензорний паралелізм (TP) зазвичай використовується для зменшення використання пам'яті та обчислень на один графічний процесор, тим самим зменшуючи затримку. Зазвичай ми можемо шардувати лінійні проєкції (Linear Projections) у шарах уваги (Attention) та MLP вздовж вимірів рядків або стовпців, а також шардувати операції уваги вздовж виміру голівки уваги (attention head).

З TP архітектура Llama-3 не має дубльованих обчислень для лінійних проєкцій та операцій уваги на різних графічних процесорах, що є ідеальним методом шардування. Однак у моделях DeepSeek-V3/R1 TP не може цього досягти.

Моделі DeepSeek-V3/R1 використовують багатолатентну увагу (Multi-Latent Attention, MLA). Шар MLA спочатку використовує лінійну проєкцію kv_a_proj для обчислення латентного вектора, а потім використовує іншу лінійну проєкцію kv_b_proj, щоб перетворити його у простір кожної голівки уваги. Оскільки всі голівки уваги спільно використовують той самий латентний вектор, TP не може шардувати латентний вектор, тому всі ранги TP повинні реплікувати параметри та обчислення kv_a_proj та kv_b_proj. Подібним чином, оскільки MLA зберігає латентний вектор у кеші KV, кожен ранг TP зберігає ідентичну копію кешу KV.

Попри певне дублювання в MLA, тензорний паралелізм все ж забезпечує часткове зменшення обчислювальних вимог, що робить його цінним для сценаріїв, які вимагають високої швидкості виведення.

Паралелізм експертів

Моделі DeepSeek-V3/R1 замінюють шари MLP на шари MoE. Шар MoE має 256 маршрутизованих експертів і одного спільного експерта. Кожен токен спрямовується до 8 різних маршрутизованих експертів для обчислень, а результати підсумовуються з урахуванням ваги. Кожен токен також обчислюється у спільному експерті, і результат додається до результату від маршрутизованих експертів.

Паралелізм експертів (EP) слугує типовим підходом до шардування для шарів MoE, де кожен графічний процесор керує 256 / EP маршрутизованими експертами, зберігаючи при цьому копію спільного експерта. У порівнянні з TP, перевагою EP є те, що він може розподіляти обчислення між більшою кількістю графічних процесорів, зменшуючи обчислення та використання пам'яті на один графічний процесор.

Перед проведенням експертних обчислень усі графічні процесори повинні виконати комунікацію AllToAll для розподілу токенів на графічні процесори, де розташовані відповідні експерти; після експертних обчислень потрібна ще одна комунікація AllToAll для збору результатів обчислень з різних графічних процесорів та виконання зваженого сумування. Ми реалізували оптимізовану версію цих двох ядер зв'язку AllToAll, Dispatch та Combine, використовуючи NVSHMEM. У нашій попередній публікації в блозі ми детально описали реалізацію, і наші ядра були відкритими (open-sourced) на GitHub.

Паралелізм даних

За допомогою EP ми можемо розподілити обчислення MoE між 128 або навіть більшою кількістю графічних процесорів. Однак обчислення MLA не можуть бути розділені за допомогою EP. У цей момент ми можемо запровадити паралелізм даних (DP). Кожна група DP має повну копію шару MLA. Кожна група DP приймає різні вхідні дані та виконує обчислення шару MLA незалежно.

DP та TP шару MLA можна комбінувати, причому одна група DP розбивається на кілька рангів TP. EP шару MoE можна комбінувати з DP/TP шару MLA. EP = DP * TP. Наприклад, на 16 машинах EP128 DP32 TP4 означає розподіл маршрутизованих експертів по 128 графічних процесорах, де кожні 4 графічні процесори утворюють групу DP, загалом утворюючи 32 незалежні групи DP.

Однопотокове та багатопотокове розгортання

671 мільярд параметрів DeepSeek перевищують місткість пам'яті однієї машини H100 з 8 графічними процесорами (80 ГБ * 8), але одна машина H200 з 8 графічними процесорами може повністю вмістити всю модель (141 ГБ * 8). Використовуючи конфігурацію EP8 DP8 TP1, модель використовує близько 100 ГБ пам'яті на один графічний процесор, залишаючи приблизно 40 ГБ для кешу KV та інших проміжних результатів. Один токен займає 70 272 байти кешу KV. Якщо припустити, що кожен запит має 5000 токенів, кожен графічний процесор може вмістити приблизно 100 запитів.

Ми хотіли зрозуміти різницю в продуктивності між однопотоковим та багатопотоковим розгортанням за різних конфігурацій. Ми використовували одну машину H200 для однопотокового розгортання та до 16 машин H100 для багатопотокового розгортання. Для кожного середовища розгортання ми використовували комбінації TP 1, 2, 4, 8 та розміри батчів на графічний процесор 1, 2, 4, 8, 16, 32, 64, 128. Ми припустили, що кожен запит має довжину кешу KV 5000 токенів. Ми також припустили, що багатокеневе прогнозування (Multi-Token Prediction, MTP) прогнозує 1 додатковий токен (тобто довжина запиту кожного запиту дорівнює 2), і консервативно припустили рівень прийняття 60%. На графіку нижче показано пропускну здатність та швидкість виведення для різних конфігурацій.

Фронтири Парето для затримки та пропускної здатності для різних конфігурацій паралелізму експертів.

Горизонтальна вісь представляє швидкість виведення на один запит у токенах за секунду (токени/с). Вертикальна вісь використовує логарифмічну шкалу для відображення пропускної здатності на одну машину в токенах/с. Ми позначили межу Парето для кожної конфігурації EP лініями різного кольору.

У сценаріях із надзвичайно високими вимогами до швидкості виведення використання однопотокового EP8 DP1 TP8 з розміром батча 1 може досягати швидкості виведення, що перевищує 100 токенів/с, але пропускна здатність є надзвичайно низькою, що еквівалентно швидкості виведення. У цьому сценарії весь батч має лише 2 токени, які можуть бути спрямовані максимум на 2*8=16 експертів, активуючи загалом максимум 57 млрд параметрів.

У діапазоні швидкості виведення 80–40 токенів/с зі збільшенням пропускної здатності швидкість виведення суттєво зменшується. Натомість EP128 має приблизно в 5 разів вищу пропускну здатність, ніж однопотокове розгортання при тій самій швидкості виведення.

Цей феномен можна пояснити, дослідивши поведінку однопотокового розгортання: збільшення розміру батча безпосередньо корелює зі збільшенням кількості активованих експертів. Коли розмір батча дорівнює 1, середня кількість активованих експертів на один графічний процесор становить 2 * 8 / 8 = 2. Коли батч достатньо великий, активуються всі експерти, а це означає, що кожен графічний процесор активує 256 / 8 = 32 експерти. Активація більшої кількості експертів означає, що графічному процесору потрібно зчитати більше параметрів з пам'яті, що суттєво збільшує навантаження на пропускну здатність пам'яті. Оскільки фаза дешифрування (decode phase) великих мовних моделей вже ускладнена пропускною здатністю пам'яті, а не продуктивністю обчислень, збільшення розміру батча в однопотоковому розгортанні суттєво знижує швидкість виведення.

Порівняння чотирьох конфігурацій багатопотокового розгортання (EP16, EP32, EP64 та EP128) показує, що вищі значення EP зміщують межу Парето в бік одночасного покращення пропускної здатності та швидкості виведення.

Використання вищого номера EP означає, що кожному графічному процесору призначено менше експертів. Наприклад, EP128 означає, що кожен графічний процесор відповідає за 256 / 128 = 2 експерти, тому навантаження на пропускну здатність пам'яті суттєво знижується. Іншими словами, використовуючи більший номер EP, ми ефективно отримуємо більшу пропускну здатність пам'яті. Коли розмір батча на один графічний процесор менший за 64, збільшення розміру батча суттєво не впливає на швидкість експертних обчислень, оскільки збільшення кількості вхідних даних суттєво не збільшує навантаження на пропускну здатність пам'яті. Тому ми спостерігаємо, що при використанні EP128 збільшення розміру батча не так суттєво впливає на швидкість виведення.

Цікаво, що на більших розмірах батчів (64 запити на один графічний процесор) ми спостерігали новий феномен: пропускна здатність однопотокового розгортання дещо вища, ніж багатопотокового. Частково це пояснюється тим, що внутрішньовузловий NVLink має вищу пропускну здатність, ніж міжвузловий InfiniBand. Інша частина пов'язана з обмеженнями в нашій реалізації. Ми проаналізуємо цей феномен детальніше пізніше.

Через обмеження місткості пам'яті конфігурація EP8 DP8 TP1 не може досягти розміру батча 128 на один графічний процесор, тому багатопотокове розгортання все ще є кращим вибором у сценаріях, що передбачають вищу пропускну здатність.

Суміщення обчислень та зв'язку

Як коротко зазначено вище щодо паралелізму експертів, графічні процесори простаюють під час комунікації шару MoE. Щоб зменшити витрати та знизити затримку, нам потрібно знайти завдання для обчислень, незалежні від даних, щоб заповнити цей час простою.

Плани обчислень і передавання даних без перекриття, з перекриттям диспетчеризації та п’ятиетапним конвеєром.

У верхній частині наведеного вище рисунка показано потік обчислень одного шару. Обчислення MoE залежать від Dispatch, а обчислення наступного шару залежать від результату Combine.

Ми розміщуємо спільного експерта на кожному графічному процесорі. Таким чином, обчислення спільного експерта не потребують комунікації AllToAll. Тому ми можемо виконувати обчислення спільного експерта одразу після Dispatch Send, а потім чекати на завершення Dispatch Recv. Ми називаємо цю схему суміщення "Dispatch Overlap".

Dispatch Overlap пропонує просту реалізацію та широку застосовність. Ця техніка приховує час обчислень спільного експерта для всіх розмірів EP та розмірів батчів.

Щоб ще більше збільшити суміщення обчислень і зв'язку, ми використовували мікробатчінг (micro batching), згаданий у технічному звіті DeepSeek, для розриву залежності даних. Як показано в нижній частині рисунка, ми розділили обчислення одного шару Transformer на 5 етапів:

Етап 1: InputNorm, QKVProj, AppendKV, BMM

Етап 2: BMM, Attn, OProj, PostNorm, Gate

Етап 3: Dispatch Send, Shared Expert

Етап 4: Dispatch Recv, MoE, Combine Send

Етап 5: Combine Recv

У перших 3 щільних шарах Transformer ми використовуємо весь батч. У наступних 58 шарах Transformer MoE ми рівномірно ділимо батч на два мікробатчі. Два мікробатчі виконуються по черзі зі зміщенням у 3 етапи. Оскільки між цими двома мікробатчами немає залежності від даних, ми можемо перемкнутися на обчислення іншого мікробатча після Dispatch Send та після Combine Send.

Розподіл затримки

Далі ми порівнюємо ефекти суміщення за допомогою експерименту, а також порівнюємо різницю в продуктивності між однопотоковим розгортанням EP8 та багатопотоковим розгортанням EP128. Для зручності порівняння для наступного експерименту ми використовували графічні процесори H100. Ми використовували TP1, розмір батча 128 на графічний процесор, довжину запиту 2 на запит та довжину кешу KV 5000.

Затримка шару за ядром для порівнюваних конфігурацій паралелізму експертів і перекриття.

Наведений вище рисунок показує загальний час, витрачений на один шар Transformer MoE, та частку затримки різних типів ядер. За винятком Dispatch, Combine та GroupGEMM, час виконання інших ядер має бути однаковим у серіях EP8, EP128 NoOverlap та EP128 DispatchOverlap, оскільки розмір батча однаковий.

Суміщення

Порівняймо спочатку ефекти трьох методів суміщення. NoOverlap зайняв загалом 2667 мкс, DispatchOverlap зайняв 2651 мкс, заощадивши 16 мкс, або лише 0,6%. MicroBatch показав дуже суттєве покращення, зайнявши 1896 мкс, тобто прискорення на 29%. Час як Dispatch, так і Combine було суттєво зменшено. Dispatch зменшився з 593 мкс до 367 мкс, а Combine — з 1012 мкс до 237 мкс.

Зауважте, що для обчислювальних ядер поділ батча розміром 128 на два батчі розміром 64 збільшує загальний час виконання. Тому, хоча час, витрачений на зв'язок, зменшився на 1001 мкс, загальний час зменшився лише на 771 мкс. Ми пояснимо цю причину за допомогою моделі Roofline у наступному розділі.

З цієї причини мікробатчінг не завжди покращує продуктивність.

Зміни швидкості виведення та пропускної здатності на вузол із мікропакетуванням, нанесені залежно від розміру пакета на GPU.

Наведений вище рисунок показує покращення продуктивності Microbatch порівняно з DispatchOverlap для розмірів батчів 4–128. Коли розмір батча менший за 32, Microbatch знижує продуктивність на 5%–40%. Коли розмір батча більший або дорівнює 32, Microbatch може покращити продуктивність на 10%–35%.

EP8 проти EP128

Повернімося до попереднього рисунка та порівняймо EP8 та EP128 Microbatch. EP8 зайняв загалом 1802 мкс, що дещо менше, ніж 1896 мкс у EP128. Окрім згаданого вище збільшення часу виконання ядер, спричиненого Microbatch, основні відмінності полягають у GroupGEMM, який використовується для обчислень MoE, та у двох ядрах зв'язку — Dispatch та Combine.

GroupGEMM для EP8 зайняв 555 мкс, тоді як GroupGEMM для EP128 зайняв 270 мкс, зменшившись удвічі. Це головна перевага багатопотокового розгортання.

На жаль, час, витрачений на зв'язок, зріс на 213 мкс, що значною мірою нівелювало перевагу GroupGEMM. В окремих тестах продуктивності наших ядер зв'язку ми виявили, що вони можуть досягати лише половини пропускної здатності Infiniband. Ми продовжуватимемо оптимізувати наші ядра зв'язку.

Іншим ядром, яке суттєво відстає, є GEMM. Microbatch збільшив GEMM на 95 мкс. Ми детальніше проаналізуємо GEMM у розділі Roofline нижче. Ми вважаємо, що поточна реалізація GEMM ще не досягла оптимальної продуктивності.

Roofline

Модель Roofline є хорошим інструментом для аналізу продуктивності ядер. Її горизонтальною віссю є арифметична інтенсивність (Arithmetic Intensity), співвідношення FLOP до байтів введення-виведення пам'яті. Значення горизонтальної осі можна розрахувати безпосередньо з семантики ядра. Вертикальна вісь представляє досягнуту продуктивність, яка обчислюється шляхом поділу FLOP на затримку еталонного тесту (benchmark latency).

Теоретична верхня межа продуктивності ядра безпосередньо визначається специфікаціями графічного процесора. Пікова продуктивність FP8 для H100 становить 1979 ТФЛОП/с (TFLOP/s), представлена як горизонтальна лінія в моделі Roofline. Пропускна здатність пам'яті H100 становить 3,35 ТБ/с, представлена як нахил лінії, що проходить через початок координат. Ці дві лінії дають обмеження продуктивності відповідно для ядер, обмежених обчисленнями (compute-bound), та обмежених пам'яттю (memory-bound).

Нижче ми обговорюємо продуктивність ядер GroupGEMM та GEMM.

GroupGEMM

Ядро GroupGEMM у MoE виконує такі обчислення: всього є g груп, i-та група має m_i токенів, виконуючи множення матриць [m_i, k] x [k, n] -> [m_i, n]. У тестуванні продуктивності ми припускаємо, що кількість токенів у кожній групі однакова, позначена як m_i = m. Тоді кількість FLOP для GroupGEMM дорівнює 2 * g * m * k * n, а байти введення-виведення пам'яті дорівнюють g * (m * k + n * k + m * n).

У моделі DeepSeek-V3/R1 є 256 експертів, і кожен токен спрямовується до 8 експертів для обчислень. Припускаючи розмір батча 128, довжину запиту 2, використовуючи конфігурацію EP128 DP128, середня кількість токенів, отриманих кожним експертом (тобто m), становить 128 * 2 * 8 * 128 / 256 = 1024. Подібним чином ми можемо розрахувати m для інших конфігурацій та розмірів батчів.

Ми використовували реалізацію GroupGEMM від DeepGEMM для тестування продуктивності. Тестові точки охоплювали комбінації конфігурацій EP8, EP16, EP32, EP64, EP128 з TP1 та розмірами батчів 1–128.

Продуктивність GroupGEMM відносно меж обчислень і пропускної здатності пам’яті.

Наведений вище рисунок показує модель Roofline для GroupGEMM за різних конфігурацій EP. Різні EP відповідають різній кількості груп. На рисунку показано практично збіжні лінії продуктивності, що вказує на те, що продуктивність GroupGEMM переважно визначається загальною кількістю токенів (представленою як g * m).

Зірочками позначено точки даних, що відповідають розміру батча 128 на графічний процесор для кожної конфігурації EP. Порівнюючи ці позначені зірочками точки даних, ми бачимо, що зі збільшенням EP (і синхронним збільшенням DP) кількість токенів на одного експерта m також збільшується. На EP8 m=128, тоді як на EP128 m=2048.

Зі збільшенням m арифметична інтенсивність також збільшується. У більшості конфігурацій GroupGEMM обмежений пропускною здатністю пам'яті, тому збільшення m покращує продуктивність.

GEMM

Ядро GEMM відповідає лінійним проєкціям у моделі, таким як проєкція Q/K/V/O. Для множення матриць [m, k] x [k, n] -> [m, n] кількість FLOP становить 2 * m * k * n, а байти введення-виведення пам'яті дорівнюють m * k + n * k + m * n. Ми також можемо перевірити затримку для розмірів батчів 1–128.

Продуктивність GEMM відносно меж обчислень і пропускної здатності пам’яті.

Наведений вище рисунок показує модель Roofline для GEMM за різних конфігурацій EP. Ми бачимо, що продуктивність GEMM обмежена пропускною здатністю пам'яті. Зі збільшенням розміру батча арифметична інтенсивність також збільшується, тим самим покращуючи продуктивність.

Мікробатчінг

При використанні мікробатчінгу ми ділимо батч рівномірно на дві частини. З двох наведених вище рисунків ми бачимо, що коли m стає m/2, ефективність множення матриць знижується. Тому виконання двох множень матриць розміром m/2 займає більше часу, ніж виконання одного множення матриць розміром m.

Багатотокенове прогнозування

Протягом цієї статті ми припускали використання багатокеневого прогнозування (Multi-Token Prediction, MTP) для спекулятивного декодування. MTP змінює довжину запиту на один запит з 1 на 2. Для множення матриць це еквівалентно зміні m на m * 2, тим самим збільшуючи ефективність множення матриць. З іншого боку, якщо ми намалюємо модель Roofline для MLA, ми виявимо, що збільшення довжини запиту суттєво збільшує ефективність ядра MLA.

Тому використання MTP відіграє важливу роль в ефективності моделі.

Реалізація та оптимізація

У цьому розділі ми представимо деякі деталі реалізації та оптимізації для нашої моделі DeepSeek-V3/R1.

Квантування

DeepSeek-V3/R1 була нативно навчена на FP8 з використанням схеми квантування по блоках (per-block quantization), причому ваги квантувалися статично, а активації —

У Perplexity ми покладаємося на суміш ядер CUDA та Triton для підтримки інференсу: CUDA використовується для найчутливіших до продуктивності та рідко модифікованих ядер (таких як увага та GEMM), тоді як Triton реалізує широкий спектр ядер активації, нормалізації та допоміжних ядер. Triton дозволив нам швидко адаптувати ядра до схеми блочного квантування.

Для лінійних і MoE-шарів ми поєднуємо ядра Deep GEMM з нашими власними ядрами Triton GEMM, оскільки помітили, що для певних розмірів матриць і малих розмірів пакета Split-K забезпечує нижчу затримку. Якщо не квантизований шар виконує множення (M, K) x (K, N), йому потрібен (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)) масштабувальний коефіцієнт для блокової квантизації. Для блокової квантизації масштабувальні коефіцієнти для активацій обчислюються на льоту, а не попередньо калібруються. Оскільки масштабувальні коефіцієнти активацій агрегуються лише вздовж виміру K, а не вздовж виміру M, ядра потребують лише незначних змін для підтримки цієї схеми.

Пакетоване обчислення SiLU та множення, що показує вхідні тензори експертів, вихідні тензори та коефіцієнти масштабування.

Функція активації SiLU, яка використовується в DeepSeek-V3/R1, вимагала суттєвих змін для підтримки графів CUDA, блочного квантування та динамічно маршрутизованої кількості токенів. Блочне квантування може бути проблематичним, оскільки воно вводить горизонтальні редукції, проте ядро вже розбивало активації вздовж їх прихованого виміру на блоки по 1024 елементи. У межах одного блоку тензор, який підлягає квантуванню, додатково розбивався на блоки по 128 для обчислення найбільшого абсолютного значення, причому Triton генерував ефективні міжварпові максимальні редукції (cross-warp max reductions), додаючи мінімальні накладні витрати.

Для підтримки маршрутизації MoE під графами CUDA ядра повинні знати інформацію про маршрутизацію, що вказує на кількість токенів на одного експерта, замість планування роботи на основі розміру буферів, виділених для утримання верхньої межі кількості токенів. Ми не можемо розділити проблему на основі розмірів вхідного тензора, тому ми запускаємо фіксовану кількість персистентних ядер, які зчитують інформацію про маршрутизацію, щоб визначити, скільки токенів заповнено, і динамічно розподіляють роботу з обробки активацій між ними.

Ми вже додали деякі з наших ядер до проєкту FlashInfer, і в майбутньому ми будемо відкривати вихідний код більшої кількості нашого коду.

Шар MLA

Ми використовуємо FlashInfer для обчислень MLA. FlashInfer підтримує гнучкі налаштування таблиці сторінок (Page Table) та надзвичайно високу продуктивність.

Ми об'єднали q_a_proj та kv_a_proj в єдиний qkv_a_proj. Затримка зменшилася з 15,4 мкс + 14,8 мкс = 30,2 мкс до 16,7 мкс.

Ми розклали kv_b_proj на дві матриці: k_b_proj та v_b_proj. Ми написали ядро BMM з блочним квантуванням FP8 для обчислень, пов'язаних із цими двома матрицями.

Граф Cuda

Граф Cuda може суттєво зменшити накладні витрати на запуск ядер, що має вирішальне значення для продуктивності. Ми створюємо граф Cuda для кожного розміру батча.

Перед розробкою нашого ядра AllToAll ми використовували torch.all_to_all_single() для комунікації AllToAll. Ця операція вимагає, щоб усі графічні процесори використовували однаковий розмір батча. Однак різні групи DP можуть запускати різні розміри батчів.

Щоб забезпечити сумісність all_to_all_single() з різними групами DP, які використовують різні розміри батчів, ми спочатку використовували операцію allreduce() перед кожним запуском моделі, щоб отримати максимальний розмір батча серед усіх груп DP. Потім ми змусили всі групи DP використовувати цей розмір батча для запуску.

Хоча цей підхід гарантує, що ми можемо використовувати граф Cuda, він має три недоліки. По-перше, він вимагає додаткової операції allreduce(). По-друге, групи DP з меншими розмірами батчів змушені використовувати заповнення (доповнення). По-третє, це робить код нашої реалізації складним.

Після реалізації власного ядра AllToAll нам більше не потрібно, щоб усі графічні процесори використовували однаковий розмір батча. Тому нам більше не потрібно виконувати додаткові операції allreduce() або заповнювати розміри батчів.

Маршрутизатор MoE

Маршрутизатор MoE реалізовано в Triton; він спирається на модифіковане сортування, похідне від стандартної бібліотеки, яке також відстежує індекси відсортованих елементів. Реалізація є спільною для всіх моделей MoE, оскільки маршрутизація Mixtral є особливим випадком маршрутів DeepSeek, де група Top-K збігається з групою всіх експертів. Розділені (sparse) ядра споживають індекси Top-K та оцінки безпосередньо, тоді як щільні (dense) схеми диспетчеризації/комбінування, що покладаються на all-to-all, вимагають агрегації інформації про маршрутизацію на основі кожного експерта, а не на основі кожного токена.

Майбутня робота

У подальшій роботі ми плануємо й надалі оптимізувати продуктивність моделі DeepSeek.

Найважливішою наступною оптимізацією є дезагрегація попереднього заповнення (Prefill Disaggregation). Фаза попереднього заповнення (Prefill) та фаза дешифрування (Decode) моделі DeepSeek-V3/R1 мають дуже різні обчислювальні характеристики. Обидві можуть використовувати різні стратегії оптимізації та схеми розгортання.

Для шару MLA у фазі дешифрування ми використовуємо поглинання матриць (Matrix Absorption), щоб зменшити кількість FLOP обчислень MLA. У фазі попереднього заповнення спочатку проєктування латентного вектора у простір K/V, а потім обчислення у формі багатоголової уваги (Multi-Head Attention, MHA) працюватиме краще.

Якщо попереднє заповнення та дешифрування виконуються на одному графічному процесорі, щоб зменшити вплив попереднього заповнення на швидкість виведення дешифрування, ми зазвичай використовуємо попереднє заповнення чанками (chunked prefill), щоб розділити запит на кілька чанків для попереднього заповнення. Оскільки кеш KV зберігає латентний вектор, перетворення MLA у форму MHA стає складним.

Для шару MoE у фазі дешифрування ми використовуємо якомога більші EP та DP, щоб збільшити кількість вхідних токенів на одного експерта, тим самим покращуючи продуктивність GroupGEMM. У фазі попереднього заповнення, оскільки кількість токенів і так достатньо велика, GroupGEMM вже обмежений обчисленнями. Тому для попереднього заповнення ми можемо використовувати менші EP та DP.

Якщо попереднє заповнення та дешифрування виконуються на одному графічному процесорі, доки будь-яка група DP виконує попереднє заповнення, затримка шарів MoE на всіх графічних процесорах збільшиться, суттєво впливаючи на швидкість виведення дешифрування.

Окрім дезагрегації попереднього заповнення, ми також плануємо оптимізувати такі аспекти:

Продуктивність AllToAll: наше ядро AllToAll наразі може досягати лише 1/3 пропускної здатності Infiniband. Ми продовжуватимемо оптимізувати це ядро.

Спекулятивне декодування у стилі EAGLE: у наведених вище даних ми припускали використання спекулятивного декодування для прогнозування 1 токена. EAGLE може використовувати структуру дерева для прогнозування кількох токенів, покращуючи довжину прийняття, що може суттєво збільшити швидкість виведення.

Ядро GEMM: у показаній раніше моделі Roofline ми можемо виявити, що ефективність ядра GEMM все ще далека від теоретичної межі. Ми продовжуватимемо оптимізувати це ядро.

GB200 NVL72: у новітньому рішенні GB200 NVL72 від NVIDIA 72 графічні процесори Blackwell з'єднані між собою через високошвидкісний NVLink. Для моделей з архітектурою MoE це дуже велика можливість і виклик.

Висновок

Багатопотокове розгортання моделей DeepSeek MoE досягає того, що зазвичай неможливо зі щільними LLM: одночасне покращення як пропускної здатності, так і затримки. Розподіляючи експертів між більшою кількістю графічних процесорів, ми зменшуємо навантаження на пропускну здатність пам'яті на кожний пристрій, забезпечуючи швидшу обробку та вищу пропускну здатність системи. Наші експерименти показують, що конфігурації EP128 досягають до 5 разів вищої пропускної здатності при еквівалентній швидкості виведення порівняно з однопотоковим розгортанням.

Техніки суміщення обчислень і зв'язку, такі як мікробатчінг, суттєво зменшують накладні витрати на багатопотоковий зв'язок, при цьому наша реалізація показує прискорення до 40%. Наші власні ядра зв'язку AllToAll та оптимізовані реалізації ядер уможливили ефективне розгортання моделі з 671 млрд параметрів.

Оскільки архітектури MoE завойовують популярність завдяки своїм можливостям, ці стратегії розгортання дають цінні поради щодо ефективного масштабування таких моделей.

Посилання

Технічний звіт DeepSeek-V3

Огляд системи інференсу DeepSeek-V3/R1

Megatron-LM: Навчання мовних моделей із багатьма мільярдами параметрів за допомогою паралелізму моделей

EAGLE: Спекулятивна вибірка вимагає переосмислення невизначеності ознак

Цитування

BibTeX
@online{perplexity2025LowerLatencyAndHigherThroughputWithMultiNodeDeepseekDeployment,
  author = {{Perplexity} and Lequn Chen and Nandor Licker and Erin McKnight},
  title = {{Lower latency and higher throughput with multi-node DeepSeek deployment}},
  date = {2025-04-18},
  url = {https://perplexity.coolkeypoint.com/hub/blog/lower-latency-and-higher-throughput-with-multi-node-deepseek-deployment}
}