Logo VRAMfarm VRAMfarm
FR
S’inscrire

11 novembre 2026 · Équipe VRAMfarm

CUDA out of memory : comment corriger l’erreur dans ComfyUI, les LLM et l’entraînement

Terminal affichant une erreur CUDA out of memory à côté d’une barre de mémoire nvidia-smi sur un GPU loué
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 2.00 GiB.
GPU 0 has a total capacity of 23.65 GiB of which 1.12 GiB is free.
Of the allocated memory 20.10 GiB is allocated by PyTorch, and 1.31 GiB
is reserved by PyTorch but unallocated.

Ce message dit une seule chose : à cet instant, le programme a demandé 2 Gio de mémoire vidéo de plus qu’il n’en restait. La carte va bien, et elle n’est pas toujours trop petite. La plupart des cas se règlent en quelques minutes avec l’un de ces quatre leviers : une précision plus basse, une unité de travail plus petite (lot, résolution, contexte), la libération de la mémoire retenue par autre chose, ou un correctif contre la fragmentation. Quand aucun ne fonctionne sans ruiner la qualité ou la vitesse, une carte plus grande est la réponse la moins chère.

Lire l’erreur avant de toucher à quoi que ce soit

Chaque partie du message vous apprend quelque chose :

  • « Tried to allocate 2.00 GiB » désigne la seule demande qui a échoué, pas le total dont votre tâche a besoin. Baisser légèrement les réglages peut simplement repousser le plantage de quelques étapes.
  • « Total capacity of 23.65 GiB » sur une carte de 24 Go, c’est normal. Le pilote garde une petite partie de la mémoire pour lui, et le contexte CUDA prend encore quelques centaines de mégaoctets avant même le chargement du modèle.
  • « Reserved by PyTorch but unallocated » est de la mémoire que PyTorch détient mais ne peut pas utiliser pour cette demande. Si elle se chiffre en gigaoctets, le problème est la fragmentation : voir plus bas.
  • Les lignes « Process 1234 has 9.80 GiB memory in use », quand elles apparaissent, signifient qu’un autre processus partage la carte.

RuntimeError: CUDA error: out of memory sans détails vient généralement d’une bibliothèque comme cuBLAS ou d’un kernel maison, souvent au démarrage. Les solutions sont les mêmes.

Voir ce qui occupe la mémoire avec nvidia-smi

Lancez nvidia-smi dans le terminal Jupyter ou en SSH. La ligne qui compte, c’est celle de chaque GPU :

| 0  NVIDIA GeForce RTX 4090  ...  | 21540MiB / 24564MiB |  97%  Default |

Le premier chiffre est la mémoire utilisée, le second la capacité totale de la carte, puis vient la charge du GPU. Pour suivre tout cela en direct pendant que votre tâche tourne :

nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv -l 1

Sur un serveur loué, la liste des processus en bas est souvent vide, même quand la mémoire est occupée. Le serveur est un conteneur, et nvidia-smi ne voit pas les noms des processus au-delà de cette frontière. Utilisez plutôt ps aux | grep python.

Trois choses retiennent couramment de la mémoire sans que vous vous y attendiez :

  1. Le cache de PyTorch. Les tenseurs libérés restent réservés pour être réutilisés, et nvidia-smi les compte donc comme utilisés. torch.cuda.memory_allocated() montre ce qui est réellement utilisé, torch.cuda.memory_reserved() ce qui est retenu. torch.cuda.empty_cache() rend le cache, ce qui n’aide que si un autre processus en a besoin.
  2. Un autre processus sur la même carte. Un noyau Jupyter qui a chargé un modèle trois cellules plus tôt, un ancien ComfyUI toujours en marche, un script d’entraînement planté en cours de route. Redémarrez le noyau ou faites un kill du PID. Si votre script meurt chaque fois qu’une autre application démarre sur la carte, c’est pour cette raison : les deux se disputent la même mémoire.
  3. La réservation de vLLM. Par défaut, vLLM prend 90 % de la carte au démarrage. Tout ce que vous lancez à côté manquera de mémoire.

ComfyUI, Flux et Wan : les solutions dans l’ordre

Descendez la liste et arrêtez-vous dès que ça tourne :

  1. Utilisez des poids FP8 ou GGUF. Flux.1 dev en 16 bits, c’est environ 24 Go rien que pour les poids ; en FP8, environ 12 Go. Son encodeur de texte T5-XXL passe d’environ 9,5 Go à environ 5 Go en FP8. Les versions GGUF (via les nœuds ComfyUI-GGUF) vont plus loin : Q8 convient aux cartes de 16 Go, Q5 et Q4 tiennent dans 12 Go, et en Q4 les détails fins commencent à en pâtir. Notre modèle Flux fournit déjà Flux.1 schnell en FP8.
  2. Remplacez VAE Decode par VAE Decode (Tiled). Le décodage final est un point de plantage classique, surtout pour les grandes images et la vidéo. Le décodage par tuiles travaille morceau par morceau, au prix de quelques secondes.
  3. Réduisez la taille du lot dans Empty Latent Image. Quatre images l’une après l’autre demandent environ un quart de la mémoire d’activation d’un lot de quatre.
  4. Baissez la résolution, puis faites un upscale. La mémoire des activations croît avec le nombre de pixels : 2048×2048 compte quatre fois plus de pixels que 1024×1024. Générez à la taille native et utilisez un upscaler par tuiles.
  5. En vidéo, réduisez le nombre d’images ou la résolution. Avec Wan 2.2, passer de 81 à 49 images ou de 720p à 480p économise plusieurs gigaoctets. Le modèle 14B se compose de deux experts de 14B que ComfyUI charge à tour de rôle ; sur les cartes de 24 à 32 Go, le block swap des nœuds Wan video wrapper déplace une partie du modèle vers la RAM système.
  6. Déchargez en dernier recours. Quand vous démarrez ComfyUI vous-même, --lowvram garde des parties du modèle en RAM système et --reserve-vram 2 laisse 2 Go libres pour le reste. Attendez-vous à une génération plusieurs fois plus lente.

Les boutons du Manager pour décharger les modèles et vider le cache sont utiles quand vous passez d’un workflow à l’autre au cours d’une même session, par exemple de Flux à Wan, car l’ancien modèle peut rester chargé.

LLM : les poids plus le KV cache

Un modèle de langage a besoin de mémoire pour trois choses : les poids, le KV cache et 1 à 2 Go de marge de fonctionnement.

Les poids valent le nombre de paramètres multiplié par le nombre d’octets par paramètre :

Modèle 16 bits FP8 / 8 bits 4 bits
8B ~16 Go ~8 Go ~5 Go
32B ~66 Go ~33 Go ~20 Go
70B ~141 Go ~71 Go ~43 Go

Le KV cache grossit à chaque token du contexte, pour toutes les requêtes en même temps. En 16 bits, il occupe environ 128 Ko par token pour Llama 3.1 8B, 256 Ko pour Qwen3 32B et 320 Ko pour Llama 3.x 70B. Une seule conversation de 32 000 tokens sur Qwen3 32B demande environ 8 Go de cache ; une conversation de 128 000 tokens sur un modèle 70B, environ 42 Go, autant que les poids en 4 bits. Voilà pourquoi un modèle se charge sans problème puis échoue sur un long chat, ou quand dix utilisateurs arrivent en même temps.

Les solutions selon l’outil :

  • Ollama. Réduisez le contexte avec num_ctx ou OLLAMA_CONTEXT_LENGTH, et divisez le cache par deux avec OLLAMA_FLASH_ATTENTION=1 et OLLAMA_KV_CACHE_TYPE=q8_0. Ollama plante rarement : il déplace plutôt des couches vers le CPU. Si ollama ps affiche quelque chose comme 35%/65% CPU/GPU, le modèle ne tient pas et tourne plusieurs fois plus lentement.
  • llama.cpp. Plafonnez le contexte avec -c 16384, choisissez combien de couches restent sur le GPU avec -ngl, et quantifiez le cache avec --cache-type-k q8_0 --cache-type-v q8_0. Un cache V quantifié exige la flash attention : les versions actuelles l’activent automatiquement quand le GPU la prend en charge, et -fa on la force.
  • vLLM. --gpu-memory-utilization (0.9 par défaut) est la part de la mémoire totale de la carte que vLLM prend au démarrage pour les poids et le cache. Descendez à 0.8 si le démarrage échoue parce qu’autre chose utilise la carte. Si vLLM indique que le max seq len du modèle dépasse ce que le KV cache peut stocker, montez à 0.95 ou fixez --max-model-len 32768. --kv-cache-dtype fp8 divise le cache par deux, --max-num-seqs plafonne les requêtes parallèles, --enforce-eager économise la mémoire des CUDA graphs au prix d’un peu de vitesse, et --tensor-parallel-size 2 répartit le modèle sur deux cartes. Le modèle vLLM vous donne une API compatible OpenAI pour essayer ces réglages.
  • Quantifiez les poids. Un checkpoint AWQ ou GPTQ en 4 bits ramène les poids à environ un quart de leur taille en 16 bits. Le FP8 les divise par deux et tourne nativement sur les cartes Ada, Hopper et Blackwell.

Entraînement : réduire le lot, les activations et l’optimiseur

Un fine-tuning complet avec AdamW en précision mixte demande environ 16 octets par paramètre avant les activations : 2 pour les poids, 2 pour les gradients, 4 pour une copie maîtresse en 32 bits et 8 pour les états de l’optimiseur. Un modèle 7B représente donc environ 112 Go, plus que n’importe quelle carte seule hormis la H200 et la B200. Les solutions, à peu près dans l’ordre du gain obtenu pour le moindre coût :

  1. Un lot plus petit, à lot effectif égal. Une taille de lot de 2 avec 8 étapes d’accumulation de gradient s’entraîne comme un lot de 16.
  2. Le gradient checkpointing. Les activations sont recalculées pendant la rétropropagation au lieu d’être stockées. On économise une grande partie de la mémoire d’activation, pour 20 à 30 % de vitesse en moins. Dans Hugging Face : gradient_checkpointing=True.
  3. La précision mixte BF16, sur toute carte à partir d’Ampere.
  4. Les optimiseurs 8 bits. AdamW8bit de bitsandbytes (optim="adamw_bnb_8bit") fait passer les états de l’optimiseur de 8 octets par paramètre à environ 2.
  5. LoRA ou QLoRA au lieu d’un fine-tuning complet. Vous entraînez de petits adaptateurs ; QLoRA charge le modèle de base en 4 bits. Un modèle 8B s’entraîne en QLoRA avec 10 à 16 Go ; un modèle 70B demande environ 48 Go et est à l’aise sur 80 Go.
  6. Des séquences plus courtes ou une résolution plus basse. Pour une LoRA Flux, entraînez d’abord en 512 à 768 px et mettez en cache les latents et les embeddings de texte.
  7. Plusieurs cartes. FSDP ou DeepSpeed ZeRO répartissent poids, gradients et états de l’optimiseur entre les GPU.

Si le plantage survient après des centaines d’étapes plutôt qu’immédiatement, cherchez une fuite : total_loss += loss garde tout le graphe en vie, total_loss += loss.item() non. Une évaluation sans torch.no_grad() a le même effet.

Fragmentation : PYTORCH_CUDA_ALLOC_CONF

Quand l’erreur affiche des gigaoctets « reserved but unallocated », la mémoire est bien là, mais morcelée en blocs trop petits pour la demande. Cela arrive surtout quand les formes changent : tailles d’image différentes, longueurs de séquence variables, ou modèles chargés et déchargés à tour de rôle. Définissez ceci avant le démarrage de Python :

export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

Dans un notebook, mettez os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True" dans la première cellule, avant import torch. Les versions récentes de PyTorch lisent aussi le même réglage sous le nom PYTORCH_ALLOC_CONF. Sur les versions plus anciennes, max_split_size_mb:128 est l’alternative. Ce réglage ne crée pas de mémoire : il vous permet seulement d’utiliser celle qui est libre.

Pour dimensionner votre tâche, mesurez le pic au lieu de deviner : torch.cuda.max_memory_allocated() après une étape complète ou une image, et torch.cuda.memory_summary() pour le détail.

Quand arrêter les réglages et prendre une carte plus grande

Passez à la taille au-dessus quand la solution vous coûte en qualité (descendre du FP8 au Q4), en vitesse (déchargement vers le CPU) ou en temps passé plus que la différence de prix. Pour comparer, une heure coûte à partir de 0,59 € sur une RTX 4090 de 24 Go, 0,76 € sur une RTX 5090 de 32 Go, 1,06 € sur une L40S de 48 Go et 3,90 € sur une H100 de 80 Go.

Ce qui manque toujours de mémoire Taille de carte qui convient
Flux dev en 16 bits, ou Flux avec plusieurs LoRA et ControlNet 24 à 32 Go
Wan 2.2 14B en 720p sans déchargement 32 Go pour des clips courts, 48 Go pour avoir de la marge
Modèle 32B avec 32 000 tokens de contexte ou plus, ou plusieurs utilisateurs 48 à 80 Go
Modèle 70B en 4 bits 48 Go avec un contexte normal, 80 Go pour un long contexte ou du service
70B en FP8 80 à 96 Go avec un contexte court, 141 Go ou deux cartes pour un long contexte
Fine-tuning complet d’un modèle 7B ou 8B 80 Go et plus, ou plusieurs cartes (en QLoRA, 16 à 24 Go suffisent)

Le sélecteur de VRAM montre quelles cartes conviennent à votre modèle et ce qu’elles coûtent maintenant ; le guide combien de VRAM vous faut-il donne le tableau complet par modèle. Un test rapide sur la carte plus grande ne coûte que 15 minutes à son tarif, et si vous enregistrez /workspace à l’arrêt, il est restauré sur le serveur suivant, même si celui-ci a une autre carte.

Questions sur ce sujet

Pourquoi nvidia-smi affiche-t-il une mémoire presque pleine alors que mon script ne fait rien ?

PyTorch garde la mémoire libérée en réserve pour la réutiliser : elle reste donc comptée comme utilisée. vLLM prend aussi volontairement environ 90 % de la carte au démarrage. Si aucune de ces raisons ne s’applique, un ancien noyau Jupyter ou un processus planté retient encore un modèle.

Pourquoi mon LLM se charge-t-il sans problème puis plante-t-il dans une longue conversation ?

Le KV cache grossit à chaque token de contexte et avec chaque utilisateur en parallèle. Un modèle qui tient avec un chat de 4 000 tokens peut manquer de mémoire à 30 000 tokens. Limitez la longueur du contexte ou quantifiez le cache.

Deux GPU règlent-ils un CUDA out of memory ?

Pour les modèles de langage, généralement oui : vLLM, llama.cpp et Ollama savent répartir un modèle sur plusieurs cartes. Les modèles d’image et de vidéo de ComfyUI doivent en général tenir sur une seule carte : pour eux, la solution est une carte avec plus de mémoire.

Le déchargement vers le CPU ou --lowvram est-il une vraie solution ?

Cela permet à la tâche de tourner, souvent plusieurs fois plus lentement. Pour un usage ponctuel, c’est acceptable. Pour un travail régulier, une carte où le modèle tient revient généralement moins cher par résultat.

Trouvez le GPU qui convient à votre modèle

Choisissez un modèle et voyez la carte la moins chère avec assez de VRAM, facturée à la minute en euros.