Changer le thème

Planification GPU Ollama et gestion des ressources : optimisation VRAM, équilibrage multi-GPU

Easton editorial illustration: agentic retrieval reasoning table

Avec une carte 8 Go de VRAM, vous chargez enfin un modèle 13B, puis après quelques inférences tout plante — l’écran affiche « CUDA out of memory ».

Ou vous avez investi dans deux GPU, convaincu de pouvoir enfin faire tourner de gros modèles, et nvidia-smi ne montre qu’une carte au travail pendant que l’autre reste inactive.

Au début avec Ollama, j’ai tombé dans ces pièges : VRAM insuffisante, multi-GPU inutilisé, vitesse d’inférence irrégulière. En creusant, j’ai compris la logique de planification GPU d’Ollama : ce n’est pas « configurer et oublier », il faut saisir ce que signifient les paramètres.

Cet article rassemble ces apprentissages pour répondre à des questions concrètes :

  • Faire tourner un 13B de façon stable sur 8 Go de VRAM (sans OOM surprise)
  • Configurer le multi-GPU pour qu’il serve vraiment (schéma d’équilibrage complet)
  • Quels paramètres ajuster quand la VRAM manque (ordre de priorité)
  • Ce qu’est l’offloading GPU (mécanisme llama.cpp sous le capot)

Prérequis : article assez technique ; une base GPU, CUDA et Ollama est utile. Si vous débutez, lisez d’abord les articles précédents de la série (surtout le n°6 sur l’optimisation des performances), puis revenez ici.

1. Gestion de la mémoire GPU : configuration des paramètres

La planification GPU d’Ollama repose sur quelques paramètres qui répartissent les couches entre GPU et CPU. Les maîtriser explique les OOM « alors que ça devrait passer » ou les ralentissements inexpliqués.

1.1 Paramètres clés

ParamètreRôleValeur par défautQuand ajuster
num_gpuNombre de couches exécutées sur le GPUDétection autoRéduire si VRAM insuffisante
main_gpuIndex du GPU principal0Multi-GPU : choisir la carte
low_vramMode faible VRAMfalseRecommandé sous 8 Go
num_batchTaille du batch512Réduire à 256 si VRAM serrée
num_ctxLongueur de contexte40962048 pour dialogues courts

num_gpu prête à confusion : ce n’est pas le nombre de cartes, mais le nombre de couches du modèle calculées sur le GPU.

Exemple : Llama 2 7B a 32 couches. num_gpu: 32 = tout sur GPU. Avec num_gpu: 20, 20 couches sur GPU et 12 sur CPU — la vitesse baisse.

Avec low_vram, Ollama applique des astuces (ex. cache KV en RAM CPU plutôt qu’en VRAM). L’inférence ralentit un peu, mais le service tient.

1.2 Flux d’allocation VRAM

Au chargement :

  1. Détection : VRAM libre disponible
  2. Calcul des couches : combien de couches tiennent sur le GPU selon la taille du modèle
  3. Cache KV : espace réservé pour l’inférence (consomme aussi de la VRAM)
  4. Inférence : occupation dynamique, avec variations

Le point sensible est l’étape 2 : l’auto peut se tromper quand la VRAM est « juste assez » (8 Go + 13B). Là, fixez num_gpu à la main.

Pour voir l’offloading actuel :

ollama run llama3 --verbose

Une ligne du type llama_model_load: model loaded - layers: 40/40 on GPU indique 40 couches sur GPU.

1.3 Moteur llama.cpp

Ollama s’appuie sur llama.cpp. Comprendre l’offloading GPU clarifie pourquoi certains réglages changent peu.

Décision d’offloading

VRAM disponible = VRAM totale GPU - réserve système (quelques centaines de Mo)
taille par couche = paramètres du modèle / nombre de couches
couches possibles = min(couches totales, VRAM disponible / taille par couche)

Piège : le calcul ne compte souvent que le modèle, pas le cache KV, qui grossit avec la conversation. D’où chargement OK puis OOM après quelques tours.

75%
Économie VRAM avec quantification Q4
Source: Comparaison mesurée : FP16 → Q4_K_M

Architecture hybride

GPU et CPU ne se partagent pas tout :

  • GPU : produits matriciels, attention (charge lourde)
  • CPU : embedding, normalisation (charge légère)
  • Transferts : aller-retour GPU↔CPU à chaque frontière de couche

Offloading partiel = latence de transfert à chaque couche — d’où un ralentissement net.

mmap

llama.cpp charge souvent le fichier modèle en mmap :

  • pas besoin de tout charger en RAM ; pages à la demande
  • plusieurs processus peuvent partager la même image
  • empreinte mémoire réduite

Pour désactiver mmap (cas particuliers) :

PARAMETER use_mmap false

2. Multi-GPU : architecture d’équilibrage

Avec deux GPU ou plus, la question est : comment Ollama les utilise-t-il tous ?

Fait important : Ollama ne supporte pas le parallélisme de modèle. Vous ne pouvez pas couper un modèle en deux moitiés sur GPU 0 et GPU 1. Une instance = une carte.

Le multi-GPU reste utile pour :

  1. Instances de modèles différents : GPU 0 = llama3, GPU 1 = mistral
  2. Plusieurs instances du même modèle : débit via équilibrage

2.1 Instance unique, plusieurs GPU (limites)

Reconnaître plusieurs GPU :

# Limiter Ollama aux GPU 0 et 1
CUDA_VISIBLE_DEVICES=0,1 ollama serve

Par défaut, le modèle va sur GPU 0 ; GPU 1 reste souvent inactif. main_gpu choisit la carte principale :

# Modelfile
FROM llama3
PARAMETER main_gpu 1  # GPU principal = carte 1

En pratique, vous changez surtout de carte — vous n’exploitez pas vraiment les deux en parallèle.

2.2 Plusieurs instances + équilibrage (recommandé)

La voie efficace : une instance Ollama par GPU, puis un répartiteur.

┌─────────┐
│ Client  │  requêtes d'inférence
└────┬────┘

┌────▼────────────────────┐
│ Nginx (équilibrage)      │  stratégie least_conn
│ Port: 8080              │
└────┬─────────┬──────────┘
     │         │
┌────▼───┐ ┌──▼────┐
│Ollama 1│ │Ollama 2│
│GPU 0   │ │GPU 1   │  une carte par instance
│Port    │ │Port    │
│11434   │ │11435   │
└────────┘ └────────┘

Étape 1 : démarrer les instances

# Instance 1 — GPU 0, port 11434
CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &

# Instance 2 — GPU 1, port 11435
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &

Les deux instances peuvent partager ~/.ollama : le mmap permet le partage du fichier modèle.

Étape 2 : Nginx

# /etc/nginx/conf.d/ollama.conf
upstream ollama_cluster {
    least_conn;  # connexions les plus faibles en priorité
    server 127.0.0.1:11434;
    server 127.0.0.1:11435;
}

server {
    listen 8080;

    location / {
        proxy_pass http://ollama_cluster;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # réponse en flux
        proxy_buffering off;
        proxy_cache off;
    }
}

least_conn envoie chaque requête vers l’instance avec le moins de connexions actives.

Étape 3 : client

# via Nginx (répartition automatique)
curl http://localhost:8080/api/generate -d '{
  "model": "llama3",
  "prompt": "Bonjour"
}'

Ou rediriger le client Ollama :

export OLLAMA_HOST=http://localhost:8080
ollama run llama3

2.3 Comparaison des stratégies

StratégiePrincipeCas d’usage
Round-robin (défaut)tour à toursimple, modèles homogènes
least_conninstance la plus librerecommandé pour l’inférence
IP Hashmême IP → même instancesession persistante

L’inférence a une durée variable (secondes à minutes). Le round-robin peut surcharger une instance. least_conn lisse la charge.

Avec bascule si une instance tombe :

upstream ollama_cluster {
    least_conn;
    server 127.0.0.1:11434 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:11435 max_fails=3 fail_timeout=30s;
}

Après 3 échecs consécutifs, Nginx retire l’instance 30 secondes.

3. Optimisation VRAM : quantification, contexte, batch

Ordre de priorité quand la VRAM manque : quantification > contexte > batch > couches GPU.

La quantification change le plus : Q4 vs FP16 ≈ −75 % de VRAM. Réduire num_gpu déplace le calcul vers le CPU : VRAM gagnée, vitesse perdue.

3.1 Niveau de quantification

Moins de bits par paramètre : FP16 = 16 bits, Q4 = 4 bits. Légère perte de précision ; en pratique Q4 ≈ 2–3 % sur la plupart des tâches.

QuantificationVRAM (vs FP16)PerteUsage
Q4_K_M~25 %2-3 %recommandé : bon compromis
Q5_K_M~33 %1-2 %précision un peu plus haute
Q8_0~50 %~0,5 %proche du FP16
FP16100 %aucunerecherche, benchmarks

Référence Llama 2 13B :

  • FP16 : ~26 Go
  • Q4_K_M : ~8 Go
  • Q8_0 : ~13 Go

8 Go + 13B Q4 tient à peine ; le cache KV fait souvent déborder en inférence.

Usage quotidien : Q4_K_M. Traduction, code : Q5_K_M ou Q8_0.

# Q4 (souvent par défaut)
ollama pull llama3

# Q8
ollama pull llama3:8b-q8_0

3.2 Longueur de contexte

Le cache KV stocke l’historique. Sa taille suit num_ctx.

Formule simplifiée :

VRAM cache KV ≈ num_ctx × num_layers × hidden_dim × 2 octets

Ex. Llama 2 7B : 32 couches, hidden_dim 4096, num_ctx 4096 → ~2 Go de cache KV. À 8192, ~4 Go. Doubler ctx double le cache KV.

Stratégies :

  1. Dialogues courts : num_ctx: 2048 — moitié de cache KV, suffisant pour Q&R simples
  2. Longs documents : éviter ctx=16000 d’un coup ; découper (chunking) par morceaux
FROM llama3
PARAMETER num_ctx 2048

Mythe : un petit ctx ne dégrade pas la qualité si la conversation est courte — 2048 et 4096 donnent le même résultat pour quelques tours.

3.3 Batch et concurrence

num_batch = tokens traités par passe (défaut 512). Batch plus grand = meilleure efficacité parallèle, pic VRAM plus haut.

FROM llama3
PARAMETER num_batch 256

512 → 256 : pic VRAM ~−20 %, vitesse un peu plus basse (moins brutal que moins de couches GPU).

Concurrence

Ollama traite souvent les requêtes en série. Plusieurs requêtes simultanées = file d’attente.

Options :

  1. Multi-instances (section 2) : une requête active par instance
  2. File applicative (Redis Queue, etc.) :
import redis
from queue import Queue

r = redis.Redis()
r.lpush('ollama_queue', request_data)

request = r.rpop('ollama_queue')
ollama.generate(request)

4. Cas pratiques : trois scénarios

4.1 Scénario 1 : 13B stable sur 8 Go

Problème

RTX 3060 8 Go, Llama 2 13B Q4 (~8 Go au chargement). Quelques inférences puis OOM — le cache KV sature la VRAM.

Solution

Réduire le cache KV + pic d’allocation :

FROM llama2:13b-q4

PARAMETER num_gpu 30      # 40 couches, 30 sur GPU
PARAMETER low_vram true   # cache KV en RAM CPU
PARAMETER num_ctx 2048    # contexte divisé par deux
PARAMETER num_batch 256   # pic VRAM plus bas

Occupation stable ~6 Go, ~2 Go de marge.

Résultat

6 Go
Occupation VRAM stable
Source: De 8 Go à 6 Go, plus d’OOM
  • VRAM : ~8 Go → ~6 Go stable
  • Débit : ~8 tokens/s (plus lent que full GPU, bien plus que CPU seul)
  • Stabilité : plus d’OOM

10 couches sur CPU = transferts à chaque frontière ; acceptable plutôt qu’un crash.

4.2 Scénario 2 : double GPU, débit API

Problème

Deux RTX 3090 24 Go, API Ollama publique. Une instance = file d’attente aux heures de pointe. nvidia-smi : une carte ~70 %+, l’autre ~20 %.

Solution

Script de cluster (voir section 2) :

#!/bin/bash
# start_ollama_cluster.sh

CUDA_VISIBLE_DEVICES=0 \
OLLAMA_HOST=127.0.0.1:11434 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama1.log 2>&1 &

CUDA_VISIBLE_DEVICES=1 \
OLLAMA_HOST=127.0.0.1:11435 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama2.log 2>&1 &

sleep 5
curl http://127.0.0.1:11434/api/pull -d '{"name": "llama3"}'
curl http://127.0.0.1:11435/api/pull -d '{"name": "llama3"}'

echo "Cluster Ollama démarré sur 11434 et 11435"

Nginx en least_conn.

Résultat

80%
Gain de débit
Source: Deux instances parallèles vs une instance série
  • Débit global : ~+80 % (parallèle vs série)
  • Utilisation GPU : ~40 % moyenne → ~80 % (les deux cartes actives)
  • Latence aux pics : ~−50 % (moins de file)

100 requêtes : ~10 min en mono-instance, ~5 min en cluster.

4.3 Scénario 3 : offloading automatique

Problème

Plusieurs tailles de modèles ; à chaque changement, réglage manuel de num_gpu. Oubli = crash.

Solution

Script qui adapte le Modelfile à la VRAM libre :

#!/bin/bash
# auto_offload.sh

GPU_MEM_FREE=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits | head -1)

declare -A MODEL_SIZES
MODEL_SIZES["llama3:8b-q4"]=5000
MODEL_SIZES["llama3:70b-q4"]=40000
MODEL_SIZES["mistral:7b-q4"]=4500

MODEL_NAME=$1

if [ -z "$MODEL_NAME" ]; then
    echo "Usage: $0 <model_name>"
    exit 1
fi

MODEL_SIZE=${MODEL_SIZES[$MODEL_NAME]}

if [ -z "$MODEL_SIZE" ]; then
    echo "Unknown model size for $MODEL_NAME"
    exit 1
fi

if [ $GPU_MEM_FREE -gt $MODEL_SIZE ]; then
    echo "Using full GPU offloading (enough memory)"
    cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu -1
PARAMETER low_vram false
EOF
else
    OFFLOAD_RATIO=$((GPU_MEM_FREE * 100 / MODEL_SIZE))
    echo "Using partial GPU offloading ($OFFLOAD_RATIO%)"
    cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu $OFFLOAD_RATIO
PARAMETER low_vram true
PARAMETER num_ctx 2048
EOF
fi

ollama create "${MODEL_NAME}-auto" -f /tmp/modelfile_temp
echo "Created ${MODEL_NAME}-auto with auto config"
./auto_offload.sh llama3:70b-q4

Effet : adaptation auto, moins d’erreurs de config, changement de modèle simplifié. Extensions possibles : bascule low_vram si VRAM chute, préchargement nocturne.

5. Bonnes pratiques et surveillance

5.1 Configurations par taille de VRAM

VRAMModèle conseilléQuantif.Couches GPUAutres
6 Go7BQ4partiel (~50 %)low_vram=true, ctx=2048
8 Go7BQ4full GPUctx=2048 (prudent)
8 Go13BQ4partiel (~75 %)low_vram=true, ctx=2048, batch=256
12 Go13BQ4full GPUctx=4096 possible
16 Go13BQ8 ou Q5full GPUctx=4096
16 Go70BQ4partiel (~50 %)low_vram=true
24 Go70BQ4full GPUctx=4096 possible
48 Go (bi-GPU)70BQ4full GPUmulti-instances + équilibrage

Estimations prudentes ; KV cache et réserve OS à prévoir. Dialogues longs → marge plus large.

5.2 Outils de surveillance

nvidia-smi -l 1

nvidia-smi --query-gpu=memory.used,memory.free --format=csv -l 1
ollama run llama3 --verbose

Cherchez GPU offloading: 40/40 layers, mmap, allocation KV.

#!/bin/bash
# monitor_gpu.sh

LOG_FILE="gpu_memory.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    GPU_MEM=$(nvidia-smi --query-gpu=memory.used,memory.free --format=csv,noheader)
    echo "$TIMESTAMP $GPU_MEM" >> $LOG_FILE
    sleep 5
done

5.3 Dépannage

OOM en inférence

  1. nvidia-smi — VRAM réellement saturée ?
  2. Config : Q4 ? ctx ≤ 2048 ? batch 256 ? trop de couches GPU ?
  3. Sinon low_vram=true

Priorité : quantification > ctx > batch > couches > low_vram

Inférence lente

ollama run your_model --verbose | grep "GPU offloading"

20/40 layers = moitié sur CPU, normal que ce soit lent. Solutions : plus de VRAM, moins de quantification (Q4→Q8), ou accepter le débit.

VRAM instable

Souvent le cache KV. Limiter num_ctx ou l’historique côté application (ex. 10 derniers tours).

Multi-GPU : une seule carte active

curl http://localhost:8080/api/tags

Vérifier least_conn, logs des instances, modèle préchargé sur les deux ports.

Résumé

  1. VRAM serrée → quantification d’abord : Q4 ≈ −75 % vs FP16, impact limité
  2. Surveiller le cache KV : lié à num_ctx et à la longueur du dialogue
  3. Multi-GPU → équilibrage : multi-instances + Nginx, pas le mode mono-instance multi-GPU
  4. llama.cpp : offloading = calcul par couches + coût des transferts

Config 8 Go stable :

PARAMETER num_gpu 30
PARAMETER low_vram true
PARAMETER num_ctx 2048
PARAMETER num_batch 256

Démarrage bi-GPU :

CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &

Pour aller plus loin : l’article 6 de la série couvre quantification et batch ; celui-ci approfondit le GPU. L’article 8 traitera le déploiement multi-modèles en parallèle.

Questions : Ollama GitHub Discussions ou commentaires sous l’article.


FAQ

Ollama peut-il répartir un modèle sur plusieurs GPU en parallèle ?
Non. Ollama ne prend pas en charge le parallélisme de modèle (tensor parallelism) : chaque instance ne peut être liée qu'à un seul GPU. Pour exploiter plusieurs GPU, lancez plusieurs instances + équilibrage Nginx.
Pourquoi l'inférence provoque-t-elle un OOM après quelques requêtes alors que le chargement réussit ?
À cause du cache KV. Au chargement, seule la VRAM du modèle est comptée ; pendant l'inférence, le cache KV grandit avec la conversation. Conseils :

• Réduire num_ctx
• Activer low_vram
• Raccourcir l'historique de dialogue
Quel paramètre ajuster en premier quand la VRAM manque ?
Priorité : quantification &gt; longueur de contexte &gt; batch &gt; couches GPU &gt; low_vram. La quantification a le plus d'impact : Q4 économise ~75 % de VRAM pour 2-3 % de perte.
num_gpu correspond-il au nombre de GPU que je possède ?
Non. num_gpu indique combien de couches du modèle sont calculées sur le GPU. Ex. : modèle 32 couches, num_gpu=32 = tout sur GPU ; num_gpu=20 = 20 sur GPU, 12 sur CPU.
Quelle stratégie d'équilibrage pour le multi-GPU ?
Recommandé : least_conn (connexions les plus faibles en priorité). La durée des requêtes d'inférence est imprévisible ; le round-robin peut saturer une instance et laisser l'autre inactive. least_conn envoie vers l'instance la plus libre.
Quelle taille de modèle avec 8 Go de VRAM ?
Configuration prudente :

• 7B Q4 : GPU complet, ctx=2048
• 13B Q4 : GPU partiel (~75 %), low_vram + ctx=2048 + batch=256
• Modèles plus grands : plus de VRAM ou offloading CPU

10 min de lecture · Publié le: 11 avr. 2026 · Mis à jour le: 27 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog