Ultraman a révélé dans un podcast pourquoi OpenAI oriente ses ressources vers Codex plutôt que Sora. La génération vidéo de Sora exige une puissance de calcul continue importante, et le temps GPU occupé par une seule tâche est difficile à réutiliser ; en revanche, Codex répartit la puissance de calcul sur plusieurs étapes intercalées grâce à des mécanismes tels que le KV cache, le continuous batching et l'appel d'outils, permettant à un même GPU de prendre en charge davantage de flux de travail parallèles. La capacité à réutiliser le temps GPU commence à déterminer la vitesse d'expansion des produits d'IA.Auteur et source de l'article : Leifeng.com
Pourquoi Sora perd-il contre Codex ?
Le 23 août, Otomo a mentionné spontanément Sora lorsqu'il a abordé les compromis en matière de ressources au sein d'OpenAI sur le podcast de David Senra.
Il l'a dit directement : Sora est un bon produit, et continuer à le développer pourrait devenir un bon business, mais il consomme trop de ressources informatiques ; pendant ce temps, Codex avait la priorité, donc les ressources informatiques et l'attention de l'équipe ont commencé à se concentrer sur Codex.
Mais il est intéressant de noter que Codex ne économise pas non plus le GPU. Pour générer une vidéo, Sora doit faire passer un latent temporel et spatial massif à travers plusieurs itérations de calculs Transformer ; tandis que Codex, en recevant la commande « corrigez ce bogue », peut exécuter en arrière-plan de nombreuses itérations d'inférence, lire le code, appeler des outils, exécuter des tests, puis revenir avec de nouveaux journaux et du contexte pour continuer l'inférence.
L’un concentre la puissance de calcul sur une seule génération vidéo, tandis que l’autre répartit la puissance de calcul sur un flux de travail Agent pouvant durer plusieurs dizaines de minutes voire plus. C’est donc à l’intérieur des centres de données que la véritable différence entre Sora et Codex commence à se dessiner.
Pourquoi, avec le même lot de GPU, le calcul pour la génération vidéo est-il plus difficile à répartir, tandis que l’agent de codage peut réinjecter la puissance de calcul dans davantage de tâches simultanées grâce au KV cache, au batching continu, à l’ordonnancement prefill / decode et à l’attente des outils ?
En réalité, Sora n'a pas perdu en raison de la consommation absolue de puissance de calcul, mais en raison de son architecture de charge de travail : la puissance de calcul de Sora est continue et exclusive, tandis que celle de Codex est fragmentée et réutilisable. C'est précisément cette différence de mécanisme d'ordonnancement qui a créé l'écart de vitesse d'expansion entre les deux.
En regardant plus loin sur cette ligne, on peut voir que les ressources perdues par Sora pourraient cacher un choix concernant la manière dont le temps GPU devrait être utilisé.
Pourquoi Sora est-il difficile à décomposer ?
Le coût de Sora pourrait commencer à augmenter dès l'entrée de la vidéo dans le modèle. Il compresse d'abord la vidéo originale dans l'espace latent, puis la découpe en patches spacetime, permettant au Transformer de calculer sur ces patches.
Les tokens texte s'étendent principalement dans la direction séquentielle, tandis que les patchs vidéo sont répartis simultanément sur le temps, la hauteur et la largeur, ce qui fait que la vidéo est naturellement une entité tridimensionnelle au sein du modèle.
From a high-level perspective, the number of visual tokens can be understood as N_video ≈ T × H × W, where T, H and W have already been compressed and patched, but the three-dimensional multiplicative relationship still holds.
Allonger la durée de la vidéo augmente les patchs dans la direction temporelle, tandis que l'augmentation de la résolution de l'image élargit les patchs spatiaux. Autrement dit, la durée de la vidéo et la taille spatiale n'augmentent pas indépendamment les coûts ; elles agissent ensemble pour étendre la grille latente.
Après avoir été introduite dans le Transformer, cette grille doit faire face à une deuxième couche de calcul apportée par le diffusion. Sora commence à partir d’un latent bruité, met à jour la représentation vidéo à chaque itération en fonction de l’état actuel, puis envoie le nouveau latent à l’itération suivante.
La charge de calcul pour une seule vidéo peut être approximativement comprise comme C_video ≈ D × C_transformer(N_video), où D est le nombre d'itérations d'échantillonnage. Plus le latent vidéo est grand, plus chaque itération est lourde ; en augmentant le nombre d'itérations d'échantillonnage, la même vidéo doit passer plusieurs fois à travers le réseau.
On peut voir ici la différence clé entre la diffusion vidéo et les LLM. Lorsqu'un modèle linguistique génère des tokens suivants, les clés et valeurs précédentes peuvent être conservées dans le cache KV, et le modèle n'a pas besoin de reconstruire à chaque étape l'ensemble de l'historique.
À chaque mise à jour complète de la diffusion vidéo, l'état latent principal a changé ; la prochaine itération fait face à un nouvel état spatio-temporel, ce qui nécessite de continuer d'effectuer un grand nombre de calculs sur le sujet vidéo.
Ainsi, le coût de Sora est difficile à réduire significativement en « réutilisant l'historique ». Il ressemble davantage à un plan visuel subissant plusieurs cycles de traitement, chaque cycle devant traiter une image entière déjà modifiée. Plus la vidéo est longue, de haute résolution et échantillonnée davantage, plus ce chemin de génération devient lourd.
Precisément parce que chaque tâche est suffisamment lourde, l'utilisation du GPU de Sora peut être très élevée. Les calculs de matrices de grande taille permettent aux Tensor Cores de rester occupés pendant de longues périodes, et les graphiques de surveillance montrent que le GPU est presque constamment actif.
Un taux d'utilisation élevé indique simplement que le processeur est en continu en fonctionnement, mais ne signifie pas qu'il a accompli beaucoup de tâches par unité de temps. Si une vidéo occupe un ensemble de GPU pendant une longue période, alors même si l'utilisation semble excellente, la consommation en GPU-seconds par requête reste élevée.
Le service vidéo est toujours ralenti par les différences de forme. Des durées, résolutions et rapports d'aspect différents génèrent des formes de tenseur variées. Pour améliorer l'efficacité du batch, le serveur regroupe les demandes de tailles similaires dans le même bucket. Attendre un peu plus longtemps permet de constituer des batchs plus denses, mais augmente la latence d'attente ; exécuter immédiatement réduit le délai d'attente, mais les batchs risquent de ne pas être pleins.
Ainsi, la majeure partie du coût de calcul de Sora est déjà intégrée dans le chemin de génération propre à chaque vidéo. Le nombre d'échantillonnages peut être réduit, les latents peuvent être davantage compressés, le modèle peut être distillé, et les noyaux peuvent encore être optimisés, mais ce que le scheduler peut modifier, c'est principalement « comment ordonner ces tâches intensives » ; il est difficile de changer le fait qu'une vidéo elle-même nécessite une grande quantité de calculs continus.
C’est aussi la clé pour comprendre Codex. Codex est tout aussi coûteux, mais il ne répartit pas l’ensemble des coûts sur un seul bloc de calcul continu ; au lieu de cela, il divise la tâche en plusieurs étapes pouvant être suspendues, reprises et recombinées.
Pourquoi Codex devient-il de plus en plus cher ?
L'utilisateur donne à Codex la tâche de « corriger ce bug » ; la tâche ne se termine pas par un seul appel au modèle. L'agent peut d'abord consulter le dépôt, demander au modèle d'évaluer la prochaine étape, puis exécuter un shell ; après avoir obtenu une erreur, il intègre les journaux au contexte et relance le modèle ; ensuite, il modifie le code, exécute les tests, puis continue à raisonner en fonction des nouveaux résultats.
Donc une tâche Codex est plus proche de l'accumulation de plusieurs tours Prefill + Decode + Tool, où, à chaque tour de appel d'outil, le contexte vu par le modèle au tour suivant est souvent plus dense que le tour précédent.
Au début de la tâche, le modèle ne dispose que de la demande de l'utilisateur et d'un petit code. Après un certain temps d'exécution, davantage de fichiers, de diff, de sorties terminal, de journaux de tests et de résultats d'outils sont intégrés au prompt.
L'utilisateur ne voit peut-être que quelques centaines de caractères dans la notice finale, mais le contenu traité par le GPU a pu devenir extrêmement volumineux. La pression sur la consommation de jetons Agent se cache dans cette trajectoire de travail en constante augmentation.
Si chaque inference traite à nouveau l'ensemble de l'historique, les tâches longues seront rapidement ralenties par des pré-remplissages répétés ; le cache de prompt est donc essentiel pour Codex.
Supposons qu'un Agent possède déjà 100K jetons de contexte, et que l'exécution de l'outil n'ajoute que 3K jetons de journal. Si le préfixe stable initial peut être mis en cache, les calculs supplémentaires de cette boucle se concentreront principalement sur cette dernière partie ; dès qu'un changement dans la partie initiale du prompt provoque un cache miss, le système pourrait devoir faire face à nouveau à un prefill très coûteux.
Un changement important se produit ici : le nombre de tokens logiques ne peut plus représenter directement le coût réel du GPU. Les deux requêtes affichent 100K tokens d'entrée, mais l'une contient principalement du contenu déjà mis en cache, tandis que l'autre nécessite un recalcul ; leur impact sur le GPU est donc très différent. La charge de l'Agent dépend donc de la vitesse d'augmentation du contexte, du taux de hit dans le cache, ainsi que du nombre de fois qu'une tâche est répétée dans le modèle.
Après avoir entré une inference unique, le prefill et le decode présentent des exigences matérielles différentes. Le prefill traite de nombreux tokens d'entrée en une seule fois, avec des matrices de grande taille, ce qui facilite la création d'une charge de travail intensive en calcul ; le decode génère seulement quelques tokens par séquence à chaque itération, mais nécessite un accès répété aux poids du modèle et au KV cache, ce qui le rend donc plus dépendant de la bande passante HBM et de la capacité de concurrence.
Cela signifie que décoder une seule séquence isolément serait très inefficace. Les poids du modèle restent aussi volumineux, et chaque token généré nécessite un calcul complet en avant. Le serveur ne peut faire progresser plusieurs demandes simultanément en regroupant plusieurs séquences dans un seul batch en avant.
Cependant, la taille du batch ne peut pas continuer à augmenter en raison des limites du cache KV. Plus le contexte de chaque séquence est long, plus il occupe de HBM. Après augmentation du nombre d'agents, le GPU peut encore disposer d'une capacité de calcul résiduelle, mais la mémoire vidéo ne peut plus contenir davantage d'états actifs.
Les conceptions de type PagedAttention gèrent le cache KV par pages, réduisant la fragmentation de la mémoire vidéo, ce qui revient essentiellement à augmenter le nombre de séquences actives qu'une GPU peut héberger simultanément.
L'appel d'outils permet de répartir davantage la charge sur Codex. Lorsque l'Agent effectue des tests, compile du code ou attend une opération E/S, le GPU n'a plus besoin de continuer à lui fournir des ressources ; le CPU, les conteneurs et le système de fichiers prennent le relais. Une fois les résultats reçus, cet Agent entre dans une nouvelle boucle d'inférence.
Un Agent qui s'exécute pendant 60 minutes ne signifie pas qu'il occupe continuellement le GPU pendant 60 minutes. Son temps de tâche est divisé en calcul du modèle et exécution externe, ce qui offre au planificateur un espace que Sora ne peut pas facilement fournir : lorsque qu'un Agent exécute un outil, le GPU peut immédiatement servir une autre séquence.
Bien sûr, cela créera également de nouveaux problèmes de mémoire vidéo. L'agent chargé d'attendre doit-il conserver le cache KV ? Le conserver permet une reprise plus rapide, mais occupe durablement la HBM ; l'évincer libère de l'espace, mais coûte cher à restaurer lorsque la tâche revient. Plus il y a d'agents, plus ce compromis ressemble à la gestion par un système d'exploitation de nombreux processus en sommeil et en réveil.
À ce stade, la différence entre Codex et Sora ne réside plus dans « qui est le plus lourd », mais dans le fait que les coûts ont été décomposés. Les ressources de calcul de Sora sont concentrées sur un chemin de génération continu, tandis que celles de Codex sont réparties sur plusieurs étapes. C’est précisément en étant décomposé que Codex peut passer à une optimisation de niveau supérieur : permettre au scheduler de déterminer comment ces étapes partagent un même ensemble de GPU.
L'efficacité de Codex provient de la réorganisation des calculs
Lors de l'exécution en ligne de grands modèles, les poids doivent généralement rester longtemps en mémoire GPU, tout en maintenant l'état de tensor parallel, de communication entre nœuds et de cache. Ainsi, la concurrence pour les ressources entre Sora et Codex se produit principalement au niveau du fleet : une partie des GPU reste en permanence dans le pool de service vidéo, tandis qu'une autre partie reste en permanence dans le pool LLM, et le système de capacité supérieur décide ensuite où étendre ou réduire les ressources.
Les choses vraiment complexes se produisent à l'intérieur du pool Codex. Supposons qu'il existe simultanément 200 séquences d'agents dans le système, certaines en cours de décodage, d'autres en attente d'outils, et des dizaines qui viennent de revenir de l'environnement outil et doivent traiter de nouveaux contextes longs. L'ordonnanceur fait face à des contraintes qui ne se limitent pas aux FLOPs, mais incluent également la capacité HBM, la bande passante mémoire, la résidence du cache KV et le budget de latence.
Continuous batching résout d'abord le problème d'utilisation du décodage. Le batch statique traditionnel lie un ensemble de demandes ensemble ; une fois les courtes séquences terminées, les demandes plus longues continuent d'occuper le batch.
Le batch continu effectue un remplacement dynamique au niveau de l'itération des tokens : dès qu'une séquence est terminée, elle est supprimée, et une nouvelle requête est immédiatement ajoutée. Plus le batch est volumineux, plus un cycle de calcul du modèle peut faire avancer de séquences, ce qui permet de répartir plus efficacement les coûts d'accès aux poids du modèle et de bande passante mémoire.
Mais on rencontrera rapidement un mur de mémoire vidéo. Les caches KV de nombreux agents longs occuperont en continu la HBM ; une GPU pourrait ne pas avoir encore pleinement utilisé ses Tensor Cores, mais la mémoire vidéo serait déjà saturée et ne pourrait plus accueillir davantage de séquences. À ce stade, augmenter la puissance de calcul n’a plus de sens ; la capacité de cache et la gestion de la mémoire vidéo sont les véritables limites de la concurrence.
Un autre conflit existe entre le prefill et le decode. Supposons que plusieurs dizaines de séquences soient en cours de decode stable, lorsqu’un Agent revient avec un nouveau contexte de 100K tokens nécessitant un prefill volumineux. Si ce prefill occupe une fenêtre d’exécution prolongée, le TPOT des requêtes voisines se dégradera nettement.
Le chunked prefill divise les entrées longues en plusieurs petits blocs pour permettre l'exécution alternée du prefill et du decode ; une approche encore plus avancée consiste à séparer le prefill et le decode sur différents pools de GPU.
La raison en est que les deux phases présentent des goulots d'étranglement matériels différents : le prefill est plus orienté débit de calcul, tandis que le decode dépend davantage de la bande passante HBM, du cache KV et d'une latence stable par token. En les séparant, il est possible de configurer les ressources selon les besoins spécifiques de chaque phase.
Cela montre que le cœur d'Agent serving dépasse largement « écrire un kernel de modèle plus rapide ». De nombreuses améliorations de capacité proviennent de la réorganisation du moment et de l'endroit où les tâches s'exécutent, des états qui méritent d'être conservés en mémoire GPU, et de la sélection des éléments à inclure dans le batch actuel.
Ainsi, l'utilisation du GPU n'est plus suffisante ici. L'équipe capacité doit surveiller simultanément les GPU-seconds par tâche, le TTFT (délai du premier token, qui détermine la réactivité perçue par l'utilisateur), le TPOT (temps de génération par token, qui détermine la vitesse à laquelle le modèle « parle »), la latence d'attente, le taux de hit du cache de préfixe, l'occupation du cache KV et le SLO goodput (débit effectif, qui représente la puissance de calcul réellement vendable).
Ces indicateurs répondent ensemble à une question : combien de tâches efficaces une GPU peut-elle maintenir pendant une heure, sous une latence acceptable par l'utilisateur.
La flexibilité de Codex se manifeste ici. Le préfixe stable réduit les pré-remplissages répétés, le décodage permet un batch continu, le cache KV peut être paginé et évacué, et l'agent peut libérer le GPU pendant qu'il attend un outil. Sa charge de travail est très fragmentée, mais ces fragments peuvent être réorganisés par l'ordonnanceur.
Cela pousse naturellement la question au niveau des ressources : si les mêmes GPU peuvent servir de manière intercalée davantage d'agents à long terme, alors le temps de travail réellement supporté par une heure de GPU pourrait dépasser une heure.
Pourquoi Codex absorbe plus facilement les nouveaux hashrates
Supposons qu’un agent Codex mette 60 minutes pour exécuter une tâche de bout en bout, mais que seule une partie de ce temps soit réellement consacrée au prefill et au decode du modèle ; le reste du temps est utilisé pour la compilation, les tests, la lecture/écriture de fichiers ou l’attente d’outils. Le ratio exact varie selon la tâche, mais la structure est essentielle : le temps wall-clock de l’agent ne correspond pas à un rapport 1:1 avec le temps de calcul GPU.
Si de nombreux agents coexistent dans le système, ils n'ont pas tous besoin du GPU en même temps, à la même seconde. Certains sont en prefill, d'autres en decode, certains exécutent des tests, et d'autres attendent le système de fichiers. Tant que le scheduler peut intercaler ces phases, un nombre limité de GPU peut maintenir bien plus de flux de travail actifs que le nombre de GPU disponible.
On peut approximativement comprendre cette relation comme suit : les Agent-hours dépendent des GPU-hours, du taux d'occupation du modèle d'inférence et de l'efficacité de la planification. Plus le temps d'exécution des outils est long, plus les batchs sont volumineux et plus le taux de命中 du cache est élevé, plus une heure de GPU a la possibilité de soutenir une durée plus longue de travail Agent en temps réel.
Cela modifiera directement la signification de l'ajout de nouvelles GPU. Ajouter un lot de GPU à Codex n'apporte pas seulement une accélération des tâches individuelles, mais permet également au système de maintenir simultanément plus d'agents. Un ingénieur peut lancer plusieurs tâches en parallèle : une pour modifier le backend, une pour compléter les tests, une pour gérer un autre dépôt — tant que ces tâches n'ont pas de dépendances fortes entre elles, le temps de travail de la machine peut augmenter en parallèle.
La courbe de capacité de Sora est plus directe. Le temps wall-clock important d'une vidéo progresse directement sur le GPU via le diffusion, ce qui lie plus étroitement la tâche unique à l'utilisation du GPU. L'ajout de GPU peut augmenter directement le débit vidéo, mais il est difficile de créer une grande différence entre l'heure GPU et le temps de calcul vidéo.
Une tâche logicielle de Codex se déplace entre le GPU, le CPU, les conteneurs, le système de fichiers et l'environnement d'outils. Le GPU gère l'inférence du modèle, tandis que les autres systèmes assurent l'exécution ; plusieurs agents partagent de manière intercalée la capacité d'inférence via un planificateur. Ainsi, le GPU passe d'un simple appareil de génération à une ressource rare de « réflexion » au sein de l'ensemble du système d'agents.
C’est pourquoi Codex, bien qu’il puisse également consommer une grande quantité de compute, obtient plus facilement de nouveaux compute. OpenAI doit considérer non seulement le coût d’inférence unique, mais aussi la capacité à convertir rapidement la capacité supplémentaire en une charge de travail parallèle accrue.
Lorsqu’un lot de GPU peut prendre en charge davantage d’agents à long terme, et que ces agents peuvent continuellement recevoir de nouvelles tâches logicielles, les ressources ont tendance à continuer de s’orienter dans cette direction.
La signification technique de la déclaration d'Altman devient ainsi claire. La puissance de calcul de Sora est verrouillée dans un seul chemin de génération, tandis que la puissance de calcul de Codex est répartie en plusieurs étapes intercalables. Les deux coûteuses, mais les courbes de retour sur les ressources diffèrent.
Influencé par la forme du workload
Sora et Codex : instructions de transfert de ressources, les produits IA commencent à avoir un nouvel élément qui affecte directement la vitesse d'expansion : l'architecture de charge de travail.
En utilisant des GPU coûteux, une catégorie de tâches bloque une grande puissance de calcul sur un seul chemin de génération, tandis qu'une autre catégorie peut, grâce au cache, au batching, à l'exécution d'outils et à l'ordonnancement, faire interagir la même capacité d'inférence avec plusieurs flux de travail ; leurs courbes de ressources se séparent naturellement.
Ainsi, certaines questions qui semblent à première vue très fondamentales deviendront de plus en plus proches des problèmes produits : où placer le cache KV, comment découper le prefill, quelle épaisseur de batch decode peut être intégrée, et si les agents en attente doivent évacuer le cache — ces choix détermineront finalement combien de tâches un ensemble de GPU peut gérer simultanément.
La différence entre Sora et Codex ne se limite pas à celle entre vidéo et code.
Ils se disputent la même heure de GPU, et il faut voir combien de travail elle peut supporter.
