GPT-OSS no Dia 0
Suporte no dia zero para GPT-OSS no H200 adaptando o ROSE com FP8, atenção sink e otimizações de MoE
A Perplexity está comprometida em disponibilizar os melhores modelos de IA para pessoas curiosas que exigem respostas precisas e confiáveis, além de ações autônomas. A OpenAI anunciou recentemente seus modelos de pesos abertos (gpt-oss-20b e gpt-oss-120b). Como ocorre com muitos modelos líderes, a Perplexity está entre as primeiras organizações a avaliar o gpt-oss-20b e o gpt-oss-120b.
Nesta publicação, compartilhamos as decisões de infraestrutura da nossa pilha de inferência interna que tornaram possível o suporte desde o dia zero. Focamo-nos em servir esses modelos em GPUs NVIDIA H200, detalhando as alterações de kernel, as escolhas de implementação e os equilíbrios entre velocidade e custo.
GPT-OSS no Hopper
Os modelos de pesos abertos são distribuídos usando quantização MXFP4, o que os ajuda a caber na memória de hardware de nível consumidor ou a alcançar o rendimento máximo em NVIDIA Blackwell. No entanto, para a avaliação inicial, queríamos executá-los em clusters Hopper H200 existentes com alterações mínimas no motor de inferência. O Hopper não possui núcleos tensores FP4 dedicados, introduzidos pelo Blackwell. Consequentemente, decidimos servir os modelos com precisão FP8 para minimizar a necessidade de kernels personalizados e aproveitar ao máximo o hardware disponível.
Em um nível elevado, LLMs baseados em transformadores são estruturalmente simples:
Incorporação de entrada
Uma sequência de camadas transformadoras. Cada uma contém um bloco de atenção e um bloco MLP denso ou MoE esparso.
Projeção de logit de saída
Ao implementar um novo modelo transformador, estamos principalmente interessados em aprender até que ponto eles correspondem aos modelos existentes para identificar as alterações necessárias. A OpenAI compartilhou gentilmente uma visão geral de seus modelos com antecedência, permitindo-nos ajustar nossa configuração de inferência adequadamente. Descobrimos que o modelo exigiu um bom número de pequenas alterações.
Atenção: GQA com Sinks de Atenção
Cada cabeça de atenção possui um parâmetro de sink pré-treinado que é fatorado no Softmax
Codificação posicional YaRN, semelhante ao DeepSeek-V3
Projeções QKV possuem vieses, semelhante ao Qwen 2
A projeção de saída possui viés
MLP: Mistura de Especialistas (MoE) Esparsa
Função de ativação SwiGLU, diferente da maioria dos modelos de pesos abertos
Softmax após Top-K para pesos de especialistas
Especialistas possuem vieses
Esperando que o número de parâmetros fique em torno de 100B-200B, decidimos:
Estender o FlashInfer para suportar sinks de atenção
Reutilizar a implementação MoE já construída para a família de modelos DeepSeek-V3
Escolher a escala de bloco FP8 128x128 como o esquema de quantização, estendendo os kernels DeepGEMM para suportar um termo de viés.
Motor de Inferência Interno
Nossos esforços de inferência são apoiados pelo nosso motor de inferência interno, o ROSE. Estamos desenvolvendo o ROSE para ser uma estrutura flexível que permite que novos modelos sejam rapidamente implementados. Além disso, uma vez comprometidos em servir um modelo em escala, ele oferece uma plataforma para otimizar e aumentar o desempenho para alcançar o estado da arte.
O ROSE expõe um motor de LLM, que pode carregar um modelo e gerar tokens decodificados para ele através de múltiplos decodificadores, incluindo decodificadores especulativos e MTP. Os próprios modelos são compostos por um conjunto personalizado de camadas, que suportam várias configurações para quantização e paralelismo. Abaixo das camadas, ele agrupa kernels Triton e CUDA que implementam e fundem com eficiência os cálculos realizados pelas camadas individuais.
O ROSE é construído principalmente em Python e depende do PyTorch para definições de modelo. Embora o Python nos permita ser flexíveis e nos adaptar a novos modelos, estamos migrando a maioria dos componentes sensíveis ao desempenho, como servir e agendamento de lotes, para Rust.
Para implementar um novo modelo, primeiro definimos a hierarquia do modelo e construímos um conversor de pesos para ele. Após contabilizar todos os pesos, definimos uma passagem direta para o caso de uso mais simples de TP=1 e garantimos que funcione de ponta a ponta. Finalmente, implementamos e testamos o suporte para várias formas de paralelismo antes de lançar um novo contêiner e implantar o modelo em um cluster para avaliação. Em seguida, iteramos no desempenho, contando com o feedback de painéis e benchmarks mais detalhados.
O ROSE opera com tokens numéricos, com pouco conhecimento de formatos de Chat fora dos testes de integração. Em paralelo, tivemos que verificar o ajuste da infraestrutura ao redor para suportar o tokenizador Harmony e mapear corretamente as solicitações para sequências de tokens de entrada.
Com o modelo GPT OSS, descobrimos que não foram necessárias alterações em nossos decodificadores, harnesses de grafo CUDA ou infraestrutura circundante, permitindo-nos concentrar nossos esforços no ajuste dos kernels que sustentam o modelo.
Kernels para GPT-OSS
Atenção Sink
A atenção sink introduz um fator de viés extra antes do softmax, acumulado com o produto de Q e K:
attn = softmax(q @ k^T * sm_scale + sink) * VEmbora uma implementação ingênua seja bastante trivial, implementações de atenção eficientes, como o FlashInfer, paralelizam o cálculo da atenção entre cabeças independentes e ao longo do comprimento da sequência KV. Além disso, para estabilidade numérica, o Softmax é calculado online enquanto subtrai o elemento máximo para estabilidade numérica:
softmax(x) = e^x / sum(e^x) = e ^ (x - max(x)) / sum(e ^ (x - max(x))A implementação online rastreou um máximo de execução m inicializado para -inf e uma escala d para 1. Ao inicializar o máximo para o valor sink da cabeça atual, garantiríamos que ele fosse acumulado corretamente no Softmax. Tivemos que tomar cuidado para garantir que esse máximo fosse incluído apenas no primeiro bloco se a atenção fosse dividida em vários blocos ao longo do comprimento da sequência.
Ajustamos o modelo de kernel FA2 do FlashInfer, usado tanto para preenchimento quanto para decodificação, para incluir os parâmetros sink.
MoE
A principal diferença entre a camada MoE de diferentes modelos é geralmente o esquema de roteamento. Esperando variabilidade substancial, o ROSE implementa este kernel em Triton, permitindo-nos adaptá-lo facilmente a novos modelos. No caso do GPT-OSS, tivemos que ajustar a pontuação de peso para realizar o softmax apenas entre os especialistas Top-K selecionados, ao contrário de alguns modelos estilo DeepSeek que calculam o softmax entre todos os especialistas. Descobrimos que é fundamental para a precisão calcular os pesos dos especialistas em precisão bfloat16.
O desafio com a camada MoE deveu-se à nossa decisão de reutilizar os kernels DeepGEMM existentes, que careciam de suporte para termos de viés. Felizmente, com o tempo, integramo-nos profundamente com eles, fazendo alterações para conectá-los melhor com nossos kernels de despacho all-to-all personalizados. Adicionamos suporte de viés ao DeepGEMM inicializando os registradores do acumulador WGMMA com os valores de viés carregados da memória. Isso ocorre uma única vez durante o processamento de um bloco MN, portanto, o custo é provavelmente insignificante e o cache L2 garante acesso eficiente a esses valores.
Como esses modelos não se beneficiam prontamente do paralelismo de dados, reutilizamos os kernels de despacho e combinação apenas de TP. As entradas para o despacho são replicadas entre todos os rankings, portanto, o despacho seleciona os tokens para os especialistas disponíveis localmente. O Combine realiza o acúmulo ponderado através do NVLink.
Ajustes de Desempenho
Mesmo que nosso objetivo fosse implementar os modelos rapidamente, queríamos garantir que o desempenho ainda fosse razoável. Após garantir a correção em relação a uma implementação de referência fornecida pela OpenAI, perfilamos nossa implementação usando o profiler padrão do PyTorch, observando as alocações de bloco e tópico nos kernels. A funcionalidade que reutilizamos foi construída para modelos que tinham uma dimensão oculta maior de 7168, substancialmente maior que os 2880 dos modelos GPT-OSS. Especializamos os lançadores de kernel para escolher melhores dimensões de grade, aumentando significativamente o rendimento.
Tokenização e canais
O formato de Chat do Harmony possui vários conceitos importantes para estruturar conversas, raciocinar conteúdo e chamadas de função. Nesse formato, cada mensagem consiste em um cabeçalho e conteúdo:
<|start|>{header}<|message|>{content}<|end|>O cabeçalho carrega metadados — mais importante, a função (sistema, desenvolvedor, usuário, assistente, ferramenta), o canal e um destinatário, como to=functions.<function-name> ao invocar uma chamada de ferramenta.
Os canais (como análise, comentário e resposta final) tornam as saídas do modelo mais transparentes e segmentadas. Como o formato impõe essa separação, o modelo pode raciocinar de forma transparente (e ser inspecionado para depuração) sem vazar a cadeia de pensamento para a produção. As tags de destinatário (cabeçalhos to=) dizem ao tempo de execução exatamente qual ator deve receber a próxima carga útil — seja uma função, o próprio modelo ou o usuário final.
Nosso motor de inferência ROSE é independente de formato. Ele recebe um lote de tokens de entrada e transmite de volta tokens de saída. Em nossa pilha de inferência, a tarefa de formatar entradas em um prompt tokenizado e analisar os resultados do LLM de volta em mensagens estruturadas é gerenciada pelo serviço de front-end da API JSON dedicado. Integramos o Harmony adicionando um novo formatador/analisador conectável a este front-end, permitindo que o back-end permaneça inalterado enquanto o front-end gerencia limpidamente as regras de formato de chat, chamadas de ferramenta e streaming. Essa separação de preocupações mantém a arquitetura modular, permitindo a adoção rápida de novos formatos e recursos de resposta com alterações mínimas no back-end.
Custo e Desempenho
Dado o tamanho relativamente pequeno dos modelos GPT-OSS, limitamos a implantação de uma réplica a um único nó para evitar a sobrecarga de comunicação entre nós. Nossa implementação suporta combinações flexíveis de paralelismo de especialistas (EP), paralelismo de dados (DP) e paralelismo de tensores (TP). Para determinar a configuração de implantação ideal, analisamos todas as combinações de estratégias de sharding em tamanhos de lote de 1 a 128. Graças à Desagregação de Pré-preenchimento e Decodificação, podemos discutir o equilíbrio entre desempenho e custo separadamente para pré-preenchimento e decodificação.
Para estimativas de custo, assumimos uma taxa de mercado nominal de H200 de $ 3,00/hora (nota: este não é o nosso preço real de GPU).
Descobrimos que definir batch_size=1 e DP=1 produz o melhor desempenho de pré-preenchimento. Diferentes configurações de TP oferecem então diferentes equilíbrios entre a latência do primeiro token e o custo. As tabelas abaixo apresentam a latência de pré-preenchimento e o custo por milhão de tokens de entrada para várias configurações e comprimentos de entrada.
GPT-OSS 120B:
Comprimento de Entrada | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0,364s, $ 0,037 | 2,421s, $ 0,062 | 7,375s, $ 0,094 | 23,902s, $ 0,156 |
EP2 DP1 TP2 | 0,190s, $ 0,039 | 1,245s, $ 0,063 | 3,786s, $ 0,096 | 12,116s, $ 0,158 |
EP4 DP1 TP4 | 0,165s, $ 0,067 | 0,900s, $ 0,092 | 2,449s, $ 0,125 | 7,165s, $ 0,187 |
EP8 DP1 TP8 | 0,179s, $ 0,145 | 0,839s, $ 0,171 | 2,003s, $ 0,204 | 5,119s, $ 0,267 |
Latência de pré-processamento do GPT-OSS 120B e custo por milhão de tokens de entrada por configuração de paralelismo e comprimento de entrada.
GPT-OSS 20B:
Comprimento de Entrada | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0,239s, $ 0,024 | 1,610s, $ 0,041 | 4,895s, $ 0,062 | 16,037s, $ 0,104 |
EP2 DP1 TP2 | 0,127s, $ 0,026 | 0,833s, $ 0,042 | 2,522s, $ 0,064 | 8,143s, $ 0,106 |
EP4 DP1 TP4 | 0,108s, $ 0,044 | 0,593s, $ 0,060 | 1,616s, $ 0,082 | 4,766s, $ 0,124 |
EP8 DP1 TP8 | 0,116s, $ 0,094 | 0,547s, $ 0,111 | 1,310s, $ 0,133 | 3,365s, $ 0,175 |
Latência de pré-processamento do GPT-OSS 20B e custo por milhão de tokens de entrada por configuração de paralelismo e comprimento de entrada.
Para a decodificação, descobrimos que o EP4 DP1 TP4 é a melhor configuração para a maioria dos casos. Os quatro gráficos abaixo ilustram o equilíbrio entre a velocidade de decodificação e o custo por milhão de tokens de saída para os modelos de 120B e 20B em comprimentos de sequência de 8192 e 32768.
Também consideramos usar o modelo menor de 20B como um modelo de rascunho de decodificação especulativa para o modelo maior de 120B. No entanto, como o número de parâmetros ativados é semelhante (3B vs. 5B), os ganhos de velocidade resultantes foram marginais.
Referências
Pré-preenchimento e Decodificação Desagregados
Acelerando o Sonar por meio de Especulação
Menor Latência e Maior Rendimento com Implantação Multi-nó DeepSeek
Comunicação Eficiente e Portátil de Mistura de Especialistas
FlashInfer: Motor de Atenção Eficiente e Personalizável para Inferência de LLM
Modelos de Linguagem de Streaming Eficientes com Sinks de Atenção
Formato de Resposta OpenAI Harmony | Livro de Receitas OpenAI
Citação
@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}
}