ezpz¶
ezpz is a thin layer over PyTorch distributed that removes the per-machine boilerplate: rank and topology detection, backend selection, hostfile parsing, and launcher invocation. The same script runs on Aurora, Polaris, and Perlmutter without an if machine == ... branch.
Full documentation: ezpz.cool.
The problem it solves¶
Moving a working PyTorch script between ALCF systems, or from ALCF to NERSC, normally means rewriting the parts that have nothing to do with the model:
| Concern | Aurora / Sunspot | Polaris / Sophia | Perlmutter |
|---|---|---|---|
| Scheduler | PBS Pro | PBS Pro | SLURM |
| Launcher | mpiexec | mpiexec | srun |
| Accelerator | Intel XPU | NVIDIA | NVIDIA |
| Backend | xccl | nccl | nccl |
| Hostfile | $PBS_NODEFILE | $PBS_NODEFILE | $SLURM_NODELIST |
| Local rank var | PALS_LOCAL_RANKID | PMI_LOCAL_RANK | SLURM_LOCALID |
ezpz detects all of it at runtime. The Supported Systems page lists the full matrix, including the hostname prefixes used for detection (x4* for Aurora, x1* for Sunspot, and so on).
Setup¶
module use /soft/modulefiles
module load conda
conda activate
pip install "git+https://github.com/saforem2/ezpz" # (1)!
- Install from the repository. The name
ezpzon PyPI belongs to an unrelated package.
Then, inside a job script or an interactive allocation:
ezpz_setup_env loads the right modules for the current machine, activates the Python environment, and exports the machine-specific environment variables. Verify with:
Launching¶
ezpz launch wraps the scheduler's launcher. It reads the hostfile, computes ranks-per-node from the detected accelerator count, and applies CPU binding:
That command is unchanged across every supported machine; on Polaris it becomes a 4-rank-per-node mpiexec, one rank per A100 GPU. See ezpz launch for the flags, including --auto-retry for resubmitting around node failures.
Minimal PBS job on Polaris
| job.sh | |
|---|---|
Using it in your own script¶
Two calls replace the usual distributed preamble:
- Initializes the process group with the correct backend, binds the device, and returns the global rank. No
MASTER_ADDR/MASTER_PORTplumbing.
See Distributed Training for the full API.
Features¶
| Area | What it does | Details |
|---|---|---|
| Launcher | Scheduler-aware mpiexec / srun wrapper with CPU binding and --auto-retry | ezpz launch |
| Setup | Per-machine module loading and environment export | Quickstart |
| Distributed | Backend selection, rank/topology detection, DDP and FSDP2 wrapping | Distributed Training |
| Parallelism | FSDP2, tensor parallel, sequence parallel, 2D meshes | Parallelism |
| Examples | Runnable training examples with a shared model-size ladder (debug → xxxl) | Examples |
| Profiling | torch.profiler wrapper with automatic XPU/CUDA activity selection | Profiling |
| Metrics | History for per-iteration metrics, plots, and W&B / MLflow logging | History |
| Checkpointing | Distributed checkpoint save/restore, resumable after node failure | Checkpoint & Restart |
| Fault handling | Node-kill injection and automatic retry | Fault Injection |
| Diagnostics | ezpz doctor, ezpz test | ezpz test |
Examples¶
Each example takes a --model size from debug (laptop-runnable) through xxxl (~10B), so the same command scales from a smoke test to a real job:
ezpz launch python3 -m ezpz.examples.test --model small
ezpz launch python3 -m ezpz.examples.fsdp --model large
ezpz launch python3 -m ezpz.examples.fsdp_tp --model large --tp 2 # FSDP2 + tensor parallel
The full set is listed under Examples, and ezpz benchmark runs them in sequence with a summary report.
Other systems¶
The same workflow applies on Aurora, which needs a few extra environment settings that ezpz_setup_env handles.
Getting help¶
Issues and questions: saforem2/ezpz. Common failure modes are collected in Troubleshooting.