GPT-OSS в Day 0

Поддержка GPT-OSS на H200 в Day-0 путем адаптации ROSE с оптимизациями FP8, sink attention и MoE

АвторыPerplexity Engineering

Perplexity стремится предоставлять лучшие модели ИИ любознательным пользователям, которым требуются точные и достоверные ответы, а также агентные действия. OpenAI недавно анонсировала свои модели с открытыми весами (gpt-oss-20b и gpt-oss-120b). Как и в случае со многими ведущими моделями, Perplexity стала одной из первых организаций, выполнивших оценку gpt-oss-20b и gpt-oss-120b.

В этой статье мы делимся решениями в области инфраструктуры нашего внутреннего стека инференса, которые позволили обеспечить поддержку Day-0. Мы сосредоточились на работе этих моделей на графических процессорах NVIDIA H200, подробно описывая изменения ядра, варианты развертывания, а также компромиссы между скоростью и затратами.

GPT-OSS на Hopper

Модели с открытыми весами поставляются с использованием квантования MXFP4, что помогает им помещаться в память потребительского оборудования или достигать пиковой пропускной способности на NVIDIA Blackwell. Однако для первоначальной оценки мы хотели запустить их на существующих кластерах H200 Hopper с минимальными изменениями движка инференса. Архитектура Hopper не имеет выделенных тензорных ядер FP4, которые были представлены в Blackwell. Следовательно, мы решили использовать модели с точностью FP8, чтобы минимизировать необходимость в пользовательских ядрах и максимально эффективно использовать доступное оборудование.

На верхнем уровне трансформерные LLM структурно просты:

Входное эмбеддинг-слой

Последовательность слоев трансформера. Каждый слой содержит блок внимания, а также плотный блок MLP или разреженный блок MoE.

Проекция выходных логитов

При внедрении новой модели-трансформера нас в первую очередь интересует степень их соответствия существующим моделям, чтобы определить необходимые изменения. Компания OpenAI заблаговременно предоставила обзор своих моделей, что позволило нам соответствующим образом настроить нашу конфигурацию инференса. Мы обнаружили, что модель действительно потребовала внесения ряда небольших изменений.

Внимание: GQA с «аттракторами» внимания (Attention Sinks)

Каждая голова внимания имеет предварительно обученный параметр аттрактора, который учитывается в Softmax

Позиционное кодирование YaRN, аналогичное DeepSeek-V3

QKV-проекции имеют смещения (biases), аналогично Qwen 2

Выходная проекция имеет смещение

MLP: Разреженная смесь экспертов (MoE)

Функция активации SwiGLU, отличающаяся от большинства моделей с открытыми весами

Softmax после Top-K для весов экспертов

Эксперты имеют смещения

Ожидая, что количество параметров составит около 100–200 млрд, мы решили:

Расширить FlashInfer для поддержки аттракторов внимания

Повторно использовать реализацию MoE, уже созданную для семейства моделей DeepSeek-V3

Выбрать масштабирование блоков FP8 128x128 в качестве схемы квантования, расширив ядра DeepGEMM для поддержки члена смещения.

Собственный движок инференса

Наша работа по инференсу поддерживается нашим собственным движком ROSE. Мы развиваем ROSE как гибкий фреймворк, позволяющий быстро внедрять новые модели. Кроме того, как только мы принимаем обязательства по обслуживанию модели в масштабе, он предоставляет платформу для оптимизации и повышения производительности до современного уровня.

ROSE предоставляет движок LLM, который может загружать модель и генерировать декодированные токены с помощью нескольких декодеров, включая спекулятивные декодеры и декодеры MTP. Сами модели состоят из пользовательского набора слоев, поддерживающих различные параметры конфигурации для квантования и параллелизма. Под слоями он объединяет ядра Triton и CUDA, которые эффективно реализуют и объединяют вычисления, выполняемые отдельными слоями.

ROSE в основном построен на Python и полагается на PyTorch для определений моделей. Хотя Python позволяет нам быть гибкими и адаптироваться к новым моделям, мы переносим большинство компонентов, чувствительных к производительности, таких как обслуживание и планирование пакетов, на Rust.

Чтобы внедрить новую модель, мы сначала определяем иерархию модели и создаем для нее конвертер весов. После того как все веса учтены, мы определяем прямой проход для простейшего случая использования TP=1 и обеспечиваем его работу от начала до конца. Наконец, мы реализуем и тестируем поддержку различных форм параллелизма перед выпуском нового контейнера и развертыванием модели в кластере для оценки. Затем мы итеративно работаем над производительностью, опираясь на отзывы с дашбордов и более детальные бенчмарки.

ROSE работает с числовыми токенами, практически не обладая информацией о форматах Чата, за исключением интеграционных тестов. Параллельно нам пришлось заняться корректировкой окружающей инфраструктуры для поддержки токенизатора Harmony и корректного отображения запросов на последовательности входных токенов.

С моделью GPT OSS мы обнаружили, что никаких изменений в наших декодерах, обвязках графов CUDA или окружающей инфраструктуре не потребовалось, что позволило нам сосредоточить усилия на настройке ядер, поддерживающих модель.

Ядра для GPT-OSS

Аттрактор внимания (Sink Attention)

Sink attention вводит дополнительный коэффициент смещения перед softmax, суммируемый с произведением Q и K:

plaintext
attn = softmax(q @ k^T * sm_scale + sink) * V

Хотя простая реализация довольно тривиальна, эффективные реализации внимания, такие как FlashInfer, распараллеливают вычисление внимания как по независимым головам, так и по длине последовательности KV. Кроме того, для числовой стабильности Softmax вычисляется онлайн с одновременным вычитанием максимального элемента:

plaintext
softmax(x) = e^x / sum(e^x) = e ^ (x - max(x)) / sum(e ^ (x - max(x))

Онлайн-реализация отслеживает текущий максимум m, инициализированный значением -inf, и масштаб d равным 1. Инициализируя максимум значением аттрактора текущей головы, мы обеспечиваем его корректное накопление в Softmax. Мы позаботились о том, чтобы этот максимум включался только в первый фрагмент, если внимание разбито на несколько блоков вдоль длины последовательности.

Мы скорректировали шаблон ядра FlashInfer FA2, используемый как для предварительного заполнения (prefill), так и для декодирования, чтобы включить параметры аттрактора.

MoE

Основное различие между слоем MoE разных моделей обычно заключается в схеме маршрутизации. Ожидая существенной вариативности, ROSE реализует это ядро на Triton, что позволяет нам легко адаптировать его к новым моделям. В случае с GPT-OSS нам пришлось скорректировать оценку весов, чтобы выполнять softmax только по Top-K выбранным экспертам, в отличие от некоторых моделей в стиле DeepSeek, которые вычисляют softmax по всем экспертам. Мы выяснили, что для точности критически важно вычислять веса экспертов с точностью bfloat16.

Сложность со слоем MoE была обусловлена нашим решением повторно использовать существующие ядра DeepGEMM, в которых отсутствовала поддержка членов смещения. К счастью, со временем мы глубоко интегрировались с ними, внеся изменения для улучшения связи с нашими пользовательскими ядрами диспетчеризации «все-ко-всем» (all-to-all). Мы добавили поддержку смещения в DeepGEMM, инициализировав аккумуляторы WGMMA значениями смещения, загруженными из памяти. Это разовая операция при обработке блока MN, поэтому затраты, вероятно, незначительны, а кэш L2 обеспечивает эффективный доступ к этим значениям.

Поскольку эти модели не получают преимуществ от Data Parallelism, мы повторно использовали только диспетчеризацию TP и комбинированные ядра. Входные данные для диспетчеризации реплицируются по всем рангам, поэтому диспетчеризация выбирает токены для локально доступных экспертов. Combine выполняет взвешенное накопление через NVLink.

Оптимизация производительности

Несмотря на то, что нашей целью было быстрое внедрение моделей, мы хотели убедиться, что производительность остается приемлемой. Убедившись в корректности по сравнению с эталонной реализацией, предоставленной OpenAI, мы профилировали нашу реализацию с использованием профилировщика PyTorch по умолчанию, следя за распределением блоков и тредов по ядрам. Использованная нами функциональность была создана для моделей с большим скрытым измерением 7168, что значительно больше 2880 у моделей GPT-OSS. Мы специализировали загрузчики ядер для выбора лучших размеров сетки, значительно повысив пропускную способность.

Токенизация и каналы

Формат Чата Harmony имеет несколько важных концепций для структурирования диалогов, логических рассуждений и вызовов функций. В этом формате каждое сообщение состоит из заголовка и контента:

plaintext
<|start|>{header}<|message|>{content}<|end|>

Заголовок содержит метаданные — самое важное: роль (система, разработчик, пользователь, ассистент, инструмент), канал и получателя, например to=functions.<function-name> при вызове функции.

Каналы (такие как анализ, комментарии и итоговый ответ) делают выводы модели более прозрачными и сегментированными. Поскольку формат обеспечивает это разделение, модель может рассуждать прозрачно (и быть проверенной для отладки) без утечки цепочки рассуждений (chain-of-thought) в рабочую среду. Теги получателя (заголовки to=) сообщают исполняемой среде, какой именно субъект должен получить следующую нагрузку — будь то функция, сама модель или конечный пользователь.

Наш движок инференса ROSE агностичен к форматам. Он получает пакет входных токенов и потоком возвращает выходные токены. В нашем стеке инференса задача форматирования входных данных в токенизированный промпт и парсинг результатов LLM обратно в структурированные сообщения обрабатывается выделенным сервисом фронтенда JSON API. Мы интегрировали Harmony, добавив новый подключаемый форматер/парсер в этот фронтенд, что позволило бэкенду остаться без изменений, в то время как фронтенд чисто управляет правилами формата Чата, вызовами функций и потоковой передачей. Такое разделение обязанностей сохраняет архитектуру модульной, позволяя быстро внедрять новые форматы и функции ответов с минимальными изменениями бэкенда.

Стоимость и производительность

Учитывая относительно небольшой размер моделей GPT-OSS, мы ограничиваем развертывание реплики одним узлом, чтобы избежать накладных расходов на межсоединения. Наша реализация поддерживает гибкие комбинации экспертного параллелизма (EP), параллелизма данных (DP) и тензорного параллелизма (TP). Чтобы определить оптимальную схему развертывания, мы провели бенчмаркинг всех комбинаций стратегий шардирования с размерами пакетов от 1 до 128. Благодаря разделению Prefill-Decode, мы можем отдельно обсуждать компромисс между производительностью и стоимостью для этапов prefill и decode.

Для оценки затрат мы предполагаем номинальную рыночную ставку H200 в $3,00/час (примечание: это не наша фактическая цена на GPU).

Мы обнаружили, что установка batch_size=1 и DP=1 обеспечивает наилучшую производительность prefill. Различные конфигурации TP обеспечивают различные компромиссы между задержкой первого токена и стоимостью. В таблицах ниже представлены задержка prefill и стоимость на миллион входных токенов для различных конфигураций и длин ввода.

GPT-OSS 120B:

Длина ввода

8192

32768

65536

128000

EP1 DP1 TP1

0.364с, $0.037

2.421с, $0.062

7.375с, $0.094

23.902с, $0.156

EP2 DP1 TP2

0.190с, $0.039

1.245с, $0.063

3.786с, $0.096

12.116с, $0.158

EP4 DP1 TP4

0.165с, $0.067

0.900с, $0.092

2.449с, $0.125

7.165с, $0.187

EP8 DP1 TP8

0.179с, $0.145

0.839с, $0.171

2.003с, $0.204

5.119с, $0.267

Задержка предварительной обработки GPT-OSS 120B и стоимость на миллион входных токенов в зависимости от конфигурации параллелизма и длины входа.

GPT-OSS 20B:

Длина ввода

8192

32768

65536

128000

EP1 DP1 TP1

0.239с, $0.024

1.610с, $0.041

4.895с, $0.062

16.037с, $0.104

EP2 DP1 TP2

0.127с, $0.026

0.833с, $0.042

2.522с, $0.064

8.143с, $0.106

EP4 DP1 TP4

0.108с, $0.044

0.593с, $0.060

1.616с, $0.082

4.766с, $0.124

EP8 DP1 TP8

0.116с, $0.094

0.547с, $0.111

1.310с, $0.133

3.365с, $0.175

Задержка предварительной обработки GPT-OSS 20B и стоимость на миллион входных токенов в зависимости от конфигурации параллелизма и длины входа.

Для декодирования мы обнаружили, что EP4 DP1 TP4 является лучшей конфигурацией для большинства случаев. Четыре графика ниже иллюстрируют компромисс между скоростью декодирования и стоимостью на миллион выходных токенов как для моделей 120B, так и для 20B при длине последовательности 8192 и 32768.

Стоимость только декодирования на миллион выходных токенов в сравнении со скоростью декодирования для GPT-OSS 120B при длине последовательности 8 192, с сопоставлением конфигураций EP1, EP2, EP4 и EP8.
Стоимость только декодирования на миллион выходных токенов в сравнении со скоростью декодирования для GPT-OSS 120B при длине последовательности 32 768, с сопоставлением конфигураций EP1, EP2, EP4 и EP8.
Стоимость только декодирования на миллион выходных токенов в сравнении со скоростью декодирования для GPT-OSS 20B при длине последовательности 8 192, с сопоставлением конфигураций EP1, EP2, EP4 и EP8.
Стоимость только декодирования на миллион выходных токенов в сравнении со скоростью декодирования для GPT-OSS 20B при длине последовательности 32 768, с сопоставлением конфигураций EP1, EP2, EP4 и EP8.

Мы также рассматривали возможность использования меньшей модели 20B в качестве модели-черновика для спекулятивного декодирования для более крупной модели 120B. Однако, поскольку количество активированных параметров схоже (3 млрд против 5 млрд), полученное ускорение было незначительным.

Ссылки

Разделенное предварительное заполнение и декодирование (Disaggregated Prefill and Decode)

Ускорение Sonar посредством спекуляции​

Снижение задержки и увеличение пропускной способности при многоузловом развертывании DeepSeek

​Эффективная и переносимая коммуникация Mixture-of-Experts

​pplx-kernels

DeepGEMM

FlashInfer: Эффективный и настраиваемый движок внимания для инференса LLM

Эффективные потоковые языковые модели с аттракторами внимания

Технический отчет DeepSeek-V3​

​Формат ответа OpenAI Harmony | OpenAI Cookbook​

Цитирование

BibTeX
@online{perplexity2025GptOssOnDay0,
  author = {{Perplexity} and Nandor Licker and Lequn Chen and Vladimir Zaytsev and Kevin Hu and Lauren Kolm and Jesse Dwyer},
  title = {{GPT-OSS on day 0}},
  date = {2025-08-08},
  url = {https://www.perplexity.ai/hub/blog/gpt-oss-on-day-0}
}