L'usine à calcul — comprendre quand un GPU sert, quand il ne sert à rien, et comment le brancher à vos conteneurs avec --gpus. The compute factory — understanding when a GPU helps, when it is useless, and how to plug it into your containers with --gpus.
Le CPU, c'est quelques artisans géniaux : peu de cœurs, très rapides, capables de tout faire. Le GPU, c'est une usine de milliers d'ouvriers simples : le même geste, en même temps, sur des données différentes. Toute la question du bonus tient là : votre calcul est-il un travail d'artisan ou un travail d'usine ? The CPU is a few brilliant craftsmen: few cores, very fast, able to do anything. The GPU is a factory of thousands of simple workers: the same move, at the same time, on different data. The whole bonus fits in one question: is your computation a craftsman's job or a factory job?
Notre régression logistique s'entraîne en 2 secondes sur CPU : un GPU n'y changerait rien, sauf la facture. Réclamer une usine pour visser une étagère n'impressionne personne. Mais quatre situations la rendent indispensable : Our logistic regression trains in 2 seconds on CPU: a GPU would change nothing, except the bill. Demanding a factory to screw in a shelf impresses nobody. But four situations make it essential:
Le GPU est un outil, pas un trophée. Mesurez avant de payer : un chrono CPU, un chrono GPU, et la décision se prend en euros — comme toutes les décisions de la semaine. The GPU is a tool, not a trophy. Measure before you pay: one CPU timer, one GPU timer, and the decision is made in euros — like every decision this week.
Par défaut, Docker isole — c'est son métier. Le GPU est un périphérique de l'hôte : sans pont explicite, torch.cuda.is_available() répond False dans le conteneur. Le pont officiel s'appelle le NVIDIA Container Toolkit.
By default, Docker isolates — that's its job. The GPU is a host device: without an explicit bridge, torch.cuda.is_available() answers False inside the container. The official bridge is the NVIDIA Container Toolkit.
--gpus '"device=0"' choisit une carte précise — le réflexe sur machine partagée.One flag, and the factory opens. --gpus '"device=0"' picks one specific card — the reflex on a shared machine.Deux missions sur la machine GPU partagée. Les durées viennent du plan de cours : Two missions on the shared GPU machine. Durations come straight from the course plan:
--gpus all, prouver que la carte est visible : nvidia-smi depuis l'intérieur, torch.cuda.is_available() → TruePlug in the factory — install the NVIDIA Container Toolkit, run a container with --gpus all, prove the card is visible: nvidia-smi from the inside, torch.cuda.is_available() → Truenvidia/cuda:12.4.1-runtime-ubuntu22.04, entraînement chronométré CPU puis GPU sur un petit réseau, et sur la régression logistique de la fraude : un tableau comparatif commitéThe race, for real — image on a nvidia/cuda:12.4.1-runtime-ubuntu22.04 base, timed CPU then GPU training on a small network, and on the fraud project's logistic regression: a comparison table, committedLa capture de nvidia-smi exécuté dans un conteneur, et un tableau de temps CPU vs GPU avec votre conclusion en une phrase honnête. Attendu : ~20× sur le réseau, quasi rien sur la fraude — et c'est exactement le message.
The output of nvidia-smi run inside a container, and a CPU vs GPU timing table with your conclusion in one honest sentence. Expected: ~20× on the network, next to nothing on the fraud model — and that is exactly the message.
Ce guide reprend les deux missions du lab, commande par commande. Préambule honnête : il vous faut une machine Linux (ou Windows + WSL2) avec un GPU NVIDIA et Docker — la machine partagée de la formation, un PC de jeu, ou une instance cloud GPU. Sans carte NVIDIA (Mac inclus), lisez simplement les étapes : le résultat attendu est donné à chaque point de contrôle, et c'est le raisonnement qui compte. Placez-vous dans le dépôt fraud-detection/.
This guide replays the lab's two missions, command by command. Honest preamble: you need a Linux machine (or Windows + WSL2) with an NVIDIA GPU and Docker — the training's shared machine, a gaming PC, or a cloud GPU instance. Without an NVIDIA card (Macs included), simply read through the steps: the expected result is given at every checkpoint, and the reasoning is what matters. Work from the fraud-detection/ repo.
Le driver est le contremaître : il vit sur l'hôte, et lui seul parle à la carte. Rien d'autre ne marchera tant que cette commande ne répond pas. The driver is the foreman: it lives on the host, and it alone talks to the card. Nothing else will work until this command answers.
nvidia-smi
Le pont officiel entre Docker et la carte — installé une fois par machine, jamais dans l'image. Ce sont les commandes officielles pour Ubuntu / Debian. The official bridge between Docker and the card — installed once per machine, never inside the image. These are the official commands for Ubuntu / Debian.
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
nvidia-ctk --version
Le toolkit est installé, mais Docker ne le connaît pas encore : une commande de configuration, un redémarrage du démon, et le drapeau --gpus devient disponible.
The toolkit is installed, but Docker does not know it yet: one configuration command, one daemon restart, and the --gpus flag becomes available.
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
docker info | grep -i runtimes
Le moment de vérité : un conteneur CUDA officiel, le drapeau --gpus all, et nvidia-smi exécuté depuis l'intérieur. Sur machine partagée, le réflexe est --gpus '"device=0"' pour ne prendre qu'une carte.
The moment of truth: an official CUDA container, the --gpus all flag, and nvidia-smi executed from the inside. On a shared machine, the reflex is --gpus '"device=0"' to claim a single card.
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
Une phrase suffit : -runtime sait exécuter du CUDA, -devel sait le compiler — et pèse trois fois plus. Sauf besoin explicite de compilation, prenez runtime. Vérifiez-le sur la balance :
One sentence is enough: -runtime can run CUDA, -devel can compile it — and weighs three times as much. Unless you explicitly need to compile, pick runtime. Check it on the scale:
docker pull nvidia/cuda:12.4.1-runtime-ubuntu22.04
docker pull nvidia/cuda:12.4.1-devel-ubuntu22.04
docker images nvidia/cuda
Le fichier entier, à la racine du dépôt : une multiplication de matrices 4096 × 4096 chronométrée sur CPU, puis sur GPU si la carte est visible. Le synchronize() est essentiel — sans lui, on chronomètre le lancement du calcul, pas le calcul.
The whole file, at the repo root: a 4096 × 4096 matrix multiplication timed on CPU, then on GPU if the card is visible. The synchronize() is essential — without it you time the launch of the computation, not the computation.
"""Time a 4096x4096 matmul on CPU, then on GPU if available."""
import time
import torch
SIZE = 4096
ROUNDS = 10
def bench(device):
a = torch.randn(SIZE, SIZE, device=device)
b = torch.randn(SIZE, SIZE, device=device)
torch.matmul(a, b) # warmup
if device == "cuda":
torch.cuda.synchronize()
start = time.perf_counter()
for _ in range(ROUNDS):
torch.matmul(a, b)
if device == "cuda":
torch.cuda.synchronize()
return (time.perf_counter() - start) / ROUNDS
cpu_time = bench("cpu")
print(f"cpu: {cpu_time * 1000:.1f} ms per matmul")
if torch.cuda.is_available():
gpu_time = bench("cuda")
print(f"cuda: {gpu_time * 1000:.1f} ms per matmul")
print(f"speedup: x{cpu_time / gpu_time:.1f}")
else:
print("cuda not available in this container")
Même image, même script, un seul drapeau de différence. Et le rappel honnête : sur la régression logistique de la fraude (2 s de CPU au total), ce gain n'existe pas — aucune matrice géante à paralléliser. Mesurez, puis décidez en euros. Same image, same script, one flag of difference. And the honest reminder: on the fraud project's logistic regression (2 s of CPU in total), this gain does not exist — no giant matrix to parallelize. Measure, then decide in euros.
docker run --rm -v "$PWD":/work -w /work pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime python bench.py
docker run --rm --gpus all -v "$PWD":/work -w /work pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime python bench.py
« could not select device driver "nvidia" » — le toolkit n'est pas déclaré auprès de Docker : rejouez nvidia-ctk runtime configure --runtime=docker puis systemctl restart docker (étape 3). « CUDA driver version is insufficient » — l'image demande un CUDA plus récent que votre driver : mettez le driver à jour, ou prenez une image CUDA plus ancienne — le driver de l'hôte doit toujours être au niveau du CUDA de l'image. Une image de 8 Go — vous avez tiré -devel : préférez -runtime (l'étape 5 montre l'écart), et les réflexes du bloc 4 valent triple ici. WSL2 — le driver s'installe côté Windows, jamais dans WSL ; nvidia-smi doit répondre dans WSL avant de toucher Docker, et Docker Desktop doit avoir l'intégration WSL2 activée. "could not select device driver "nvidia"" — the toolkit is not registered with Docker: rerun nvidia-ctk runtime configure --runtime=docker then systemctl restart docker (step 3). "CUDA driver version is insufficient" — the image asks for a newer CUDA than your driver: update the driver, or pick an older CUDA image — the host driver must always match the image's CUDA level. An 8 GB image — you pulled -devel: prefer -runtime (step 5 shows the gap), and block 4's reflexes are worth triple here. WSL2 — the driver installs on the Windows side, never inside WSL; nvidia-smi must answer inside WSL before you touch Docker, and Docker Desktop must have WSL2 integration enabled.