Combien de VRAM pour faire tourner un modèle : l’arithmétique avant l’achat

admineci

admineci

Author

2276 words

Les poids d’un modèle ne sont pas seuls en mémoire : le cache d’attention peut les dépasser, et c’est lui qui décide du nombre de cartes.

Portée de cet article. Dimensionnement de la mémoire d’un accélérateur pour servir un modèle de langage en inférence. Toutes les formules sont données avec leur source et vérifiables sur n’importe quel modèle dont la configuration est publique. L’entraînement et le réglage fin obéissent à d’autres règles et ne sont pas traités ici.

Un modèle de 70 milliards de paramètres quantifié sur 4 bits pèse 35 gigaoctets. Une carte H100 en embarque 80. Le calcul semble réglé, le bon de commande part, la plateforme est installée. Puis arrive la première requête à contexte long, et la carte sature.

Le calcul n’était pas faux. Il était incomplet. Les poids du modèle ne sont pas la seule chose qui occupe la mémoire d’un accélérateur en service, et la part manquante est celle qui décide du nombre de cartes à acheter.

Le calcul que tout le monde fait

La taille des poids en mémoire est le produit du nombre de paramètres par le nombre d’octets utilisés pour représenter chacun d’eux.

poids (octets) = nombre de parametres x octets par parametre

FP32   4 octets par parametre
FP16   2 octets par parametre
BF16   2 octets par parametre
FP8    1 octet  par parametre
INT4   0,5 octet par parametre

Ce calcul est juste et se vérifie facilement : le poids d’un fichier de modèle publié correspond, à quelques mégaoctets près, au résultat de cette multiplication.

Modèle FP16 ou BF16 FP8 INT4
7 milliards de paramètres 14 Go 7 Go 3,5 Go
70 milliards de paramètres 140 Go 70 Go 35 Go
405 milliards de paramètres 810 Go 405 Go 202,5 Go

C’est de ce tableau que sortent les affirmations courantes : un modèle de 7 milliards de paramètres tient sur une carte grand public, un modèle de 70 milliards demande deux cartes de 80 gigaoctets en 16 bits, ou une seule s’il est quantifié en 4 bits. Ces affirmations sont exactes pour un modèle au repos. Elles cessent de l’être dès qu’il travaille.

Ce que ce calcul oublie : le cache d’attention

Un modèle de langage génère son texte un jeton à la fois. Pour produire le jeton suivant, le mécanisme d’attention doit consulter tous les jetons qui précèdent. Sans mémoire intermédiaire, chaque nouveau jeton exigerait de tout recalculer depuis le début : le coût deviendrait quadratique et la génération en flux serait impossible.

La solution universellement retenue consiste à conserver, pour chaque jeton déjà traité, deux vecteurs par couche : la clé et la valeur. C’est le cache clé-valeur, souvent désigné par son abréviation anglaise KV cache. Il transforme un problème quadratique en problème linéaire, et c’est ce qui rend la génération en temps réel possible.

Il occupe de la mémoire. Beaucoup, et de façon proportionnelle à deux grandeurs que le calcul des poids ignore complètement : la longueur du contexte et le nombre de requêtes traitées en même temps.

La formule

La documentation technique de NVIDIA sur l’optimisation de l’inférence donne la formule applicable à la plupart des architectures actuelles :

octets par jeton = 2 x couches x tetes_KV x dimension_tete x octets_par_element

Le facteur 2 correspond aux deux matrices, clés et valeurs. Les autres termes se lisent directement dans le fichier de configuration publié avec le modèle : num_hidden_layers pour les couches, num_key_value_heads pour les têtes, et la dimension de tête s’obtient en divisant hidden_size par num_attention_heads.

Pourquoi les têtes de clé-valeur ne sont pas les têtes d’attention

Ce point est la source d’erreur la plus fréquente dans les dimensionnements. Les architectures récentes emploient l’attention à requêtes groupées, où plusieurs têtes de requête partagent une même paire clé-valeur. Un modèle peut ainsi déclarer 64 têtes d’attention mais seulement 8 têtes de clé-valeur.

Utiliser le nombre de têtes d’attention à la place du nombre de têtes de clé-valeur surestime le cache d’un facteur 8 sur un tel modèle. L’erreur inverse — reprendre une formule écrite pour une architecture ancienne — le sous-estime d’autant. Il faut lire la valeur dans la configuration du modèle visé, pas la déduire d’un article portant sur un autre modèle.

Un cas complet : 70 milliards de paramètres en service

Prenons un modèle de 70 milliards de paramètres à l’architecture classique de cette catégorie : 80 couches, 8 têtes de clé-valeur, dimension de tête de 128, cache stocké en BF16 sur 2 octets.

octets par jeton = 2 x 80 x 8 x 128 x 2
                 = 327 680 octets
                 = 0,31 mebioctet par jeton

Ce nombre paraît modeste. Il ne l’est plus une fois multiplié par la charge réelle. Le tableau suivant reprend le même modèle quantifié en 4 bits, soit 35 gigaoctets de poids, et fait varier le contexte et le nombre de requêtes simultanées.

Charge Poids Cache d’attention Total
1 requête, 8 192 jetons 35 Go 2,7 Go 37,7 Go
1 requête, 131 072 jetons 35 Go 42,9 Go 77,9 Go
32 requêtes, 8 192 jetons 35 Go 85,9 Go 120,9 Go
10 requêtes, 32 768 jetons 35 Go 107,4 Go 142,4 Go

Trois lectures s’imposent.

À contexte maximal et pour un seul utilisateur, le cache dépasse le poids du modèle quantifié. Les 42,9 gigaoctets de cache sont supérieurs aux 35 gigaoctets de poids. La partie que le calcul initial oubliait est donc devenue la plus grosse.

Trente-deux requêtes simultanées à 8 192 jetons produisent exactement 80 gibioctets de cache. C’est la capacité entière d’une carte de 80 gigaoctets, consommée par le seul cache, avant même d’y placer un octet de modèle.

Enfin, la ligne la plus lourde du tableau ne correspond ni au contexte le plus long ni au nombre de requêtes le plus élevé. C’est leur produit qui compte, et rien d’autre : le cache est proportionnel au nombre total de jetons en vol, quelle que soit la façon dont ils se répartissent entre les requêtes.

Gigaoctet ou gibioctet : sept pour cent d’écart

Les sources publiques donnent tantôt 40, tantôt 42,9 gigaoctets pour le même calcul à 131 072 jetons. Les deux sont exacts et désignent la même quantité d’octets. La différence tient à l’unité.

1 gigaoctet  (Go)  = 1 000 000 000 octets
1 gibioctet  (Gio) = 1 073 741 824 octets
ecart = 7,4 pour cent

Sur un dimensionnement, 7,4 pour cent suffisent régulièrement à faire basculer une décision d’une carte à deux. La règle de travail est simple : ramener toutes les valeurs à la même unité avant de comparer, et retenir que les outils d’administration des accélérateurs affichent en mébioctets, donc en unités binaires.

Une deuxième marge, moins visible, doit s’ajouter. La mémoire réellement disponible pour un modèle est inférieure à la capacité annoncée de la carte : le contexte d’exécution, les tampons intermédiaires et la fragmentation en consomment une part. Prévoir une réserve de l’ordre de dix pour cent est prudent, et cette réserve se vérifie par la mesure une fois la plateforme installée.

Quand le modèle ne tient plus sur une carte

Deux franchissements successifs se présentent, et ils n’ont pas le même coût.

Plusieurs cartes dans un même serveur

Le modèle est découpé entre les cartes, qui se synchronisent à chaque couche par un lien dédié à haut débit. Ce lien est nettement plus rapide qu’un réseau, mais la synchronisation reste un coût fixe payé à chaque couche traversée. Le débit obtenu à deux cartes n’est jamais le double du débit à une carte.

Plusieurs serveurs

La synchronisation traverse alors le réseau, dont la latence est d’un tout autre ordre. Le découpage couche par couche s’y comporte mal ; on passe généralement à un découpage par étages, où chaque serveur traite une tranche du modèle et transmet son résultat au suivant. Le débit agrégé peut être bon, la latence d’une requête isolée se dégrade.

La conclusion pratique est constante : tant qu’une configuration tient dans un seul serveur, elle est préférable, même au prix de cartes plus capacitaires. C’est l’un des points que nous instruisons systématiquement lors d’un cadrage d’infrastructure GPU, car il commande le choix du châssis et l’alimentation de la baie autant que celui des accélérateurs.

Le débit ne dépend pas de la puissance de calcul

Une fois le modèle logé, la question devient celle de la vitesse. La réponse est contre-intuitive pour qui compare des fiches techniques sur leur puissance annoncée.

La génération se déroule en deux phases aux comportements opposés. Le traitement initial de la requête consomme du calcul : toutes les positions du contexte sont traitées ensemble, et les unités de calcul travaillent à plein régime. La génération qui suit, jeton après jeton, consomme de la bande passante mémoire : pour produire un seul jeton, il faut relire l’intégralité des poids du modèle, effectuer un volume de calcul minuscule, puis recommencer pour le jeton suivant.

C’est cette seconde phase qui domine le temps perçu, et elle est limitée par la mémoire, non par le calcul. Le débit maximal d’un flux unique s’en déduit directement.

jetons par seconde (plafond) = bande passante memoire / taille des poids

carte a 3,35 To/s, poids de 35 Go  :   96 jetons par seconde
carte a 8 To/s,    poids de 35 Go  :  229 jetons par seconde

Le rapport de débit entre ces deux cartes suit le rapport de leurs bandes passantes, pas celui de leurs puissances de calcul annoncées. Une carte deux fois plus puissante en calcul et dotée de la même mémoire ne génère pas plus vite pour un utilisateur unique.

Le traitement par lots change la donne, et c’est là que se joue l’économie d’une plateforme. Les poids ne sont lus qu’une fois pour tout le lot : le coût de lecture est amorti sur toutes les requêtes traitées ensemble, et le débit total croît fortement. Mais chaque requête ajoutée au lot ajoute son cache d’attention.

L’arbitrage central du dimensionnement tient donc en une phrase : la mémoire restante après le chargement des poids détermine la taille de lot possible, et la taille de lot détermine le débit. Acheter de la capacité mémoire, c’est acheter du débit, bien plus sûrement qu’acheter de la puissance de calcul.

Lire une fiche technique sans se tromper

Trois pièges récurrents méritent d’être signalés, parce qu’ils faussent les comparaisons dès la phase amont.

Les capacités annoncées par les revendeurs divergent. Pour un même accélérateur de génération récente, les sources publiques annoncent 180 ou 192 gigaoctets, et une bande passante de 7,7 ou 8 téraoctets par seconde. Ces écarts viennent des variantes de conditionnement et des arrondis. Seule la documentation du constructeur fait foi, et elle doit être consultée pour la référence exacte qui sera commandée.

Une même dénomination recouvre des variantes très différentes. Deux cartes portant le même nom commercial peuvent employer des générations de mémoire distinctes selon leur format, avec des bandes passantes qui diffèrent de plusieurs dizaines de pour cent. Comme le débit de génération suit la bande passante, cet écart se retrouve intégralement dans le service rendu.

Les puissances annoncées ne sont pas comparables entre elles. Un chiffre exprimé en précision réduite n’a pas la même signification qu’un chiffre en précision standard, et certaines valeurs supposent une structure creuse des données que les charges réelles n’ont pas toujours. Comparer deux cartes exige de comparer la même précision et le même mode.

Une méthode en cinq étapes

  1. Relever dans la configuration publiée du modèle le nombre de couches, le nombre de têtes de clé-valeur et la dimension de tête.
  2. Calculer la taille des poids pour le format de quantisation retenu.
  3. Calculer le coût du cache par jeton, puis le multiplier par le nombre total de jetons en vol, c’est-à-dire le contexte visé multiplié par le nombre de requêtes simultanées.
  4. Ajouter une réserve d’environ dix pour cent pour le contexte d’exécution et la fragmentation.
  5. Comparer le total à la capacité de la carte exprimée dans la même unité, et vérifier ce résultat par la mesure sur la charge réelle.

Cette méthode donne une borne. Elle ne remplace pas la mesure : les moteurs de service modernes gèrent le cache par blocs et récupèrent la mémoire des requêtes terminées, ce qui améliore le remplissage réel. Le dimensionnement calculé sert à commander le matériel ; la mesure sert à exploiter la plateforme d’inférence une fois qu’elle tourne.

Ce que cet article ne traite pas

L’entraînement et le réglage fin ont une empreinte mémoire différente et bien supérieure : aux poids s’ajoutent les gradients, les états de l’optimiseur et les activations conservées. Le rapport courant est de l’ordre de plusieurs fois la taille des poids, et les méthodes à adaptateurs modifient complètement ce calcul.

Les modèles à experts, où seule une fraction des paramètres est activée par jeton, obéissent à une arithmétique distincte : la mémoire nécessaire reste celle du modèle complet, mais la bande passante consommée par jeton correspond aux seuls experts activés. Le raisonnement sur le débit exposé plus haut ne leur est pas transposable tel quel.

Enfin, cet article ne traite ni du choix du modèle, ni de la qualité de ses réponses, ni des comparaisons de performance entre accélérateurs, qui dépendent trop du moteur de service et de la charge pour être énoncées de façon générale.

Sources

  • NVIDIA, Mastering LLM Techniques: Inference Optimization, documentation technique — formule du cache clé-valeur et phases de l’inférence.
  • NVIDIA, documentation d’architecture Hopper et Blackwell — capacités mémoire et bandes passantes des accélérateurs cités.
  • Dettmers, Pagnoni, Holtzman, Zettlemoyer, QLoRA: Efficient Finetuning of Quantized LLMs, NeurIPS 2023, arXiv:2305.14314 — quantisation sur 4 bits et empreinte mémoire du réglage fin.
  • Hu, Shen, Wallis, Allen-Zhu, Li, Wang, Wang, Chen, LoRA: Low-Rank Adaptation of Large Language Models, 2021, arXiv:2106.09685 — méthode à adaptateurs.
  • Kwon, Li, Zhuang, Sheng, Zheng, Yu, Gonzalez, Zhang, Stoica, Efficient Memory Management for Large Language Model Serving with PagedAttention, SOSP 2023, arXiv:2309.06180 — gestion du cache par blocs et fragmentation.

Share this article

Do you have a similar project?

Our experts are there to support you in your cloud and infrastructure projects.