Maison > Article > Périphériques technologiques > Comme TensorFlow, le monopole CUDA de NVIDIA sera-t-il brisé ?
Au cours des dix dernières années, le paysage du développement de logiciels d'apprentissage automatique a subi des changements importants. De nombreux frameworks ont vu le jour, mais la plupart s'appuient fortement sur le CUDA de NVIDIA et obtiennent les meilleures performances sur les GPU de NVIDIA. Cependant, avec l’arrivée de PyTorch 2.0 et d’OpenAI Triton, la domination de Nvidia dans ce domaine est en train de se briser.
Au début, Google disposait de grands avantages en matière d'architecture, de formation et d'optimisation des modèles d'apprentissage automatique, mais il est désormais difficile d'utiliser pleinement ces avantages. Du côté du matériel, il sera difficile pour les autres fabricants de matériel d'IA d'affaiblir la domination de Nvidia. Jusqu'à l'émergence de PyTorch 2.0 et d'OpenAI Triton, la pile logicielle par défaut pour les modèles d'apprentissage automatique ne sera plus le CUDA fermé de Nvidia.
Une concurrence similaire se produit dans les frameworks d'apprentissage automatique. Il y a quelques années, l'écosystème du framework était assez fragmenté, mais TensorFlow était le leader. En apparence, Google semble être fermement ancré dans l'industrie des cadres d'apprentissage automatique. Ils ont conçu l'accélérateur TPU spécifique aux applications d'IA avec TensorFlow, obtenant ainsi l'avantage du premier arrivé.
Cependant, il semble maintenant que PyTorch a gagné et que Google n'a pas réussi à convertir son avantage de premier arrivé en domination dans l'industrie émergente du ML. Google semble être quelque peu isolé dans la communauté de l'apprentissage automatique ces jours-ci, car il n'utilise pas PyTorch ni les GPU, mais utilise plutôt sa propre pile logicielle et son propre matériel. En fait, Google a développé un deuxième framework d'apprentissage automatique - JAX, qui concurrence directement TensorFlow. Il s'agit d'un "comportement Google" typique.
Certains pensent que la domination de Google dans la recherche et le traitement du langage naturel diminue en raison de la montée en puissance des grands modèles de langage, en particulier les grands modèles de langage d'OpenAI et divers modèles de langage construits à l'aide de l'API OpenAI. Peut-être que ce point de vue est trop pessimiste, après tout, l'infrastructure de la plupart des modèles actuels est toujours le transformateur développé par Google.
Alors, pourquoi PyTorch est-il un grand gagnant ? La raison principale est que PyTorch a une flexibilité et une convivialité plus élevées que TensorFlow. La principale différence entre PyTorch et TensorFlow réside dans l'utilisation du mode Eager au lieu du mode Graph.
Le mode Eager peut être considéré comme une méthode d'exécution de script standard, pas différente du code Python ordinaire. Cela facilite le débogage et la compréhension du code, car les utilisateurs peuvent voir les résultats des opérations intermédiaires et le fonctionnement du modèle.
En revanche, le mode Graphique est divisé en deux étapes. La première étape représente le graphe de calcul sur lequel les opérations doivent être effectuées, où les nœuds représentent des opérations ou des variables, et les bords entre les nœuds représentent le flux de données entre eux. La deuxième étape est une exécution différée d'une version optimisée du graphe informatique.
Cette approche en deux étapes rend la compréhension et le débogage du code plus difficiles car l'utilisateur ne peut pas voir ce qui se passe jusqu'à la fin de l'exécution du graphique. Ceci est similaire aux langages « interprétés » par rapport aux langages « compilés » tels que Python et C++, le débogage de Python est plus facile car il s’agit d’un langage interprété.
Bien que TensorFlow utilise désormais également le mode Eager par défaut, la communauté des chercheurs et la plupart des grandes entreprises technologiques choisissent d'utiliser PyTorch.
Si la formation du modèle d'apprentissage automatique est simplifiée à sa forme la plus simple, il existe deux facteurs principaux qui affectent la formation du modèle d'apprentissage automatique :
Auparavant, le principal facteur affectant le temps de formation à l'apprentissage automatique était le temps de calcul, en attendant que le système effectue une multiplication matricielle. À mesure que les GPU Nvidia continuent d’évoluer, ce ne sera bientôt plus un problème majeur.
NVIDIA a exploité la loi de Moore pour améliorer les FLOPS de plusieurs ordres de grandeur, mais les principaux changements architecturaux concernaient les cœurs tenseurs et les formats à virgule flottante de moindre précision. En comparaison, peu de choses ont changé en matière de stockage.
En 2018, le modèle le plus avancé était BERT et NVIDIA V100 était le GPU le plus avancé. À cette époque, la multiplication matricielle n'était plus le principal facteur d'amélioration des performances du modèle. Par la suite, les modèles ont augmenté de 3 à 4 ordres de grandeur en nombre de paramètres, tandis que les GPU les plus rapides ont augmenté d'un ordre de grandeur en FLOPS.
Même en 2018, les charges de travail purement liées au calcul représentaient 99,8 % des FLOPS mais seulement 61 % du temps d'exécution. Par rapport à la multiplication matricielle, la normalisation et les opérations ponctuelles n'utilisent que 1/250 et 1/700 des FLOPS de la multiplication matricielle, mais elles consomment près de 40 % du temps d'exécution du modèle.
Alors que la taille des modèles continue de monter en flèche, les modèles en grand langage (LLM) nécessitent plus de 100 Go de mémoire uniquement pour les poids des modèles. Les réseaux de recommandation de produits déployés par Baidu et Meta nécessitent des dizaines de téraoctets de mémoire pour stocker leurs énormes tables d'intégration. La plupart du temps dans la formation/inférence de grands modèles n'est pas consacré à calculer des multiplications matricielles, mais à attendre que les données soient transférées. De toute évidence, la question est de savoir pourquoi les architectes ne rapprochent pas davantage de mémoire du calcul, et la réponse est évidente : le coût.
Le pool de mémoire partagée le plus proche est généralement la SRAM sur la même puce. Certains ASIC d'apprentissage automatique tentent d'exploiter d'énormes pools SRAM pour conserver les poids des modèles. Mais même la puce à l'échelle d'une tranche d'environ 5 000 000 $ de Cerebras ne dispose que de 40 Go de SRAM. La capacité de mémoire est insuffisante pour accueillir les poids d'un modèle paramétrique de 100 B+.
Nvidia a conçu les puces avec beaucoup moins de mémoire sur puce : l'A100 a 40 Mo et le H100 50 Mo. Une SRAM de 1 Go sur une puce TSMC 5 nm nécessite environ 200 millimètres carrés de silicium, et la mise en œuvre de la logique/structure de contrôle associée nécessiterait plus de 400 millimètres carrés de silicium. Étant donné que le GPU A100 coûte plus de 10 000 dollars et que le H100 est plus proche de 20 000 dollars, cette approche n'est pas économiquement réalisable. Même en ignorant la marge bénéficiaire d'environ 75 % de Nvidia sur les GPU des centres de données, la mémoire SRAM coûte toujours environ 100 $/Go pour un produit entièrement produit.
De plus, le coût de la mémoire SRAM sur puce ne diminuera pas beaucoup à mesure que la technologie traditionnelle du processus de la loi de Moore diminue. La même mémoire de 1 Go utilise la technologie de processus 3 nm de nouvelle génération de TSMC, mais le coût est plus élevé. Même si la SRAM 3D contribuera à réduire les coûts de la SRAM dans une certaine mesure, cela n’est que temporaire.
La prochaine étape dans la hiérarchie de la mémoire est la mémoire DRAM hors puce étroitement couplée. La DRAM a une latence d'un ordre de grandeur supérieure à celle de la SRAM (~ 100 ns contre 10 ns), mais elle est également beaucoup moins chère. La DRAM suit la loi de Moore depuis des décennies. Lorsque Gordon Moore a inventé le terme, l'activité principale d'Intel était la DRAM. Ses prédictions concernant la densité et le coût des transistors étaient généralement vraies pour les DRAM avant 2009. Mais les coûts des DRAM se sont à peine améliorés depuis 2012.
Cependant, la demande de mémoire des gens n’a fait qu’augmenter. La DRAM représente désormais 50 % du coût total des serveurs, formant progressivement ce qu'on appelle le « mur de mémoire ». En comparant le GPU P100 2016 de Nvidia au dernier GPU H100, nous constatons que la capacité de mémoire a augmenté jusqu'à 5 fois (16 Go → 80 Go) et les performances du FP16 ont augmenté jusqu'à 46 fois (21,2 TFLOPS → 989,5 TFLOPS).
Bien que la capacité de la mémoire soit un goulot d'étranglement important, un autre goulot d'étranglement : la bande passante mémoire est également très critique. Les augmentations de bande passante mémoire sont souvent obtenues grâce au parallélisme. Alors que la DRAM standard ne coûte aujourd'hui que quelques dollars/Go, pour obtenir la bande passante massive nécessaire à l'apprentissage automatique, Nvidia utilise la mémoire HBM, un dispositif composé de couches DRAM empilées en 3D qui nécessite un package plus coûteux. HBM coûte environ 10 à 20 $/Go, y compris les coûts d'emballage et de volume.
Le problème des contraintes de coût sur la bande passante et la capacité de la mémoire est particulièrement évident dans le GPU A100 de Nvidia. Sans optimisation approfondie, l'A100 ne peut avoir qu'une très faible utilisation des FLOPS.
Même si les chercheurs ont fait beaucoup d'optimisation, le taux d'utilisation des FLOPS des grands modèles de langage ne peut atteindre qu'environ 60 %. Une grande partie du temps est consacrée à attendre les données d'un autre calcul/mémoire, ou à recalculer les résultats en temps opportun pour réduire les goulots d'étranglement de la mémoire.
De A100 à H100, les FLOPS augmentent jusqu'à plus de 6 fois, mais la bande passante mémoire n'augmente qu'à 1,65 fois. Cela a conduit de nombreuses personnes à craindre que l'utilisation du H100 ne soit faible. L'A100 a nécessité de nombreuses astuces pour contourner le mur de mémoire, et le H100 nécessite encore plus d'astuces pour y parvenir.
H100 apporte la mémoire partagée distribuée et la multidiffusion L2 à l'architecture Hopper. L'idée est de permettre aux données d'un SM d'être écrites directement dans la SRAM (mémoire partagée/Cache L1) d'un autre SM. Cela augmente efficacement la taille du cache et réduit la bande passante requise pour les lectures/écritures DRAM. Les architectures futures réduiront le nombre d’opérations envoyées en mémoire afin de minimiser l’impact des murs de mémoire. Il convient de noter que les modèles plus grands ont tendance à atteindre une utilisation plus élevée, car FLOPS doit évoluer comme le cube du nombre de paramètres, tandis que les exigences en matière de bande passante et de capacité mémoire ont tendance à évoluer comme le quadratique.
Si tout le temps est consacré aux transferts de mémoire (c'est-à-dire à une bande passante mémoire limitée), alors augmenter les FLOPS du GPU n'aidera pas. D'un autre côté, si tout votre temps est consacré à l'exécution de gros matmuls, alors même réécrire la logique du modèle en C++ pour réduire les frais généraux ne vous aidera pas.
La raison pour laquelle PyTorch peut surpasser TensorFlow est que le mode Eager améliore la flexibilité et la convivialité, mais le passage au mode Eager n'est pas le seul avantage. Lors de l'exécution en mode impatient, chaque opération est lue dans la mémoire, calculée, puis envoyée en mémoire avant de traiter l'opération suivante. Sans optimisation approfondie, cela peut augmenter considérablement les besoins en bande passante mémoire.
Donc, pour les modèles exécutés en mode Eager, l'une des principales méthodes d'optimisation est la fusion d'opérateurs. Les opérations de fusion calculent plusieurs fonctions en un seul passage pour minimiser les lectures/écritures en mémoire, plutôt que d'écrire chaque résultat intermédiaire en mémoire. La fusion des opérateurs améliore la planification des opérateurs, la bande passante mémoire et les coûts de taille de la mémoire.
Ce type d'optimisation implique généralement l'écriture d'un noyau CUDA personnalisé, mais c'est beaucoup plus difficile que d'utiliser un simple script Python. Au fil du temps, de plus en plus d'opérateurs ont été progressivement implémentés dans PyTorch, dont beaucoup combinent simplement plusieurs opérations courantes en une fonction plus complexe.
L'ajout d'opérateurs facilite la création de modèles dans PyTorch, et le mode Eager fonctionne plus rapidement en raison de moins de lectures/écritures de mémoire. L’inconvénient est que PyTorch a atteint plus de 2 000 opérateurs en quelques années.
On peut dire que les développeurs de logiciels sont trop paresseux, mais pour être honnête, qui n'a pas été paresseux ? Une fois qu'ils se sont habitués à un nouvel opérateur dans PyTorch, ils continuent de l'utiliser. Le développeur peut même ne pas se rendre compte que les performances s'améliorent et continuer à utiliser l'opérateur car il élimine le besoin d'écrire davantage de code.
De plus, tous les opérateurs ne peuvent pas être fusionnés. Décider quelles opérations combiner et lesquelles allouer à des ressources informatiques spécifiques au niveau de la puce et du cluster prend beaucoup de temps. Bien que les stratégies d'intégration des opérateurs soient généralement similaires, elles peuvent varier considérablement en raison des différentes architectures.
La croissance et le statut par défaut des opérateurs sont un avantage pour NVIDIA car chaque opérateur est rapidement optimisé pour son architecture mais n'est optimisé pour aucun autre matériel. Si une startup de matériel d’IA souhaitait implémenter pleinement PyTorch, cela signifierait prendre en charge une liste croissante de 2 000 opérateurs hautes performances.
Parce qu'extraire des performances maximales nécessite beaucoup de compétences, la formation de grands modèles avec une utilisation élevée des FLOPS sur des GPU nécessite un niveau de talent de plus en plus élevé. L'exécution hâtive de la fusion additive d'opérateurs signifie que les logiciels, les techniques et les modèles développés sont constamment poussés pour s'adapter aux ratios de calcul et de mémoire dont disposent les GPU de la génération actuelle.
Tous ceux qui développent des puces d'apprentissage automatique sont contraints par le même mur de mémoire. Les ASIC sont limités par la prise en charge des frameworks les plus couramment utilisés, par les méthodes de développement par défaut, le code PyTorch optimisé pour le GPU et un mélange de bibliothèques NVIDIA et externes. Dans ce cas, cela n’a pas de sens d’avoir une architecture qui évite les divers bagages non informatiques du GPU au profit de plus de FLOPS et d’un modèle de programmation plus strict.
Cependant, la facilité d'utilisation passe avant tout. La seule façon de briser le cercle vicieux est de rendre le logiciel qui exécute les modèles sur les GPU de Nvidia aussi simple et transférable de manière transparente vers d’autres matériels que possible. À mesure que les architectures de modèles se stabilisent et que les abstractions de PyTorch 2.0, OpenAI Triton et de sociétés MLOps comme MosaicML deviennent la valeur par défaut, l'architecture et l'économie des solutions de puces commencent à être les principaux moteurs d'achat, plutôt que la facilité d'utilisation offerte par les logiciels avancés de Nvidia. .
Il y a quelques mois, la Fondation PyTorch a été créée et séparée de Meta. Outre les modifications apportées au modèle ouvert de développement et de gouvernance, la version 2.0 a été publiée en première version bêta et est devenue généralement disponible en mars. PyTorch 2.0 apporte de nombreux changements, mais la principale différence est qu'il ajoute une solution de compilation prenant en charge un modèle d'exécution graphique. Ce changement facilitera l’utilisation correcte des diverses ressources matérielles.
PyTorch 2.0 améliore les performances d'entraînement de 86 % sur NVIDIA A100 et les performances d'inférence sur le processeur de 26 %. Cela réduit considérablement le temps de calcul et le coût requis pour entraîner le modèle. Ces avantages s'étendent à d'autres GPU et accélérateurs d'AMD, Intel, Tenstorrent, Luminous Computing, Tesla, Google, Amazon, Microsoft, Marvell, Meta, Graphcore, Cerebras, SambaNova, etc.
PyTorch 2.0 offre une plus grande marge d'amélioration des performances sur le matériel actuellement non optimisé. Meta et d'autres sociétés apportent d'énormes contributions à PyTorch parce qu'elles souhaitent obtenir une utilisation plus élevée des FLOPS avec moins d'efforts sur leurs clusters de formation GPU de plusieurs milliards de dollars. De cette façon, ils sont également incités à rendre leurs piles logicielles plus portables sur d’autres matériels, introduisant ainsi la concurrence dans l’espace d’apprentissage automatique.
Avec l'aide de meilleures API, PyTorch 2.0 peut également prendre en charge le parallélisme des données, le partitionnement, le parallélisme des pipelines et le parallélisme des tenseurs, faisant progresser la formation distribuée. De plus, il prend en charge les formes dynamiques de manière native dans la pile, ce qui, parmi de nombreux autres exemples, facilite la prise en charge de différentes longueurs de séquence pour les LLM. Vous trouverez ci-dessous la première prise en charge majeure du compilateur pour les formes dynamiques, de la formation à l'inférence :
Écrit pour PyTorch pour tous les ASIC d'apprentissage automatique, à l'exception des GPU NVIDIA. Un backend hautes performances qui prend entièrement en charge tous les 2000+ opérateurs n’est pas une tâche facile. PrimTorch réduit le nombre d'opérateurs à environ 250 opérateurs d'origine tout en conservant la même convivialité pour les utilisateurs finaux de PyTorch. PrimTorch rend la mise en œuvre de différents backends non NVIDIA de PyTorch plus simple et plus accessible. Les fournisseurs de matériel et de systèmes personnalisés peuvent déployer plus facilement leurs piles logicielles.
Le passage aux modèles graphiques nécessite une définition graphique fiable. Meta et PyTorch tentent de réaliser ce changement depuis environ 5 ans, mais chaque solution qu'ils ont proposée présentait des lacunes importantes. Finalement, ils ont résolu le problème en utilisant TorchDynamo. TorchDynamo ingèrera n'importe quel script utilisateur PyTorch, y compris les scripts qui appellent des bibliothèques tierces externes, et générera des graphiques FX.
Dynamo réduit tous les opérateurs complexes à environ 250 opérateurs primitifs dans PrimTorch. Une fois le graphe formé, les opérateurs inutilisés sont supprimés et le graphe détermine quels opérateurs intermédiaires doivent être stockés ou écrits en mémoire, et lesquels peuvent être fusionnés. Cela réduit considérablement les frais généraux au sein du modèle tout en étant « transparent » pour l'utilisateur.
TorchDynamo fonctionne déjà sur plus de 99 % des 7 000 modèles PyTorch testés, y compris les modèles d'OpenAI, HuggingFace, Meta, NVIDIA, Stability.AI, et plus encore, sans aucune modification du code d'origine. Les 7 000 modèles testés ont été sélectionnés au hasard parmi les projets les plus populaires utilisant PyTorch sur GitHub.
TensorFlow/Jax de Google et d'autres pipelines d'exécution en mode graphique exigent souvent que les utilisateurs s'assurent que leurs modèles correspondent à l'architecture du compilateur afin que les graphiques puissent être capturés. Dynamo change cela en permettant la capture partielle de graphiques, la capture de graphiques protégés et la recapture instantanée.
La capture partielle de graphiques permet aux modèles de contenir des constructions non prises en charge/non python. Lorsqu'un graphique ne peut pas être généré pour une pièce de modèle, une rupture de graphique sera insérée et une construction non prise en charge sera effectuée en mode impatient entre les graphiques de pièces.
La capture de graphique protégée vérifie si le graphique capturé est valide pour l'exécution. « Protection » signifie un changement qui nécessite une recompilation. Ceci est important car exécuter le même code plusieurs fois ne sera pas recompilé plusieurs fois. La recapture à la volée permet de recapturer le graphique si le graphique capturé n'est pas valide pour l'exécution.
L'objectif de PyTorch est de créer une interface unifiée avec une UX fluide qui exploite Dynamo pour la génération de graphiques. L’expérience utilisateur de la solution ne change pas, mais les performances peuvent être considérablement améliorées. Les graphiques de capture peuvent être exécutés plus efficacement en parallèle sur de grandes quantités de ressources informatiques.
Dynamo et AOT Autograd transmettent ensuite le graphe FX optimisé au niveau du compilateur natif PyTorch, TorchInductor. Les fabricants de matériel informatique peuvent également insérer ce graphique dans leurs propres compilateurs back-end.
TorchInductor est un compilateur d'apprentissage en profondeur natif Python qui peut générer du code rapide pour plusieurs accélérateurs et backends. Inductor prendra des graphiques FX avec environ 250 opérateurs et les réduira à environ 50 opérateurs. Ensuite, l'Inductor entre dans la phase de planification, où les opérateurs sont fusionnés et la planification de la mémoire est déterminée.
Ensuite, l'inducteur entre dans "Wrapper Codegen", qui génère du code qui s'exécute sur un CPU, un GPU ou un autre accélérateur d'IA. Le wrapper Codegen remplace la partie interpréteur de la pile du compilateur et peut appeler le noyau et allouer de la mémoire. La partie génération de code backend exploite OpenAI Triton pour les GPU et génère du code PTX. Pour les processeurs, le compilateur Intel génère du C++ (fonctionne également sur les processeurs non Intel).
Ils prendront en charge davantage de matériel à l'avenir, mais le fait est qu'Inductor réduit considérablement la quantité de travail que les équipes de compilateurs doivent effectuer lors de la création de compilateurs pour leurs accélérateurs matériels d'IA. De plus, le code est davantage optimisé en termes de performances, et les besoins en bande passante et en capacité mémoire sont considérablement réduits.
Ce dont les chercheurs ont besoin, ce n'est pas seulement un compilateur qui prend en charge uniquement les GPU, mais un compilateur qui prend en charge divers backends matériels.
OpenAI Triton est une présence perturbatrice pour le logiciel d'apprentissage automatique fermé de NVIDIA. Triton récupère les données directement depuis Python ou via la pile PyTorch Inductor, cette dernière étant l'utilisation la plus courante. Triton est responsable de la conversion de l'entrée en une représentation intermédiaire LLVM et de la génération du code. Les GPU NVIDIA généreront directement du code PTX, en ignorant les bibliothèques CUDA à source fermée de NVIDIA (telles que cuBLAS) et en utilisant à la place des bibliothèques open source (telles que cutlass).
CUDA est populaire dans le monde du calcul accéléré, mais peu connu parmi les chercheurs en apprentissage automatique et les data scientists. L'utilisation de CUDA peut présenter des défis et nécessiter une compréhension approfondie de l'architecture matérielle, ce qui peut ralentir le processus de développement. En conséquence, les experts en apprentissage automatique peuvent s'appuyer sur les experts CUDA pour modifier, optimiser et paralléliser leur code.
Triton comble cette lacune, permettant aux langages de haut niveau d'atteindre des performances comparables aux langages de bas niveau. Le noyau Triton lui-même est très clair pour le chercheur ML typique, ce qui est très important pour la convivialité. Triton automatise la fusion de mémoire, la gestion de la mémoire partagée et la planification dans SM. Triton n'est pas particulièrement utile pour la multiplication matricielle élément par élément, mais la multiplication matricielle peut déjà être effectuée de manière très efficace. Triton est utile pour les opérations point par point coûteuses et pour réduire les frais généraux des opérations complexes.
OpenAI Triton ne prend actuellement officiellement en charge que les GPU NVIDIA, mais cela changera dans un avenir proche pour prendre en charge plusieurs autres fournisseurs de matériel. D'autres accélérateurs matériels peuvent être intégrés directement dans le LLVM IR de Triton, ce qui réduit considérablement le temps de création d'une pile de compilateur IA pour le nouveau matériel.
L'énorme système logiciel de NVIDIA manque de prévoyance et est incapable de tirer parti de ses énormes avantages en matière de matériel et de logiciels ML, et ne parvient donc pas à devenir le compilateur par défaut pour l'apprentissage automatique. Ils ne se concentrent pas sur la convivialité qui permet à OpenAI et Meta de créer des piles logicielles portables sur d'autres matériels.
Lien original : https://www.semianalysis.com/p/nvidiaopenaitritonpytorch
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!