[bug] Lesson code is CUDA-only — no Apple Silicon (MPS) device path
Where
- Phase / lesson: Phase 0 ·
01-dev-environment(Step 6: GPU Setup) and03-gpu-setup-and-cloud, plus ~30 other lesson files across Phases 2, 3, 4, 10, and 19. - File / URL: Multiple — see the Affected files section below. Representative page:
lesson.html?path=phases/00-setup-and-tooling/01-dev-environment
What's wrong
GPU-related code throughout the curriculum is CUDA-only: device selection is written as "cuda" if torch.cuda.is_available() else "cpu", with no branch for Apple Silicon's MPS (Metal Performance Shaders) backend.
On an Apple Silicon Mac (M1–M4), torch.backends.mps.is_available() returns True and works — a 4096×4096 matmul runs on the GPU in ~120 ms. But because the lessons never check for mps, on these machines they:
- Silently fall back to CPU (training/inference runs many times slower than it should), or
- Report "No GPU" even though a usable GPU is present (e.g.
gpu_check.py), or - Hard-error when a device is passed explicitly (e.g. the gradient-clipping capstone rejects any device that isn't
"cpu"/"cuda").
This is an inconsistency, not a missing capability: a scan of the repo shows 197 files already reference mps, while 32 files use cuda with no mps branch. The correct pattern already exists in the codebase; these 32 files just don't follow it. Given that Apple Silicon is one of the most common laptop dev environments, the setup lessons (Phase 0) being CUDA-only is especially rough for newcomers — it's the first thing a Mac user hits.
Reproduce
- On an Apple Silicon Mac (macOS 12.3+) with PyTorch installed — confirm the GPU is real:
python3 -c "import torch; print(torch.backends.mps.is_available())"→True. - Run a GPU lesson, e.g.
python phases/04-computer-vision/04-image-classification/code/main.py. - Observe
deviceresolves tocpu(line 195:device = "cuda" if torch.cuda.is_available() else "cpu") — the available GPU is never used. - Or run
python phases/00-setup-and-tooling/03-gpu-setup-and-cloud/code/gpu_check.py→ prints "CUDA available: False" and exits, reporting no GPU despite MPS being available.
Concrete examples
| File | Line | Problem |
|---|---|---|
phases/00-setup-and-tooling/01-dev-environment/docs/en.md |
Step 6 | GPU snippet only shows nvidia-smi + CUDA install + torch.cuda.is_available(); no MPS equivalent. |
phases/00-setup-and-tooling/03-gpu-setup-and-cloud/code/gpu_check.py |
14–41 | Hard-codes .to("cuda") and torch.cuda.synchronize(); reports no GPU on Apple Silicon. |
phases/00-setup-and-tooling/01-dev-environment/code/verify.py |
19–20 | Only probes torch.cuda.is_available() / get_device_name(0). |
phases/03-deep-learning-core/11-intro-to-pytorch/code/pytorch_intro.py |
— | CUDA/CPU only device selection. |
phases/04-computer-vision/04-image-classification/code/main.py |
195 | device = "cuda" if torch.cuda.is_available() else "cpu". |
phases/19-capstone-projects/45-gradient-clipping-amp/code/main.py |
151–152 | Hard blocker: raise ValueError(f"device_type must be 'cpu' or 'cuda', got {device_type}") — cannot pass "mps" at all. |
Full list of the 32 CUDA-only files (use cuda, never mention mps):
00-setup-and-tooling/01-dev-environment/code/verify.py
00-setup-and-tooling/03-gpu-setup-and-cloud/code/gpu_check.py
00-setup-and-tooling/03-gpu-setup-and-cloud/docs/en.md
00-setup-and-tooling/06-python-environments/docs/en.md
00-setup-and-tooling/07-docker-for-ai/docs/en.md
00-setup-and-tooling/10-terminal-and-shell/docs/en.md
00-setup-and-tooling/11-linux-for-ai/docs/en.md
00-setup-and-tooling/12-debugging-and-profiling/code/debug_tools.py
00-setup-and-tooling/12-debugging-and-profiling/outputs/prompt-debug-ai-code.md
01-math-foundations/13-numerical-stability/outputs/prompt-numerical-debugger.md
02-ml-fundamentals/13-ml-pipelines/docs/en.md
03-deep-learning-core/11-intro-to-pytorch/code/pytorch_intro.py
03-deep-learning-core/11-intro-to-pytorch/outputs/skill-pytorch-patterns.md
03-deep-learning-core/12-intro-to-jax/docs/en.md
04-computer-vision/04-image-classification/code/main.py
04-computer-vision/04-image-classification/docs/en.md
04-computer-vision/05-transfer-learning/code/main.py
04-computer-vision/07-semantic-segmentation-unet/code/main.py
04-computer-vision/09-image-generation-gans/code/main.py
04-computer-vision/09-image-generation-gans/docs/en.md
04-computer-vision/10-image-generation-diffusion/code/main.py
04-computer-vision/11-stable-diffusion/code/main.py
04-computer-vision/11-stable-diffusion/docs/en.md
04-computer-vision/15-real-time-edge/code/main.py
04-computer-vision/15-real-time-edge/docs/en.md
04-computer-vision/16-vision-pipeline-capstone/code/main.py
04-computer-vision/23-diffusion-transformers-rectified-flow/docs/en.md
04-computer-vision/25-vision-language-models/docs/en.md
10-llms-from-scratch/34-gradient-checkpointing/docs/en.md
19-capstone-projects/45-gradient-clipping-amp/code/main.py
19-capstone-projects/45-gradient-clipping-amp/docs/en.md
19-capstone-projects/47-checkpoint-save-resume/outputs/skill-checkpoint-save-resume.mdSuggested fix
Adopt a single device-selection helper (cuda → mps → cpu) and reuse it everywhere, matching the pattern the other 197 files already use:
import torch
def get_device():
if torch.cuda.is_available():
return torch.device("cuda")
if torch.backends.mps.is_available():
return torch.device("mps")
return torch.device("cpu")Plus the supporting changes:
- Replace bare
torch.cuda.synchronize()/torch.cuda.empty_cache()with device-aware calls (torch.mps.synchronize()/torch.mps.empty_cache()on MPS), or guard them by device type. - In
45-gradient-clipping-amp, allow"mps"in thedevice_typevalidation (and note that AMP/GradScaleris CUDA-specific, so document the MPS path rather than silently failing). - In the Phase 0 docs (Step 6 +
03-gpu-setup-and-cloud), add an Apple Silicon section:torch.backends.mps.is_available(), the unified-memory note, and thePYTORCH_ENABLE_MPS_FALLBACK=1env var for ops MPS hasn't implemented yet. - Document the two MPS gotchas learners will hit: no
float64on MPS, and missing-op fallback.
Happy to open a PR implementing the shared helper + Phase 0 docs section if that's welcome.
Environment
- OS: macOS 15.7.1 (Apple M4, arm64)
- Runtime: Python 3.x, PyTorch 2.12.0 —
torch.backends.mps.is_built()andis_available()bothTrue - How run: local
Source: rohitg00/ai-engineering-from-scratch