Skill Tracer
Skills › Scientific Agent Skills › modal › gpu.md

gpu.md

203 lines · skills/modal/references/gpu.md at 5f2bc03

Open on GitHub
1# Modal GPU Compute
2
3Reviewed against SDK 1.6.0, the [GPU guide](https://modal.com/docs/guide/gpu),
4[multi-node guide](https://modal.com/docs/guide/multi-node-clusters) and
5[RTX PRO release](https://modal.com/blog/product-updates-rtx-pro-6000-command-k-sandbox-fs-api-and-more).
6GPU allocation and model workloads were not executed. A payment method is required.
7

Modal GPU Compute

Reviewed against SDK 1.6.0, the GPU guide, multi-node guide and RTX PRO release. GPU allocation and model workloads were not executed. A payment method is required.

Raw lines 1 to 7
8## Table of Contents
9
10- [Available GPUs](#available-gpus)
11- [Requesting GPUs](#requesting-gpus)
12- [GPU Selection Guide](#gpu-selection-guide)
13- [Multi-GPU](#multi-gpu)
14- [GPU Fallback Chains](#gpu-fallback-chains)
15- [Auto-Upgrades](#auto-upgrades)
16- [Multi-GPU Training](#multi-gpu-training)

Table of Contents

  • Available GPUs
  • Requesting GPUs
  • GPU Selection Guide
  • Multi-GPU
  • GPU Fallback Chains
  • Auto-Upgrades
  • Multi-GPU Training
Raw lines 8 to 17
18## Available GPUs
20| GPU | VRAM | Max per Container | Best For |
21|-----|------|-------------------|----------|
22| T4 | 16 GB | 8 | Budget inference, small models |
23| L4 | 24 GB | 8 | Inference, video processing |
24| A10 | 24 GB | 4 | Inference, fine-tuning small models |
25| L40S | 48 GB | 8 | Inference (best cost/perf), medium models |
26| A100-40GB | 40 GB | 8 | Training, large model inference |
27| A100-80GB | 80 GB | 8 | Training, large models |
28| RTX-PRO-6000 | 96 GB | Confirm workspace capacity | Rendering, inference |
29| H100 | 80 GB | 8 | Large-scale training, fast inference |
30| H200 | 141 GB | 8 | Very large models, training |
31| B200 | 192 GB | 8 | Largest models, maximum throughput |
32| B200+ | 192 or 288 GB | 8 | B200 or B300, B200 pricing |
33| B300 | 288 GB | 8 | Large models, CUDA 13.1+ |

Available GPUs

GPUVRAMMax per ContainerBest For
T416 GB8Budget inference, small models
L424 GB8Inference, video processing
A1024 GB4Inference, fine-tuning small models
L40S48 GB8Inference (best cost/perf), medium models
A100-40GB40 GB8Training, large model inference
A100-80GB80 GB8Training, large models
RTX-PRO-600096 GBConfirm workspace capacityRendering, inference
H10080 GB8Large-scale training, fast inference
H200141 GB8Very large models, training
B200192 GB8Largest models, maximum throughput
B200+192 or 288 GB8B200 or B300, B200 pricing
B300288 GB8Large models, CUDA 13.1+
Raw lines 18 to 34
35## Requesting GPUs

Requesting GPUs

Raw lines 35 to 36
37### Basic Request
39```python
40@app.function(gpu="H100")
41def train():
42 import torch
43 assert torch.cuda.is_available()
44 print(f"Using: {torch.cuda.get_device_name(0)}")
45```

Basic Request

@app.function(gpu="H100")
def train():
    import torch
    assert torch.cuda.is_available()
    print(f"Using: {torch.cuda.get_device_name(0)}")
Raw lines 37 to 46
47### String Shorthand
49```python
50gpu="T4" # Single T4
51gpu="A100-80GB" # Single A100 80GB
52gpu="H100:4" # Four H100s
53```

String Shorthand

gpu="T4"           # Single T4
gpu="A100-80GB"    # Single A100 80GB
gpu="H100:4"       # Four H100s
Raw lines 47 to 54
55### Case-Insensitive Strings
57GPU strings are case-insensitive, so `gpu="h100"` and `gpu="H100"` are equivalent.
59> **Deprecation:** The legacy `modal.gpu.*` objects (e.g. `modal.gpu.H100(count=2)`) are deprecated as of v0.73.31. Always configure GPUs with strings — use `gpu="H100:2"` for multiple GPUs and `gpu="A100-80GB"` for the 80 GB A100.

Case-Insensitive Strings

GPU strings are case-insensitive, so gpu="h100" and gpu="H100" are equivalent.

Deprecation: The legacy modal.gpu.* objects (e.g. modal.gpu.H100(count=2)) are deprecated as of v0.73.31. Always configure GPUs with strings — use gpu="H100:2" for multiple GPUs and gpu="A100-80GB" for the 80 GB A100.
Raw lines 55 to 60
61## GPU Selection Guide

GPU Selection Guide

Raw lines 61 to 62
63### For Inference
65These are starting points, not fit guarantees: account for precision/quantization,
66weights, activations, KV cache and batch/context length. A 70B BF16 model needs
67about 140 GB for weights alone and does not fit on one 80 GB H100.
69| Model Size | Recommended GPU | Why |
70|-----------|----------------|-----|
71| < 7B params | T4, L4 | Cost-effective, sufficient VRAM |
72| 7B-13B params | L40S | Best cost/performance, 48 GB VRAM |
73| 13B-70B params | A100-80GB, H100 | Large VRAM, fast memory bandwidth |
74| 70B+ params | H100:2+, H200, B200 | Multi-GPU or very large VRAM |

For Inference

These are starting points, not fit guarantees: account for precision/quantization, weights, activations, KV cache and batch/context length. A 70B BF16 model needs about 140 GB for weights alone and does not fit on one 80 GB H100.

Model SizeRecommended GPUWhy
< 7B paramsT4, L4Cost-effective, sufficient VRAM
7B-13B paramsL40SBest cost/performance, 48 GB VRAM
13B-70B paramsA100-80GB, H100Large VRAM, fast memory bandwidth
70B+ paramsH100:2+, H200, B200Multi-GPU or very large VRAM
Raw lines 63 to 75
76### For Training
78| Task | Recommended GPU |
79|------|----------------|
80| Fine-tuning (LoRA) | L40S, A100-40GB |
81| Full fine-tuning small models | A100-80GB |
82| Full fine-tuning large models | H100:4+, H200 |
83| Pre-training | H100:8, B200:8 |

For Training

TaskRecommended GPU
Fine-tuning (LoRA)L40S, A100-40GB
Full fine-tuning small modelsA100-80GB
Full fine-tuning large modelsH100:4+, H200
Pre-trainingH100:8, B200:8
Raw lines 76 to 84
85### General Recommendation
87L40S is the best default for inference workloads — it offers an excellent trade-off of cost and performance with 48 GB of GPU RAM.

General Recommendation

L40S is the best default for inference workloads — it offers an excellent trade-off of cost and performance with 48 GB of GPU RAM.

Raw lines 85 to 88
89## Multi-GPU
91Request multiple GPUs by appending `:count`:
93```python
94@app.function(gpu="H100:4")
95def distributed():
96 import torch
97 print(f"GPUs available: {torch.cuda.device_count()}")
98 # All 4 GPUs are on the same physical machine
99```
101- Up to 8 GPUs for most types (up to 4 for A10)
102- All GPUs attach to the same physical machine
103- Requesting more than 2 GPUs may result in longer wait times
104- Maximum listed single-node VRAM: 8 x B300 = 2,304 GB

Multi-GPU

Request multiple GPUs by appending :count:

@app.function(gpu="H100:4")
def distributed():
    import torch
    print(f"GPUs available: {torch.cuda.device_count()}")
    # All 4 GPUs are on the same physical machine
  • Up to 8 GPUs for most types (up to 4 for A10)
  • All GPUs attach to the same physical machine
  • Requesting more than 2 GPUs may result in longer wait times
  • Maximum listed single-node VRAM: 8 x B300 = 2,304 GB
Raw lines 89 to 105
106## GPU Fallback Chains
108Specify a prioritized list of GPU types:
110```python
111@app.function(gpu=["H100", "A100-80GB", "L40S"])
112def flexible():
113 # Modal tries H100 first, then A100-80GB, then L40S
114 ...
115```
117Useful for reducing queue times when a specific GPU isn't available.

GPU Fallback Chains

Specify a prioritized list of GPU types:

@app.function(gpu=["H100", "A100-80GB", "L40S"])
def flexible():
    # Modal tries H100 first, then A100-80GB, then L40S
    ...

Useful for reducing queue times when a specific GPU isn't available.

Raw lines 106 to 118
119## Auto-Upgrades
121### H100 → H200
123Modal may automatically upgrade H100 requests to H200 at no extra cost. To prevent this:
125```python
126@app.function(gpu="H100!") # Exclamation mark prevents auto-upgrade
127def must_use_h100():
128 ...
129```

H100 → H200

Modal may automatically upgrade H100 requests to H200 at no extra cost. To prevent this:

@app.function(gpu="H100!")  # Exclamation mark prevents auto-upgrade
def must_use_h100():
    ...
Raw lines 121 to 130
131### A100 → A100-80GB
133`gpu="A100"` requests may be upgraded to 80GB at no extra cost.
134Use `gpu="A100-40GB"` when you specifically require the 40GB variant.

A100 → A100-80GB

gpu="A100" requests may be upgraded to 80GB at no extra cost. Use gpu="A100-40GB" when you specifically require the 40GB variant.

Raw lines 131 to 135
136### B200+
138`gpu="B200+"` allows Modal to run on B200 or B300 GPUs at B200 pricing.
139Both `B200+` and direct `B300` requests require a stack compatible with CUDA 13.1+.

B200+

gpu="B200+" allows Modal to run on B200 or B300 GPUs at B200 pricing. Both B200+ and direct B300 requests require a stack compatible with CUDA 13.1+.

Raw lines 136 to 140
141## Multi-GPU Training
143Modal 1.6 adds `@modal.clustered(size=N)` and `modal.Cluster.from_context()` for
144multi-node Functions and Servers. The dedicated current guide supersedes the older
145GPU page's private-beta wording. Clustered jobs require full GPU nodes (e.g. H100:8),
146not CPU-only jobs or partial H100:4 nodes; verify workspace availability before use.
147The snippets below are single-node launcher templates, not tested training jobs.

Multi-GPU Training

Modal 1.6 adds @modal.clustered(size=N) and modal.Cluster.from_context() for multi-node Functions and Servers. The dedicated current guide supersedes the older GPU page's private-beta wording. Clustered jobs require full GPU nodes (e.g. H100:8), not CPU-only jobs or partial H100:4 nodes; verify workspace availability before use. The snippets below are single-node launcher templates, not tested training jobs.

Raw lines 141 to 148
149### PyTorch DDP Example
151```python
152# train.py must implement distributed training and read torchrun's rank variables.
153image = (
154 modal.Image.debian_slim(python_version="3.11")
155 .uv_pip_install("torch")
156 .add_local_file("train.py", "/root/train.py")
159@app.function(gpu="H100:4", image=image, timeout=86400)
160def train_distributed():
161 import subprocess
162 subprocess.run([
163 "torchrun", "--standalone", "--nnodes=1", "--nproc-per-node=4",
164 "/root/train.py",
165 ], check=True)
166```
168Requesting four GPUs does not start four Python workers. The launcher establishes
169`RANK`, `WORLD_SIZE` and `LOCAL_RANK`; initialize the process group inside `train.py`.

PyTorch DDP Example

# train.py must implement distributed training and read torchrun's rank variables.
image = (
    modal.Image.debian_slim(python_version="3.11")
    .uv_pip_install("torch")
    .add_local_file("train.py", "/root/train.py")
)

@app.function(gpu="H100:4", image=image, timeout=86400)
def train_distributed():
    import subprocess
    subprocess.run([
        "torchrun", "--standalone", "--nnodes=1", "--nproc-per-node=4",
        "/root/train.py",
    ], check=True)

Requesting four GPUs does not start four Python workers. The launcher establishes RANK, WORLD_SIZE and LOCAL_RANK; initialize the process group inside train.py.

Raw lines 149 to 170
171### PyTorch Lightning
173When using frameworks that re-execute Python entrypoints (like PyTorch Lightning), either:
1751. Use a strategy supported by the installed Lightning release (the Modal guide lists `ddp_spawn` / `ddp_notebook`)
1762. Or run training as a subprocess
178```python
179@app.function(gpu="H100:4", image=image)
180def train():
181 import subprocess
182 subprocess.run(["python", "train_script.py"], check=True)
183```

PyTorch Lightning

When using frameworks that re-execute Python entrypoints (like PyTorch Lightning), either:

  1. Use a strategy supported by the installed Lightning release (the Modal guide lists ddp_spawn / ddp_notebook)
  2. Or run training as a subprocess
@app.function(gpu="H100:4", image=image)
def train():
    import subprocess
    subprocess.run(["python", "train_script.py"], check=True)
Raw lines 171 to 184
185### Hugging Face Accelerate
187Install `accelerate` in the Image and include `train.py` with `add_local_file`.
189```python
190@app.function(gpu="A100-80GB:4", image=image)
191def finetune():
192 import subprocess
193 subprocess.run([
194 "accelerate", "launch",
195 "--num_processes", "4",
196 "train.py"
197 ], check=True)
198```
200> **Security:** These launchers use fixed, hardcoded argument lists. Never build the
201> `subprocess` argument list from unsanitized user input. If a workload needs
202> user-supplied values (e.g. hyperparameters), validate them against an allowlist or
203> pass them as files / environment variables rather than as command arguments.

Hugging Face Accelerate

Install accelerate in the Image and include train.py with add_local_file.

@app.function(gpu="A100-80GB:4", image=image)
def finetune():
    import subprocess
    subprocess.run([
        "accelerate", "launch",
        "--num_processes", "4",
        "train.py"
    ], check=True)
Security: These launchers use fixed, hardcoded argument lists. Never build the subprocess argument list from unsanitized user input. If a workload needs user-supplied values (e.g. hyperparameters), validate them against an allowlist or pass them as files / environment variables rather than as command arguments.
Raw lines 185 to 203