AIKraft Agents
Главная/Блог/Аналитика/Ускорение MoE-инференса на NVIDIA DGX…
Аналитика9 мин чтения · 27 октября 2026 г.

Ускорение MoE-инференса на NVIDIA DGX Spark: 3 способа

Глубокое руководство по оптимизации вывода больших языковых моделей (MoE) на NVIDIA DGX Spark: от замены бэкендов до спекулятивного декодирования.

В эпоху, когда большие языковые модели (LLM) становятся все более сложными, а их параметры исчисляются сотнями миллиардов, вопрос эффективности вывода (inference) выходит на первый план. Особенно это касается гибридных архитектур, таких как Mixture of Experts (MoE), которые предлагают высокую плотность параметров при относительно низкой вычислительной нагрузке на каждый токен. Однако, как показывает практика, сама архитектура MoE вносит специфические узкие места, связанные с доступом к памяти и маршрутизацией экспертов. В этой статье мы подробно разберем реальный кейс оптимизации модели Ling-3.0-flash на платформе NVIDIA DGX Spark, где удалось достичь значительного прироста производительности без потери точности.

Рассматриваемая модель Ling-3.0-flash от Inclusion AI — это мощный MoE-модель с 124 миллиардами параметров, из которых активными являются лишь 5,1 миллиарда на каждый токен. Такая архитектура идеально подходит для задач агентного ИИ, где требуется не только генерация текста, но и сложное логическое рассуждение, работа с инструментами и понимание пространственных отношений. Но даже при таком эффективном распределении ресурсов, базовая конфигурация может не обеспечивать желаемую скорость отклика, особенно в сценариях с малым пакетом (batch size 1), что типично для интерактивных приложений.

Профилирование показало, что процесс декодирования в Ling-3.0-flash ограничен пропускной способностью памяти (memory-bound). Это означает, что GPU простаивает, ожидая загрузки весов модели из видеопамяти, а не выполняет вычисления. Два основных компонента, потребляющих больше всего времени, — это вычисления MoE (маршрутизация и активация экспертов) и проекция выходного слоя (LM head), которая преобразует скрытые представления в вероятности токенов словаря. На основе этих данных были разработаны три ключевые оптимизации, которые мы рассмотрим подробно.

01Контекст задачи: Модель Ling-3.0-flash и архитектура DGX Spark

Прежде чем углубляться в технические детали оптимизаций, важно понять, с чем именно мы работаем. Ling-3.0-flash — это не просто еще одна LLM. Это модель, спроектированная для агентных рабочих процессов (Agentic AI). Она поддерживает нативное контекстное окно в 256 тысяч токенов, которое можно расширить до 1 миллиона. Это критически важно для задач, требующих анализа длинных документов, кодовых баз или историй диалогов.

Архитектурно модель состоит из 42 слоев. 35 из них используют линейное внимание Kimi Delta Attention (KDA), а остальные 7 — многоголовое латентное внимание (MLA). Такая гибридная структура позволяет эффективно обрабатывать длинные последовательности, снижая вычислительную сложность, типичную для стандартного механизма внимания. В каждом слое MoE токен маршрутизируется к восьми из 512 экспертов, а также к одному общему эксперту. Это обеспечивает высокую емкость модели при сохранении низкой задержки.

Оценка проводилась на NVIDIA DGX Spark — компактной, но мощной платформе для развертывания ИИ-моделей на краю сети (edge) или в локальных центрах обработки данных. DGX Spark предлагает высокую плотность вычислений и памяти, что делает ее идеальной средой для тестирования оптимизаций, которые затем можно масштабировать на более крупные кластеры. Базовая конфигурация для сравнения использовала формат MXFP4 для весов MoE и BF16 для выходного слоя (LM head), что является стандартным подходом для балансировки между точностью и скоростью.

02Оптимизация 1: Замена бэкенда MoE на Humming

Первая и фундаментальная оптимизация касается бэкенда, отвечающего за выполнение вычислений в слоях MoE. В базовой конфигурации используется бэкенд flashinfer_mxfp4, который опирается на библиотеку NVIDIA CUTLASS для плотных матричных умножений (GEMM). Однако для специфических форматов данных и архитектур, таких как Ling-3.0-flash, этот путь не всегда является оптимальным.

Вместо этого мы внедрили библиотеку Humming (доступную через пакет humming-kernels). Главная особенность Humming заключается в использовании NVIDIA CUDA Runtime Compilation (NVRTC). В отличие от статической компиляции, Humming генерирует и компилирует CUBIN-бинарники непосредственно во время выполнения, адаптируясь под конкретные размеры M/N/K, типы данных и архитектуру GPU. Это позволяет создать специализированные ядра, идеально подходящие для узких размеров промежуточных слоев MoE (moe_intermediate_size = 768 в случае Ling-3.0-flash).

💡
Почему это важно. Humming компилирует ядра с finer granularity (более мелкой детализацией). Одно ядро компилируется за секунды, тогда как путь FlashInfer CUTLASS требует компиляции 97 целей через ninja, что занимает десятки минут. Это не только ускоряет запуск, но и обеспечивает лучшую производительность за счет точной адаптации под конкретную модель.

Результаты профилирования показали значительный прирост. Время на генерацию одного выходного токена (TPOT) сократилось с 27,71 мс до 25,35 мс. Это эквивалентно увеличению пропускной способности декодирования на 9,3% (с 36,09 до 39,45 токенов в секунду). Хотя процент может показаться modest, в контексте высоконагруженных систем это существенная экономия ресурсов, особенно при масштабировании на тысячи запросов.

03Оптимизация 2: Онлайн-квантование LM head в FP8

Вторая оптимизация направлена на устранение еще одного узкого места: операции чтения весов выходного слоя (LM head). В исходном чекпоинте веса LM head хранятся в формате BF16. Размер этого слоя огромен: он проецирует скрытое измерение размером 2560 в словарь из 157 184 токенов. Это означает, что для генерации каждого нового токена GPU должен прочитать огромный блок данных из видеопамяти.

Поскольку процесс декодирования ограничен пропускной способностью памяти, уменьшение объема передаваемых данных дает прямой выигрыш. Мы применили динамическое квантование в формат FP8 только для LM head. Это делается с помощью флага SGLANG_ENABLE_FP8_LM_HEAD=1. Важно отметить, что эта опция взаимно исключает использование флага --enable-fp32-lm-head, который выводит логиты в FP32 и использует более медленный путь GEMM для словаря.

Перевод весов из BF16 (16 бит) в FP8 (8 бит) удваивает плотность хранения, тем самым сокращая объем чтения весов для этого слоя вдвое. В сочетании с оптимизацией HumMoE, это дало кумулятивный эффект. TPOT снизился до 22,76 мс, а пропускная способность выросла до 43,94 токенов в секунду. Общий прирост по сравнению с базовой линией составил 21,7%. Это демонстрирует, что даже небольшие изменения в управлении памятью могут иметь огромный эффект при memory-bound нагрузках.

04Оптимизация 3: Спекулятивное декодирование с MTP и NEXTN

Первые две оптимизации снижали стоимость каждого отдельного шага декодирования. Третья оптимизация меняет саму парадигму: она уменьшает количество шагов декодирования. Для этого используется спекулятивное декодирование с предсказанием нескольких токенов (Multi-Token Prediction, MTP). Модель Ling-3.0-flash имеет встроенный слой NEXTN (num_nextn_predict_layers: 1), который может действовать как модель-черновик (draft model) без дополнительного обучения или загрузки сторонних весов.

Конфигурация MTP работает следующим образом: модель-черновик предсказывает несколько токенов последовательно (в нашем случае 3 шага черновика), а целевая модель проверяет их за один проход, верифицируя до 4 позиций одновременно. Если предсказание верно, токены принимаются. Ключевые метрики здесь — это длина принятия (accept length) и коэффициент стоимости верификации. В нашем случае коэффициент составил около 2,26, что означает, что шаг верификации стоит в 2,26 раза дороже обычного шага декодирования. Это связано с тем, что при верификации активируется больше экспертов (до 32 вместо 8), так как обрабатывается несколько токенов одновременно.

⚠️
Критическая ошибка интеграции. При совместном использовании онлайн-квантования LM head в FP8 и MTP возникает проблема совместимости. Модель-черновик должна разделять весь модуль LM head с целевой моделью, а не только тензор весов. В оригинальной реализации Ling NEXTN этот интерфейс не был открыт. Без него система молча падает: черновик получает веса FP8, но интерпретирует их как BF16, что снижает длину принятия до 1.00 и делает производительность хуже базовой. Необходимо использовать исправленную версию из Ling cookbook, чтобы обеспечить корректный обмен модулями.

При правильной настройке MTP показал впечатляющие результаты. Длина принятия токенов достигла 3,90 на синтетической нагрузке. Это привело к снижению TPOT до 9,72 мс и увеличению пропускной способности до 102,88 токенов в секунду. Прирост составил 185,1% по сравнению с базовой линией. Однако, как мы увидим далее, эти цифры характерны для синтетических данных и могут отличаться в реальных сценариях.

05Реальные результаты: Тестирование на наборе данных GSM8K

Хотя синтетические нагрузки (32K входных токенов, 2K выходных) полезны для изоляции отдельных оптимизаций, они часто переоценивают преимущества спекулятивного декодирования из-за высокой повторяемости генерируемого текста. Для получения объективной картины мы провели тестирование на полном наборе данных GSM8K, который содержит 1 319 математических задач. Этот тест требует цепочки рассуждений (chain-of-thought), что делает его более репрезентативным для сложных агентных задач.

Тестирование проводилось с использованием five-shot prompting, температуры 0.6, top_p 0.95 и top_k 29. Все переменные, кроме оптимизаций, были идентичны. Результаты на реальном наборе данных показали, что три оптимизации вместе увеличили пропускную способность декодирования на 42,5% (с 37,81 до 53,89 токенов в секунду) и снизили среднюю задержку на 24,5% (с 15,21 с до 11,49 с). При этом точность модели на GSM8K осталась практически неизменной: 96,89% для базовой версии и 96,82% для оптимизированной, что статистически незначимо.

Важно отметить различия в длине принятия токенов. На синтетической нагрузке она составила 3,90, а на GSM8K — 2,68. Это связано с тем, что реальные ответы на задачи GSM8K короче (медиана около 310 токенов против фиксированных 2000 в синтетике) и менее повторяемы. Тем не менее, даже в реальных условиях комбинированная оптимизация дала существенный прирост скорости.

06Почему синтетические и реальные нагрузки различаются

Разница между результатами на синтетических данных и GSM8K обусловлена несколькими факторами. Во-первых, синтетические выходные данные более повторяемы, что облегчает задачу модели-черновика в предсказании следующих токенов. Во-вторых, параметры сэмплирования различаются: синтетический тест использовал жадное декодирование (greedy decoding), в то время как реальная оценка применяла вероятностное сэмплирование с температурой 0.6. В-третьих, распределение длин выходных данных различается: фиксированная длина 2K токенов в синтетике позволяет распределить фиксированные накладные расходы от первых двух оптимизаций на более длинную последовательность, тогда как в GSM8K выходные данные короче.

Это подчеркивает важность выбора репрезентативной рабочей нагрузки для тестирования. Прирост в 185,1%, измеренный на синтетической нагрузке, не гарантирует такого же прироста для других рабочих нагрузок. Разработчикам следует использовать сценарии, максимально близкие к их целевому развертыванию, для оценки реальной производительности.

07Что это значит на практике

Рассмотренные оптимизации демонстрируют, что даже в зрелых фреймворках и моделях можно найти значительные резервы производительности. Ключевые выводы для разработчиков:

  • Используйте специализированные ядра. Замена стандартных бэкендов (FlashInfer) на специализированные (Humming) может дать прирост в 10% без изменения архитектуры модели. Это особенно актуально для моделей с нестандартными размерами слоев.
  • Квантуйте выходной слой. Если ваша модель ограничена пропускной способностью памяти, квантование LM head в FP8 — один из самых эффективных способов ускорения. Убедитесь, что вы используете правильные флаги конфигурации (например, SGLANG_ENABLE_FP8_LM_HEAD=1).
  • Внимательно интегрируйте MTP. Спекулятивное декодирование с использованием встроенных слоев NEXTN может дать двукратный прирост скорости. Однако критически важно обеспечить корректный обмен модулями LM head между черновиком и целевой моделью, особенно при использовании квантования. Иначе система может молча деградировать.
  • Тестируйте на реальных данных. Всегда валидируйте оптимизации на наборах данных, отражающих ваши реальные задачи. Синтетические тесты полезны для отладки, но не для оценки финальной производительности.

Комбинирование этих методов позволяет достичь значительного ускорения вывода MoE-моделей на NVIDIA DGX Spark без потери точности. Следуйте инструкциям в Ling cookbook для развертывания этих оптимизаций и не забывайте проверять активацию каждой оптимизации при запуске, чтобы избежать скрытых ошибок конфигурации.

Источник: NVIDIA Developer ↗