Définir la charge avant de choisir le compteur
« Un modèle 7B » ne précise ni la représentation des poids ni le travail à effectuer. Relevez sa révision, le framework, les versions des extensions, le format réellement chargé et l’opération : entraînement, adaptation ou génération. Pour le texte, notez les longueurs d’entrée et de sortie ; pour la vision, la résolution et le nombre d’images. Un modèle multimodal demande de conserver ces deux dimensions.
Préparez une entrée habituelle, une longue mais attendue et une proche de votre limite fonctionnelle. Gardez-les pendant les comparaisons. Vérifiez les formes après tokenisation, padding, regroupement ou redimensionnement : la valeur inscrite dans la configuration ne prouve pas la forme réellement traitée.
Fixez également ce qui reste simultanément en mémoire : une séquence, un microbatch, plusieurs requêtes ou une évaluation lancée après l’entraînement. Votre question devient vérifiable : cette charge complète tient-elle sur chaque appareil utilisé, y compris pendant son étape la plus exigeante ?
- Identité de l’essai : modèle ou code, révision, jeu d’entrées et graine lorsque pertinente.
- Dimensions : batch, contexte, tokens générés, résolution ou nombre de requêtes simultanées.
- Environnement : GPU sélectionné, pilote, Python, PyTorch, backend CUDA ou HIP/ROCm et réglages d’allocateur.
- Périmètre : chargement, calcul, transfert, évaluation, export ; premier passage ou passage après échauffement.
Calculer les poids sans mélanger Go et Gio
Un Go correspond à 1 000 000 000 octets ; un Gio à 1 073 741 824 octets. Les compteurs PyTorch utilisés ici renvoient des octets. Conservez cette valeur brute dans le fichier de résultats, puis appliquez une seule conversion pour comparer les lignes. Le libellé commercial d’une carte ne remplace pas la capacité effectivement déclarée par l’appareil.
Pour un ensemble dense de sept milliards de paramètres stockés sur deux octets chacun, les poids représentent 14 000 000 000 octets : 14 Go, ou environ 13,04 Gio. Cette opération ne comprend ni activations, ni gradients, ni cache KV, ni états d’optimiseur. Ajouter une réserve de 4 Gio donne environ 17,04 Gio comme hypothèse de préparation ; cela ne démontre pas qu’une charge tiendra dans cette enveloppe.
La division théorique à quatre bits suppose un stockage compact uniforme. Un vrai chargement quantifié peut ajouter des échelles et autres informations, et conserver certains modules dans une autre précision. Le format de stockage des poids et le format de calcul doivent donc apparaître séparément dans votre fiche.
| Hypothèse de stockage | Octets calculés | Gio approximatifs |
|---|---|---|
| 32 bits uniformes | 28 000 000 000 | 26,08 |
| 16 bits uniformes | 14 000 000 000 | 13,04 |
| 4 bits compacts, hors métadonnées | 3 500 000 000 | 3,26 |
Sources techniques : NIST — préfixes binaires et comparaison GB/GiB · Hugging Face — formats et modules quantifiés avec bitsandbytes
En entraînement, mesurer un pas complet
Les poids coexistent avec d’autres objets : gradients, états d’optimiseur, activations nécessaires au passage arrière et tenseurs temporaires. Leurs tailles dépendent de la boucle, de la précision et des dimensions de la charge. Une constante universelle en octets par paramètre masquerait notamment l’effet du microbatch et des entrées.
Instrumentez le passage avant, le calcul de perte, la rétropropagation et la mise à jour. Pour observer les états réellement créés par votre optimiseur, ne vous arrêtez pas au chargement du modèle. Conservez également une mesure du premier pas complet : un échauffement réussi peut avoir déjà effectué une initialisation que vous devez pouvoir financer en mémoire au démarrage.
Ajoutez une évaluation et l’export dont votre projet a besoin. Si l’échec survient pendant l’évaluation, réduire uniquement le batch d’entraînement ne corrige pas cette phase. Une adaptation qui entraîne peu de paramètres peut encore conserver un modèle de base et des activations volumineuses.
Sources techniques : Hugging Face — catégories de mémoire pendant l’entraînement
En inférence, suivre le contexte et la concurrence
Dans une génération autorégressive avec attention, le cache KV garde des états associés aux tokens. Pour un cache dense uniforme, sa taille dépend des couches, des têtes KV, de leur dimension, des tokens conservés et des séquences présentes ensemble. Utilisez les têtes KV du modèle, pas automatiquement ses têtes de requête.
Exemple arithmétique : 32 couches, 8 têtes KV, une dimension de 128, 8 192 tokens, deux octets par valeur et une séquence donnent 1 073 741 824 octets, soit 1 Gio pour K et V réunis. Quatre séquences identiques donnent 4 Gio pour ce seul poste. Ce calcul ne mesure ni débit ni occupation complète du GPU.
Adaptez la formule au cache réellement employé. Une fenêtre glissante ne conserve pas nécessairement tout l’historique ; un cache statique peut préallouer sa capacité maximale. Les caches quantifiés et déportés changent aussi le problème. Mesurez séparément le traitement initial de l’entrée et la génération, sans attribuer automatiquement tout leur écart au cache.
Sources techniques : Hugging Face — stratégies de cache, allocation statique et fenêtres
Allocated et reserved : deux lectures qui ne s’additionnent pas
memory_allocated décrit les octets occupés par les tenseurs suivis par PyTorch sur l’appareil. memory_reserved décrit la mémoire gérée par son allocateur avec cache, dont celle qui sert déjà à ces tenseurs. Additionner les deux compte deux fois une partie de la mémoire. Conservez-les dans deux colonnes distinctes.
Leurs variantes max enregistrent chacune un pic depuis le début du suivi ou sa dernière remise à zéro. Ce sont des pics absolus de la période, qui incluent les allocations déjà présentes au début. Le résultat ne représente pas automatiquement les seuls objets créés par la phase.
Une lecture système peut avoir un périmètre plus large. Les allocations faites directement par une bibliothèque CUDA, par exemple certaines communications NCCL, ne sont pas toutes visibles dans l’allocateur PyTorch. Une différence avec un outil système n’établit donc pas, à elle seule, une fuite.
| Compteur | Question à laquelle il répond | Erreur à éviter |
|---|---|---|
| memory_allocated | Combien les tenseurs occupent-ils à ce point de lecture ? | Le prendre pour toute l’occupation de la carte. |
| memory_reserved | Combien l’allocateur gère-t-il à ce point de lecture ? | L’ajouter à allocated. |
| max_memory_allocated | Quel pic des tenseurs a été suivi pendant la période ? | Le confondre avec la valeur en fin de phase. |
| max_memory_reserved | Quel pic de réservation l’allocateur rapporte-t-il ? | Supposer qu’il survient au même instant que l’autre pic. |
Sources techniques : PyTorch — memory_allocated · PyTorch — memory_reserved · PyTorch — max_memory_allocated · PyTorch — allocations hors de son allocateur
Pourquoi la différence entre les deux pics ne mesure pas le cache
Considérons uniquement les deux instants fictifs du tableau. Le pic allocated vaut 8 Gio et le pic reserved 12 Gio. Leur différence, 4 Gio, n’est la différence observée à aucun de ces deux instants : celle-ci vaut respectivement 2 et 6 Gio. Deux maxima ne décrivent pas forcément un même état.
Pour étudier leur écart à un moment donné, relevez allocated et reserved au même point de contrôle, après synchronisation et sans nouvelle opération volontaire entre les lectures. Vous obtenez un écart de compteurs à cet instant, pas une mesure du cache KV du modèle, ni une garantie que toute cette différence peut satisfaire la prochaine allocation.
Gardez aussi le backend de l’allocateur dans le rapport. La documentation PyTorch 2.14 précise que, avec cudaMallocAsync, max_memory_reserved peut combiner les plus hauts niveaux de deux pools et fournir une borne supérieure du pic simultané. Cela renforce la nécessité de conserver le nom et le périmètre du compteur.
| Instant illustratif | Allocated | Reserved | Reserved − allocated à cet instant |
|---|---|---|---|
| A | 8 Gio | 10 Gio | 2 Gio |
| B | 6 Gio | 12 Gio | 6 Gio |
Sources techniques : PyTorch — définition et limite de max_memory_reserved
Délimiter chaque phase avant de relever son pic
Les opérations GPU peuvent être mises en file avant d’être terminées. Pour une mesure par phase, terminez les travaux précédents avant de remettre les pics à zéro, puis attendez la fin de la phase avant la lecture. torch.cuda.synchronize attend les kernels de tous les streams de l’appareil sélectionné ; ce choix définit une frontière explicite pour ce protocole.
reset_peak_memory_stats réinitialise le suivi des pics à partir de l’état courant ; il ne libère pas les tenseurs du programme. Relevez d’abord les niveaux de départ. À la fin, conservez les deux pics absolus et les deux niveaux courants. Ne présentez pas la soustraction d’un niveau de départ comme le volume exact de tous les tenseurs temporaires : des objets antérieurs peuvent aussi avoir été libérés pendant la phase.
Cette instrumentation peut modifier le chevauchement habituel des phases. Utilisez-la pour localiser le problème, puis vérifiez aussi la boucle complète avec son ordonnancement réel. En multicarte, répétez les lectures pour chaque appareil ; une mesure sur cuda:0 ne décrit pas les autres GPU.
- 1. Donner un nom à la phase et noter ses entrées exactes.
- 2. Synchroniser l’appareil, puis relever allocated et reserved de départ.
- 3. Appeler reset_peak_memory_stats sur ce même appareil.
- 4. Exécuter la phase définie en conservant les sorties nécessaires à la suite.
- 5. Synchroniser, relever les pics et les niveaux de fin, puis enregistrer réussite ou erreur.
- 6. Garder le résultat brut, les dimensions et la configuration ; ne remplir aucune mesure manquante par zéro.
Sources techniques : PyTorch — synchronisation d’un appareil · PyTorch — remise à zéro des statistiques de pic
Distinguer premier passage et passages après échauffement
Le premier essai et une boucle déjà préparée ne répondent pas à la même question. Conservez une trace du chargement et du premier passage, puis documentez le nombre d’itérations d’échauffement avant les répétitions. Ne supprimez pas un échec d’initialisation au motif que les passages suivants auraient été plus légers.
Le script IteraGPU distingue model_load, inputs, cold_forward, warmup et warm_forward. Son cold_forward est le premier passage du petit modèle après initialisation de l’appareil. Il ne mesure pas tout le démarrage d’un serveur, d’un pilote ou d’un service. Les répétitions warm_forward restent dans le même processus et profitent de son état existant.
Pour votre modèle, commencez une nouvelle série dans un nouveau processus lorsque vous changez une condition susceptible de laisser des objets ou réservations précédents. Notez l’ordre des essais et la politique d’échauffement. Relancer cinq fois une même boucle et lancer cinq processus ne constituent pas le même protocole.
Utiliser le notebook et le script IteraGPU Lab v1
Commencez par le README, puis téléchargez le notebook autonome ou le script Python. Le calcul estimate utilise la bibliothèque standard. La mesure exige PyTorch installé avec un backend GPU compatible et un appareil accessible ; elle ne télécharge ni modèle ni paquet. Le notebook demande un environnement capable de lire les fichiers ipynb.
L’exercice de mesure utilise un petit réseau dense original et des entrées synthétiques. Les options batch, context et width décrivent ses tenseurs ; context n’est pas ici la longueur d’un véritable LLM avec cache KV. Ce support sert à examiner la méthode de mesure et à faire varier une dimension. Il ne démontre pas la capacité d’une carte pour votre modèle de recherche.
Exécutez les commandes ci-dessous depuis le dossier contenant le script. Consultez d’abord le rapport environment. Si PyTorch ou le GPU manque, measure doit s’arrêter explicitement avec le code 2 ; aucun résultat CPU ne doit être interprété comme une mesure GPU. Le JSON de sortie d’une mesure réussie est produit dans votre environnement. Choisissez un nouveau nom de fichier pour chaque série : le script refuse d’écraser un résultat existant.
La première commande refait le calcul des poids et de la réserve hypothétique de 4 Gio. Pour les suivantes, utilisez un appareil que vous êtes autorisé à solliciter et gardez des dimensions modestes au départ. Relevez la version de PyTorch réellement utilisée : les références techniques de cette page décrivent notamment la version 2.14, sans imposer qu’elle soit installée chez vous.
Le fonctionnement du script a été contrôlé sur un petit cas : RTX 5070 locale hors catalogue, pilote 610.62, Python 3.14.6 et PyTorch 2.11.0+cu128. L’essai utilisait batch 1, contexte 16, largeur 64, float32, un échauffement et deux répétitions. Il valide ce chemin d’exécution, sans qualifier un LLM, un entraînement ou les GPU proposés à la location. Le notebook est livré sans sorties et le tableau de comparaison sans résultats ; la garde d’absence de PyTorch a aussi été vérifiée dans un environnement distinct.
python mesure_memoire.py estimate --parameters 7000000000 --bits 16 --reserve-gib 4
python mesure_memoire.py environment --device cuda:0
python mesure_memoire.py measure --device cuda:0 --batch 2 --context 128 --width 1024 --dtype float32 --warmup 3 --repeats 5 --output mesures.json- Notebook de calcul et de mesure
Notebook autonome à ouvrir, relire et exécuter dans votre environnement.
- Script mesure_memoire.py
Calcul sans dépendance externe, contrôle d’environnement et mesure GPU explicite.
- Mode d’emploi du dossier
Prérequis, commandes, périmètre des phases et limites d’interprétation.
- Archive IteraGPU Lab v1
Les ressources versionnées réunies, avec leur mode d’emploi et leur licence.
- Licence des ressources
Conditions de réutilisation des fichiers fournis.
Interpréter une défaillance avant de changer de carte
Un essai incomplet reste une observation utile. Conservez la phase, les dimensions demandées, le message d’erreur et les dernières valeurs disponibles. Un pic partiel avant une saturation ne constitue pas le besoin mémoire d’une exécution complète. Réduisez une seule dimension pour construire un cas qui aboutit, puis cherchez la frontière entre réussite et échec.
empty_cache libère des blocs inutilisés du cache de l’allocateur, sans libérer les tenseurs encore vivants. Ce n’est pas une correction universelle à une charge trop grande. L’appeler entre chaque répétition change les conditions : documentez ce choix au lieu de mélanger ces essais avec ceux qui conservent le cache.
Si les compteurs simples n’expliquent pas la situation, une trace de mémoire peut aider à identifier les allocations au fil du temps. Son périmètre reste celui des allocations visibles par PyTorch. Un faible pic allocated n’exclut donc pas une allocation externe ou un autre utilisateur de la carte.
| Observation | Vérification utile | Essai suivant |
|---|---|---|
| Échec pendant le chargement | Format chargé, placement des poids et mémoire déjà occupée. | Reproduire le chargement seul dans un processus neuf. |
| Chargement réussi, passage arrière impossible | Microbatch, entrées, activations conservées et état de la boucle. | Réduire une dimension puis refaire le pas complet. |
| Évaluation seule en échec | Batch d’évaluation, sorties retenues et contexte de calcul. | Mesurer l’évaluation avec ses propres limites. |
| Allocated augmente d’une répétition à l’autre | Références conservées dans des listes, caches applicatifs ou graphes. | Vérifier leur durée de vie avant d’accuser l’allocateur. |
| Reserved reste élevé après le calcul | Tenseurs encore vivants et politique de cache. | Comparer les valeurs courantes, sans additionner les compteurs. |
| Un outil système indique davantage | Périmètre de l’outil, contexte GPU, autres processus et bibliothèques. | Isoler la charge et rapprocher des lectures prises au même moment. |
Sources techniques : PyTorch — ce que libère empty_cache · PyTorch — traces et limites de visibilité mémoire
Construire une marge à partir de charges comparables
Évitez un pourcentage de marge présenté comme universel. La marge doit couvrir des variations identifiées : entrée plus longue, batch autorisé, évaluation, export, version de bibliothèque ou autre occupation de la carte. Testez les cas limites attendus, puis consignez ce qui reste hors du périmètre. Une exécution réussie sur une seule petite entrée ne valide pas la charge maximale.
Changez une variable à la fois : batch 1 puis 2 à contexte constant, ou contextes 2 048 puis 4 096 à batch constant. Gardez le même contenu et les mêmes règles de préparation. Une troncature qui retire une information nécessaire rend la tâche différente, même si elle réduit le pic.
Si les poids dominent, étudiez un autre format en contrôlant la qualité. Si les activations dominent, le microbatch ou le checkpointing d’activations peuvent être des pistes. Ce dernier échange de la mémoire contre du recalcul : mesurez aussi la durée et vérifiez les résultats. Si le cache KV domine, examinez contexte, concurrence et stratégie de cache. Le dossier de comparaison complète cette démarche avec une règle de qualité commune.
Sources techniques : PyTorch — checkpointing d’activations et recalcul
Passer de la trace à une décision de configuration
Votre sortie attendue est une fiche courte : estimation des poids, charge maximale testée, phases réussies ou échouées, quatre compteurs avec unités, environnement et choix retenu. Joignez le résultat brut à cette fiche. Séparez ce que vous avez calculé, ce que vous avez observé et ce que vous supposez encore.
Comparez ensuite le besoin avec la capacité de chaque carte, en gardant les contraintes logicielles. Plusieurs GPU exigent une répartition du travail et des données ; leur présence ne crée pas automatiquement un seul réservoir de mémoire pour l’application. Un échec sur une carte peut persister malgré de la mémoire libre sur une autre.
Le protocole PyTorch emploie l’interface torch.cuda ; une construction HIP/ROCm de PyTorch réutilise ce nom. Identifiez le backend réellement installé avant de comparer deux familles matérielles. L’emploi d’une même fonction Python ne démontre pas que les noyaux, les précisions ou les résultats sont équivalents.
Le dimensionneur permet de reprendre l’hypothèse initiale ; les fiches GPU permettent de comparer les capacités. Revenez ensuite au même cas de travail pour vérifier le choix. Le petit réseau du téléchargement reste un exercice d’instrumentation : seule l’exécution de votre charge, dans son environnement documenté, peut valider votre propre marge.
Sources techniques : NVIDIA — répartition du travail sur plusieurs GPU · PyTorch — interface torch.cuda dans les constructions HIP/ROCm