GPUcloud

Guide GPU

CUDA out of memory : causes, correctifs, et quand passer à un GPU avec plus de VRAM

Mis à jour le

Réponse courte

Essaie d’abord de réduire la taille du batch, puis la précision mixte, le gradient checkpointing et la quantification : ces correctifs règlent souvent l’erreur sans changer de carte. Si le modèle ne tient toujours pas, loue plus de VRAM chez GPU Cloud, au Canada : 48 Go dès 0,67 $ CA/h, 80 Go dès 1,81 $ CA/h, 96 Go dès 2,48 $ CA/h.

Ce que veut dire l’erreur

torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate … veut dire que PyTorch demande plus de mémoire que ce qui reste libre sur la carte. Cette mémoire sert aux poids du modèle, aux gradients, à l’état de l’optimiseur et aux activations, qui grandissent avec la taille du batch et la longueur des séquences.

Avant de corriger, mesure : la ligne « pic » montre combien ton entraînement demande vraiment.

import torch

print(torch.cuda.get_device_name(0))
print(f"total : {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")
print(f"pic   : {torch.cuda.max_memory_allocated() / 1e9:.1f} GB")
print(torch.cuda.memory_summary(abbreviated=True))

Les correctifs, dans l’ordre

  1. 1.Réduis la taille du batch

    Divise batch_size par deux jusqu’à ce que l’erreur disparaisse. Pour garder le même batch effectif, accumule les gradients sur plusieurs pas.

    accumulation_steps = 4  # batch effectif = batch_size x 4
    
    optimizer.zero_grad()
    for step, (inputs, targets) in enumerate(loader):
        loss = criterion(model(inputs), targets) / accumulation_steps
        loss.backward()
        if (step + 1) % accumulation_steps == 0:
            optimizer.step()
            optimizer.zero_grad()
  2. 2.Passe en précision mixte

    Les activations en 16 bits prennent environ la moitié de la mémoire du 32 bits. torch.autocast choisit la précision opération par opération.

    import torch
    
    # bf16 si la carte le permet, sinon fp16 avec un GradScaler
    dtype = torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16
    scaler = torch.amp.GradScaler("cuda", enabled=(dtype == torch.float16))
    
    for inputs, targets in loader:
        optimizer.zero_grad()
        with torch.autocast(device_type="cuda", dtype=dtype):
            loss = criterion(model(inputs), targets)
        scaler.scale(loss).backward()
        scaler.step(optimizer)
        scaler.update()
  3. 3.Active le gradient checkpointing

    Les activations intermédiaires sont recalculées pendant la rétropropagation au lieu d’être gardées en mémoire : moins de VRAM, un peu plus de calcul.

    # Modèle Hugging Face Transformers
    model.gradient_checkpointing_enable()
    
    # Module PyTorch maison
    from torch.utils.checkpoint import checkpoint
    
    def forward(self, x):
        x = checkpoint(self.block1, x, use_reentrant=False)
        return self.block2(x)
  4. 4.Quantifie le modèle

    Pour l’inférence ou un ajustement QLoRA, charger les poids en 4 bits divise leur taille par quatre par rapport au 16 bits.

    # pip install transformers accelerate bitsandbytes
    import torch
    from transformers import AutoModelForCausalLM, BitsAndBytesConfig
    
    quantization = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.bfloat16,
    )
    model = AutoModelForCausalLM.from_pretrained(
        "Qwen/Qwen2.5-7B-Instruct",
        quantization_config=quantization,
        device_map="auto",
    )
  5. 5.En inférence, coupe le calcul des gradients

    Sans torch.inference_mode(), PyTorch garde ce qu’il faut pour une rétropropagation qui n’arrivera jamais.

    model.eval()
    with torch.inference_mode():
        outputs = model(inputs)
  6. 6.Limite la fragmentation

    Si le message indique beaucoup de mémoire « reserved but unallocated », laisse l’allocateur agrandir ses segments.

    PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True python train.py

Combien de VRAM prennent les poids d’un modèle

Mémoire occupée par les poids seuls, selon la précision
Taille du modèle16 bits (fp16, bf16)8 bits4 bits
7 milliards de paramètres14 Go7 Go3,5 Go
8 milliards de paramètres16 Go8 Go4 Go
13 milliards de paramètres26 Go13 Go6,5 Go
34 milliards de paramètres68 Go34 Go17 Go
70 milliards de paramètres140 Go70 Go35 Go

Calcul : nombre de paramètres × octets par paramètre. C’est un minimum : les activations, le cache KV, les gradients et l’état de l’optimiseur s’y ajoutent, et un entraînement complet demande plusieurs fois la taille des poids.

Exemple : un modèle de 7 milliards de paramètres occupe 14 Go en 16 bits, 7 Go en 8 bits et 3,5 Go en 4 bits, avant les activations et le reste.

Quand passer à un GPU avec plus de VRAM

Si ton modèle ne tient toujours pas après ces correctifs, ou si la quantification dégrade trop les résultats, il te faut plus de mémoire. Chez GPU Cloud, la plus petite carte a 48 Go, et un serveur peut aller jusqu’à 8 GPU, soit 768 Go au total (8 × NVIDIA RTX PRO 6000).

Mémoire par GPU chez GPU Cloud, et prix d’un serveur à 1 GPU
Mémoire par GPUGPUÀ la demande, par heureSpot, par heure
48 GoNVIDIA RTX A60000,67 $0,54 $
48 GoNVIDIA L401,34 $1,07 $
80 GoNVIDIA A100 PCIe1,81 $1,45 $
80 GoNVIDIA H100 PCIe3,35 $2,68 $
96 GoNVIDIA RTX PRO 60002,48 $1,98 $

Prix en dollars canadiens, taxes en sus, lus dans le catalogue au moment de la publication de la page.

Avec plusieurs GPU, le modèle doit être réparti entre les cartes (par exemple device_map="auto" avec Transformers, ou FSDP pour l’entraînement). Le guide pour lancer ton script sur un GPU montre comment copier ton projet et lancer l’entraînement sur le serveur.

Ce qu’il faut savoir avant de lancer

  • La facturation se fait à l’heure, au tarif horaire du serveur, à partir d’un crédit prépayé. Il n’y a pas de facturation à la minute, et la première heure est prélevée au déploiement.
  • Un serveur arrêté reste facturé au plein tarif horaire. Pour payer moins, hiberne-le (0,02 $ par heure (environ 14,60 $ par mois), disque conservé) ou supprime-le. Une machine Spot ne s’hiberne pas : supprime-la quand tu as fini.
  • La recharge minimale est de 25,00 $ CA, payée par carte de crédit.
  • Les serveurs et leurs disques restent au Canada (région canada-montreal, à Montréal). Les renseignements du compte (identité, facturation, courriels) peuvent être traités hors du Québec, comme l’explique la politique de confidentialité.

Questions fréquentes

Pourquoi CUDA out of memory alors que nvidia-smi montre de la mémoire libre ?

PyTorch garde en réserve la mémoire qu’il a déjà allouée, et cette réserve peut être fragmentée : une grosse demande échoue même s’il reste de petits blocs libres. Un autre processus peut aussi occuper la carte. expandable_segments:True limite la fragmentation.

Est-ce que torch.cuda.empty_cache() règle l’erreur ?

Rarement. Il rend au système la mémoire en réserve que plus aucun tenseur n’utilise, mais il ne libère pas les tenseurs encore référencés par ton code.

Combien de VRAM faut-il pour un modèle de 7 milliards de paramètres ?

Les poids seuls occupent 14 Go en 16 bits, 7 Go en 8 bits et 3,5 Go en 4 bits. Il faut ajouter les activations et le cache KV en inférence, et les gradients et l’état de l’optimiseur en entraînement.

Quelle est la plus grande quantité de VRAM disponible chez GPU Cloud ?

Par GPU, 96 Go. Par serveur, jusqu’à 8 GPU, soit 768 Go au total (8 × NVIDIA RTX PRO 6000).

Combien coûte une heure avec plus de VRAM ?

48 Go : dès 0,67 $ CA/h ; 80 Go : dès 1,81 $ CA/h ; 96 Go : dès 2,48 $ CA/h, en dollars canadiens, taxes en sus, facturé à l’heure sans engagement.

Tu veux du GPU ? On est là.

Lance un serveur GPU NVIDIA à l’heure au Canada, payé en dollars canadiens par carte de crédit, ou réserve un GPU pour une date précise.

Autres guides