Почему MoE-модели на RTX 5090 работают медленнее: разбор узкого места

Современные видеокарты, такие как RTX 5090, обещают высокую производительность при запуске больших языковых моделей, но на практике пользователи часто сталкиваются с неожиданным замедлением. Особенно это заметно при работе с архитектурой Mixture of Experts (MoE), где активируется лишь часть параметр

Почему MoE-модели на RTX 5090 работают медленнее: разбор узкого места

Современные видеокарты, такие как RTX 5090, обещают высокую производительность при запуске больших языковых моделей, но на практике пользователи часто сталкиваются с неожиданным замедлением. Особенно это заметно при работе с архитектурой Mixture of Experts (MoE), где активируется лишь часть параметров. Свежее исследование, опубликованное на Habr, проливает свет на истинную причину: дело не в маршрутизации экспертов, а в том, сколько байт памяти считывает каждое ядро за один запуск. Это открытие меняет подход к оптимизации инференса и объясняет, почему бенчмарки часто расходятся с реальным пользовательским опытом.

Эксперимент, проведённый автором, показал, что плотная модель Qwen3.5-9B утилизирует 72% пропускной способности памяти, тогда как MoE Qwen3.5-35B-A3B — лишь 41%. При этом маршрутизация экспертов, которую часто считают узким местом, занимала всего 7% времени ядер top-k. CUDA-графы захватывались корректно, зазоров между запусками не было, а занятость потоковых мультипроцессоров (SM) достигала 97%. Карта работала почти всё время, но просто выполняла операции медленнее, чем позволяла память.

Причина найдена: размер данных на ядро

Ключевым фактором оказался объём данных, который считывает одно ядро за запуск. Автор написал программу на ggml, которая гоняет ту же операцию mulmatvecq на холодных весах, и снял кривую зависимости. При размере данных 1 МБ ядро использовало лишь 23% полосы пропускания, при 4.2 МБ — уже 53%, а при 33.6 МБ — 91%. У MoE-модели на одно ядро приходится всего 4.6 МБ, тогда как у плотной модели — 22.2 МБ. Именно этот разрыв объясняет почти двукратную разницу в эффективности.

Почему это происходит? Современные GPU используют иерархию памяти: быстрая кэш-память L2 и медленная глобальная память HBM. Когда ядро обрабатывает небольшой объём данных, оно не успевает полностью загрузить конвейер: латентность доступа к памяти доминирует над пропускной способностью. Для достижения максимальной скорости нужно, чтобы каждый поток читал достаточно большие блоки, чтобы скрыть задержки. В MoE-моделях веса экспертов разбросаны по памяти, и каждое ядро обрабатывает лишь малую часть, что приводит к недогрузке.

Предыстория и контекст

MoE-архитектуры стали популярны благодаря возможности увеличивать общее число параметров без пропорционального роста вычислительных затрат. В моделях вроде Qwen3.5-35B-A3B активируются лишь 3 миллиарда параметров из 35, что должно ускорять инференс. Однако на практике выигрыш часто нивелируется особенностями аппаратного обеспечения. Ранее считалось, что основная проблема — накладные расходы на маршрутизацию, но данное исследование показывает, что она почти не влияет.

Интересно, что аналогичные проблемы наблюдаются и на других архитектурах. Автор проверил модель на другой архитектуре и получил ошибку всего 3.7%, что подтверждает универсальность вывода. Также были протестированы четыре глубины контекста — результаты остались стабильными. Это говорит о том, что проблема фундаментальна и связана с тем, как GPU взаимодействует с памятью при работе с разреженными весами.

Как это влияет на пользователей?

Для конечных пользователей это означает, что реальная скорость генерации может быть ниже, чем показывают синтетические бенчмарки. В эксперименте llama-server выдавал 225 токенов в секунду, тогда как бенчмарк показывал 317. Разница объясняется накладными расходами сэмплера и всей обвязки сервера, которые в сумме оказались больше, чем всё остальное. Если вы используете MoE-модели для чат-ботов или генерации кода, стоит ожидать, что пропускная способность будет на 30–40% ниже пиковой.

Разработчикам важно понимать, что оптимизация только маршрутизации не даст значительного прироста. Вместо этого нужно сосредоточиться на увеличении размера данных, обрабатываемых одним ядром, например, через группировку экспертов или изменение формата хранения весов. Также полезно профилировать приложения с помощью инструментов вроде Nsight Systems, как это сделал автор, чтобы выявить реальные узкие места.

Технические подробности эксперимента

Автор провёл детальный анализ всех 437 матричных умножений (matvec) с помощью трассировки nsys. Он также описал четыре способа измерить производительность неправильно, предостерегая от типичных ошибок: использование среднего времени вместо медианы, игнорирование холодного кэша, неучёт накладных расходов на синхронизацию и неправильная интерпретация занятости SM. Каждая ловушка подробно разобрана, что делает статью ценным руководством для тех, кто хочет самостоятельно провести бенчмарки.

Одним из ключевых результатов стало сравнение эффективности при разных размерах данных. Кривая показывает, что для достижения хотя бы 50% полосы пропускания нужно читать не менее 4–5 МБ на ядро. Плотные модели легко удовлетворяют этому требованию, а MoE — нет. Это объясняет, почему даже с высокой занятостью SM производительность остаётся низкой: память не успевает подавать данные.

Кого затронет и как

Разработчики локальных инференс-движков, таких как llama.cpp, могут использовать эти данные для оптимизации планировщика ядер. Например, можно объединять операции для нескольких экспертов в одно ядро, чтобы увеличить объём читаемых данных. Пользователи, которые запускают MoE-модели на потребительских GPU, должны быть готовы к тому, что реальная скорость будет ниже теоретической. В то же время для серверных решений с большими батчами проблема может быть менее выражена, так как параллельная обработка запросов увеличивает размер данных на ядро.

Для российских пользователей, которые часто используют RTX 5090 из-за ограничений на поставки, это исследование особенно актуально: оно помогает выбрать модель под конкретное железо. Если вы планируете запускать MoE, лучше рассмотреть варианты с меньшим числом экспертов или оптимизированные форматы вроде GGUF с квантованием, которые могут частично компенсировать проблему.

Что будет дальше

Автор планирует продолжить исследования, сосредоточившись на оптимизации форматов весов и алгоритмов загрузки. Возможно, в ближайшее время появятся патчи для llama.cpp, которые учтут эти особенности. Также стоит ожидать новых статей с практическими рекомендациями по настройке. Пока же пользователям рекомендуется использовать последние версии движков и следить за обновлениями.

Итог

Главный вывод: узким местом MoE-моделей на RTX 5090 является не маршрутизация, а малый объём данных на ядро, что приводит к недозагрузке пропускной способности памяти. Это понимание позволяет разработчикам и пользователям принимать обоснованные решения об оптимизации и выборе моделей. Следите за обновлениями в экосистеме llama.cpp — возможно, скоро мы увидим решения, которые сократят этот разрыв.