GPT-OSS au jour J
Prise en charge dès le jour J de GPT‑OSS sur H200 par l'adaptation de ROSE avec FP8, l'attention avec réceptacle et les optimisations MoE
Perplexity s'engage à offrir les meilleurs modèles d'IA aux personnes curieuses qui exigent des réponses exactes et fiables ainsi que des actions autonomes. OpenAI a récemment annoncé ses modèles à poids ouverts (gpt-oss-20b et gpt-oss-120b). Comme pour de nombreux modèles de pointe, Perplexity figure parmi les premières organisations à évaluer gpt-oss-20b et gpt-oss-120b.
Dans cet article, nous partageons les choix d'infrastructure de notre pile d'inférence interne qui ont rendu possible la prise en charge dès le jour J. Nous nous concentrons sur le service de ces modèles sur des GPU NVIDIA H200, en détaillant les modifications apportées aux noyaux (kernels), les choix de déploiement et les compromis entre vitesse et coût.
GPT-OSS sur Hopper
Les modèles à poids ouverts sont livrés avec une quantification MXFP4, ce qui les aide à tenir dans la mémoire d'un matériel grand public ou à atteindre un débit de pointe sur NVIDIA Blackwell. Cependant, pour l'évaluation initiale, nous voulions les exécuter sur des grappes (clusters) Hopper H200 existantes avec un minimum de modifications du moteur d'inférence. Hopper ne dispose pas de cœurs tensoriels FP4 dédiés, introduits par Blackwell. Par conséquent, nous avons décidé de servir les modèles avec une précision FP8 afin de minimiser le besoin de noyaux personnalisés et de tirer le meilleur parti du matériel disponible.
De manière générale, les grands modèles de langage (LLM) de type transformateur sont structurellement simples :
Incorporation (embedding) d'entrée
Une séquence de couches de transformateurs. Chacune contient un bloc d'attention et un bloc MLP dense ou MoE creux (sparse).
Projection de logits de sortie
Lors de la mise en place d'un nouveau modèle de transformateur, nous cherchons principalement à savoir dans quelle mesure il correspond aux modèles existants afin d'identifier les modifications nécessaires. OpenAI a eu l'amabilité de partager un aperçu de ses modèles à l'avance, ce qui nous a permis d'ajuster notre configuration d'inférence en conséquence. Nous avons constaté que le modèle nécessitait effectivement un bon nombre de petites modifications.
Attention : GQA avec réceptacles d'attention (Attention Sinks)
Chaque tête d'attention possède un paramètre de réceptacle (sink) pré-entraîné qui est pris en compte dans le calcul de Softmax.
Encodage positionnel YaRN, similaire à DeepSeek-V3
Les projections QKV ont des biais, similaires à Qwen 2
La projection de sortie a un biais
MLP : mélange d'experts creux (Sparse Mixture-of-Experts - MoE)
Fonction d'activation SwiGLU, différente de la plupart des modèles à poids ouverts
Softmax après Top-K pour les poids des experts
Les experts ont des biais
Nousendant à un nombre de paramètres compris entre 100B et 200B, nous avons décidé de :
Étendr FlashInfer pour prendre en charge les réceptacles d'attention (attention sinks)
Réutiliser l'implémentation MoE déjà créée pour la famille de modèles DeepSeek-V3
Choisir la mise à l'échelle par blocs FP8 128x128 comme schéma de quantification, en étendant les noyaux DeepGEMM pour prendre en charge un terme de biais.
Moteur d'inférence interne
Nos efforts d'inférence sont soutenus par notre moteur d'inférence interne, ROSE. Nous développons ROSE pour en faire un cadre flexible qui permet de déployer rapidement de nouveaux modèles. De plus, une fois que nous nous engageons à servir un modèle à grande échelle, il offre une plateforme pour optimiser et accroître les performances afin d'atteindre l'état de l'art.
ROSE expose un moteur LLM, qui peut charger un modèle et générer des jetons (tokens) décodés pour celui-ci via plusieurs décodeurs, y compris des décodeurs spéculatifs et MTP. Les modèles eux-mêmes sont composés d'un ensemble personnalisé de couches qui prennent en charge diverses options de configuration pour la quantification et le parallélisme. Sous les couches, il intègre des noyaux Triton et CUDA qui mettent en œuvre et fusionnent efficacement les calculs effectués par les couches individuelles.
ROSE est principalement écrit en Python et s'appuie sur PyTorch pour les définitions de modèles. Bien que Python nous permette d'être flexibles et de nous adapter à de nouveaux modèles, nous migrons la plupart des composants sensibles aux performances, tels que le service et l'ordonnancement de lots, vers Rust.
Pour lancer un nouveau modèle, nous définissons d'abord la hiérarchie du modèle et construisons un convertisseur de poids pour celui-ci. Une fois que tous les poids sont pris en compte, nous définissons une passe avant (forward pass) pour le cas d'utilisation TP=1 le plus simple et nous nous assurons qu'elle fonctionne de bout en bout. Enfin, nous implémentons et testons la prise en charge de diverses formes de parallélisme avant de publier un nouveau conteneur et de déployer le modèle sur une grappe (cluster) pour évaluation. Nous itérons ensuite sur les performances en nous appuyant sur les commentaires des tableaux de bord et de benchmarks plus fins.
ROSE opère sur des jetons numériques, avec peu de connaissances sur les formats de clavardage en dehors des tests d'intégration. En parallèle, nous avons dû examiner l'ajustement de l'infrastructure environnante pour prendre en charge le tokenizer Harmony et mapper correctement les requêtes aux séquences de jetons d'entrée.
Avec le modèle GPT OSS, nous avons constaté qu'aucun changement n'était nécessaire pour nos décodeurs, nos harnais de graphes CUDA ou notre infrastructure environnante, ce qui nous a permis de concentrer nos efforts sur l'ajustement des noyaux sous-tendant le modèle.
Noyaux pour GPT-OSS
Attention avec réceptacle (Sink Attention)
L'attention avec réceptacle introduit un facteur de biais supplémentaire avant Softmax, accumulé avec le produit de Q et K :
attn = softmax(q @ k^T * sm_scale + sink) * VBien qu'une implémentation naïve soit assez triviale, les implémentations d'attention efficaces, telles que FlashInfer, parallélisent le calcul de l'attention à la fois sur des têtes indépendantes et sur la longueur de la séquence KV. De plus, pour des raisons de stabilité numérique, Softmax est calculé en ligne tout en soustrayant l'élément maximal :
softmax(x) = e^x / sum(e^x) = e ^ (x - max(x)) / sum(e ^ (x - max(x))L'implémentation en ligne a suivi un maximum courant m initialisé à -inf et une échelle d à 1. En initialisant le maximum à la valeur de réceptacle de la tête actuelle, nous nous assurons qu'il s'accumulera correctement dans Softmax. Nous avons dû veiller à ce que ce maximum ne soit inclus que dans le premier bloc si l'attention était divisée sur plusieurs blocs le long de la longueur de la séquence.
Nous avons ajusté le modèle de noyau FlashInfer FA2, utilisé à la fois pour le préremplissage (prefill) et le décodage, pour y inclure les paramètres de réceptacle.
MoE
La principale différence entre la couche MoE de différents modèles est généralement le schéma de routage. S'attendant à une variabilité substantielle, ROSE implémente ce noyau en Triton, ce qui nous permet de l'adapter facilement à de nouveaux modèles. Dans le cas de GPT-OSS, nous avons dû ajuster la notation des poids pour effectuer Softmax uniquement sur les experts sélectionnés du Top-K, contrairement à certains modèles de style DeepSeek qui calculent Softmax sur tous les experts. Nous avons constaté qu'il est essentiel pour la précision de calculer les poids des experts en précision bfloat16.
Le défi avec la couche MoE était dû à notre décision de réutiliser les noyaux DeepGEMM existants, qui manquaient de prise en charge pour les termes de biais. Heureusement, au fil du temps, nous nous y sommes intégrés en profondeur, en apportant des modifications pour mieux les connecter à nos noyaux de répartition (dispatch) all-to-all personnalisés. Nous avons ajouté la prise en charge des biais à DeepGEMM en initialisant les registres d'accumulateurs WGMMA aux valeurs de biais chargées depuis la mémoire. Il s'agit d'une opération ponctuelle lors du traitement d'un bloc MN, de sorte que le coût est probablement négligeable et le cache L2 garantit un accès efficace à ces valeurs.
Puisque ces modèles ne bénéficient pas directement du parallélisme de données, nous avons réutilisé les noyaux de répartition et de combinaison propres au TP (tensor parallelism). Les entrées de la répartition sont répliquées sur tous les rangs, de sorte que la répartition sélectionne les jetons pour les experts disponibles localement. La combinaison effectue l'accumulation pondérée via NVLink.
Ajustements des performances
Même si notre objectif était de lancer rapidement les modèles, nous voulions nous assurer que les performances restaient raisonnables. Après avoir vérifié l'exactitude par rapport à une implémentation de référence fournie par OpenAI, nous avons profilé notre implémentation à l'aide du profileur PyTorch par défaut, en surveillant les allocations de blocs et de fils d'exécution (threads) dans les noyaux. La fonctionnalité que nous avons réutilisée a été conçue pour des modèles qui avaient une dimension cachée plus grande de 7168, substantiellement plus grande que les 2880 des modèles GPT-OSS. Nous avons spécialisé les lanceurs de noyaux pour choisir de meilleures dimensions de grille, augmentant considérablement le débit.
Tokénisation et canaux
Le format de clavardage d'Harmony comporte plusieurs concepts importants pour structurer les conversations, le contenu de raisonnement et les appels de fonctions. Dans ce format, chaque message se compose d'un en-tête et d'un contenu :
<|start|>{header}<|message|>{content}<|end|>L'en-tête transporte des métadonnées — plus important encore, le rôle (système, développeur, utilisateur, assistant, outil), le canal et un destinataire tel que to=functions.<function-name> lors de l'appel d'une fonction.
Les canaux (tels que l'analyse, le commentaire et la réponse finale) rendent les sorties du modèle plus transparentes et segmentées. Comme le format impose cette séparation, le modèle peut raisonner de manière transparente (et être inspecté pour le débogage) sans laisser fuiter de chaîne de pensée dans la production. Les balises de destinataire (en-têtes to=) indiquent exactement au moteur d'exécution quel acteur doit recevoir la charge utile suivante — qu'il s'agisse d'une fonction, du modèle lui-même ou de l'utilisateur final.
Notre moteur d'inférence ROSE est agnostique quant au format. Il reçoit un lot de jetons d'entrée et diffuse (stream) en retour des jetons de sortie. Dans notre pile d'inférence, la tâche de formater les entrées en un prompt tokénisé et de parser les résultats du LLM en messages structurés est gérée par le service frontal de l'API JSON dédié. Nous avons intégré Harmony en ajoutant un nouveau formateur/analyseur enfichable à cette interface frontale, permettant au backend de rester inchangé tandis que le front-end gère proprement les règles de format de clavardage, les appels d'outils et le streaming. Cette séparation des préoccupations maintient l'architecture modulaire, permettant une adoption rapide de nouveaux formats et de nouvelles fonctionnalités de réponse avec un minimum de modifications du backend.
Coût et performances
Étant donné la taille relativement petite des modèles GPT-OSS, nous limitons le déploiement d'une réplique à un seul nœud pour éviter les frais généraux de communication inter-nœuds. Notre implémentation prend en charge des combinaisons flexibles de parallélisme d'experts (EP), de parallélisme de données (DP) et de parallélisme de tenseurs (TP). Pour déterminer la configuration de déploiement optimale, nous avons évalué toutes les combinaisons de stratégies de partitionnement (sharding) sur des tailles de lots allant de 1 à 128. Grâce à la désaggrégation du préremplissage et du décodage, nous pouvons discuter séparément du compromis performance-coût pour le préremplissage et le décodage.
Pour les estimations de coûts, nous supposons un tarif de marché nominal pour le H200 de 3,00 $/heure (remarque : il ne s'agit pas de notre prix GPU réel).
Nous avons découvert que le réglage batch_size=1 et DP=1 donne les meilleures performances de préremplissage. Différentes configurations TP offrent ensuite des compromis variables entre la latence du premier jeton et le coût. Les tableaux ci-dessous présentent la latence de préremplissage et le coût par million de jetons d'entrée pour diverses configurations et longueurs d'entrée.
GPT-OSS 120B :
Longueur d'entrée | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0,364 s, 0,037 $ | 2,421 s, 0,062 $ | 7,375 s, 0,094 $ | 23,902 s, 0,156 $ |
EP2 DP1 TP2 | 0,190 s, 0,039 $ | 1,245 s, 0,063 $ | 3,786 s, 0,096 $ | 12,116 s, 0,158 $ |
EP4 DP1 TP4 | 0,165 s, 0,067 $ | 0,900 s, 0,092 $ | 2,449 s, 0,125 $ | 7,165 s, 0,187 $ |
EP8 DP1 TP8 | 0,179 s, 0,145 $ | 0,839 s, 0,171 $ | 2,003 s, 0,204 $ | 5,119 s, 0,267 $ |
Latence de préremplissage et coût par million de jetons d’entrée pour GPT-OSS 120B selon la configuration de parallélisme et la longueur d’entrée.
GPT-OSS 20B :
Longueur d'entrée | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0,239 s, 0,024 $ | 1,610 s, 0,041 $ | 4,895 s, 0,062 $ | 16,037 s, 0,104 $ |
EP2 DP1 TP2 | 0,127 s, 0,026 $ | 0,833 s, 0,042 $ | 2,522 s, 0,064 $ | 8,143 s, 0,106 $ |
EP4 DP1 TP4 | 0,108 s, 0,044 $ | 0,593 s, 0,060 $ | 1,616 s, 0,082 $ | 4,766 s, 0,124 $ |
EP8 DP1 TP8 | 0,116 s, 0,094 $ | 0,547 s, 0,111 $ | 1,310 s, 0,133 $ | 3,365 s, 0,175 $ |
Latence de préremplissage et coût par million de jetons d’entrée pour GPT-OSS 20B selon la configuration de parallélisme et la longueur d’entrée.
Pour le décodage, nous avons découvert que EP4 DP1 TP4 est la meilleure configuration dans la plupart des cas. Les quatre graphiques ci-dessous illustrent le compromis entre la vitesse de décodage et le coût par million de jetons de sortie pour les modèles 120B et 20B à des longueurs de séquence de 8192 et 32768.
Nous avons également envisagé d'utiliser le plus petit modèle de 20B comme modèle provisoire de décodage spéculatif pour le modèle plus grand de 120B. Cependant, étant donné que le nombre de paramètres activés est similaire (3B vs 5B), les accélérations obtenues ont été minimes.
Références
Préremplissage et décodage désagrégés
Accélération de Sonar par la spéculation
Latence réduite et débit accru avec un déploiement DeepSeek multi-nœud
Communication efficace et portable pour le mélange d'experts (MoE)
FlashInfer : moteur d'attention efficace et personnalisable pour le service d'inférence LLM
Modèles de langage en continu efficaces avec réceptacles d'attention (Attention Sinks)
Rapport technique DeepSeek-V3
Format de réponse OpenAI Harmony | Livre de recettes OpenAI
Citation
@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}
}