How to Install DeepSpeed
PyPI serves only a source distribution for DeepSpeed, so pip install deepspeed compiles instead of downloading a wheel. Prebuilt wheels are on the Astral GPU indexes, one index per CUDA version, and they arrive with the CUDA ops already compiled.
The index removes the build, not the toolkit. DeepSpeed runs $CUDA_HOME/bin/nvcc while importing, so a GPU machine still needs either a toolkit or DS_IGNORE_CUDA_DETECTION=1. See Why Installing GPU Python Packages Is So Complicated for background.
Pick an install path
- Install from the Astral GPU index for any project on a CUDA version it covers. Start here.
- Build from source when your CUDA and PyTorch pair falls outside the index, or when you need an op the wheel omits.
- Install with conda-forge or pixi to hand CUDA toolkit matching to a solver.
Check your platform
- Platform: Linux (x86_64). Windows has partial support through WSL2. No macOS GPU support. The index wheels are
manylinux_2_27_x86_64only, with noaarch64build, so Grace Hopper and other ARM hosts need a source build. - PyTorch: installed before DeepSpeed on every path. The index wheels pin it (
torch==2.11.*); the source build imports it insetup.py. - Toolkit: needed for a source build, and for
import deepspeedon a GPU machine unlessDS_IGNORE_CUDA_DETECTION=1is set. - System libraries:
libaio-devfor the async I/O op used by ZeRO-Infinity and NVMe offloading (apt install libaio-devon Debian/Ubuntu). No wheel bundles it, sods_reportflagsasync_ioas unavailable until it is installed.
Install from the Astral GPU index
Each index covers one CUDA version, and each wheel targets one PyTorch version. Both sit in a PEP 440 local version segment rather than a platform tag, so deepspeed resolves like any other dependency:
deepspeed-0.19.2+cu.12.8.torch.2.11-cp312-cp312-manylinux_2_27_x86_64.whlRoute torch and deepspeed to indexes on the same CUDA line. Pick the CUDA version your driver supports (cu126, cu128, cu129, cu130, or cu132), then add both:
uv add torch --index pytorch-cu128=https://download.pytorch.org/whl/cu128
uv add deepspeed --index astral-cu128=https://wheels.astral.sh/simple/cu128/$ uv add deepspeed --index astral-cu128=https://wheels.astral.sh/simple/cu128/
Resolved 46 packages in 5.31s
Downloading deepspeed (186.9MiB)
Prepared 15 packages in 5.43s
Installed 15 packages in 109ms
+ deepspeed==0.19.2+cu.12.8.torch.2.11
+ einops==0.8.2
+ hjson==3.1.0
...
Each wheel declares its PyTorch as a dependency (torch==2.11.*), so the resolver picks the build matching the project’s torch. Routing torch to a CUDA-specific index pins the other half of the pair.
Warning
Routing torch is not optional. The Astral indexes serve no torch, so an unrouted torch comes from PyPI, whose CUDA build changes between releases: PyPI ships PyTorch 2.11 as a CUDA 13 build. It satisfies torch==2.11.*, so pairing it with a cu128 wheel resolves and installs cleanly, then fails against CUDA 12 shared libraries at runtime.
Installing deepspeed as a dependency of something else (Megatron, Axolotl, a training framework) skips this routing, because [tool.uv.sources] applies only to declared dependencies. Declare deepspeed directly too.
Configure the index in pyproject.toml
uv add --index writes both indexes and the source mappings:
[tool.uv.sources]
torch = { index = "pytorch-cu128" }
deepspeed = { index = "astral-cu128" }
[[tool.uv.index]]
name = "pytorch-cu128"
url = "https://download.pytorch.org/whl/cu128"
explicit = true # add by hand; uv add omits it
[[tool.uv.index]]
name = "astral-cu128"
url = "https://wheels.astral.sh/simple/cu128/"
explicit = trueA named index outranks PyPI for every package it carries, so deepspeed comes from Astral. The cu128 index also carries vllm, flash-attn, mmcv, and others; explicit = true keeps it from silently supplying those. uv’s PyTorch guide recommends the flag.
Important
explicit = true without a matching [tool.uv.sources] entry removes the index from the pool and resolves deepspeed from PyPI instead. uv lock reports no error, and the lock records a PyPI source distribution, so uv sync starts the source build this section exists to avoid. Add both or neither.
Import on a GPU machine without a toolkit
DeepSpeed builds a compatibility table for every op at import. One of those probes runs $CUDA_HOME/bin/nvcc -V whenever torch.cuda.is_available() is true, which stops the import on a GPU machine carrying no toolkit:
$ uv run python -c "import deepspeed"
deepspeed.ops.op_builder.builder.MissingCUDAException: CUDA_HOME does not exist,
unable to compile CUDA op(s)
Set DS_IGNORE_CUDA_DETECTION=1 to skip the probe:
DS_IGNORE_CUDA_DETECTION=1 uv run python -c "import deepspeed; print(deepspeed.__version__)"The variable only skips a check on whether ops could be JIT-compiled. The wheel’s ops are already compiled, so they load and run either way. An op the wheel omits still needs a toolkit to JIT-compile, so keep the toolkit if you rely on one.
The probe never fires on a CPU-only machine, where torch.cuda.is_available() is false. A container image that installs cleanly during a CPU build can still fail on first import once scheduled onto a GPU.
The nvidia-cuda-nvcc-cu12 wheel does not substitute for a toolkit here: it ships ptxas but no nvcc binary, so pointing CUDA_HOME at it fails the same probe with FileNotFoundError.
Confirm the ops arrived precompiled
ds_report prints which ops are installed against which are merely available for JIT compilation. On an index wheel the interesting column is installed:
$ DS_IGNORE_CUDA_DETECTION=1 uv run ds_report
op name ................ installed .. compatible
fused_adam ............. [YES] ...... [OKAY]
cpu_adam ............... [YES] ...... [OKAY]
transformer_inference .. [YES] ...... [OKAY]
async_io ............... [NO] ....... [NO]
...
deepspeed info ................... 0.19.2+cu.12.8.torch.2.11, b919284, HEAD
torch cuda version ............... 12.8
nvcc version ..................... [FAIL] cannot find CUDA_HOME
deepspeed wheel compiled w. ...... torch 2.11, cuda 12.8
installed [YES] is the outcome that DS_BUILD_OPS=1 buys on a source build after several minutes of compilation. Constructing a FusedAdam returns immediately rather than pausing to JIT-compile, and the nvcc version [FAIL] line is expected on this path.
Check the index coverage
Coverage for deepspeed 0.19.2, by index:
| Index | PyTorch | Python |
|---|---|---|
cu126 |
2.7-2.12 | 3.9-3.14 |
cu128 |
2.7-2.11 | 3.9-3.14 |
cu129 |
2.8-2.11 | 3.9-3.14 |
cu130 |
2.9-2.12 | 3.10-3.14 |
cu132 |
2.12 | 3.10-3.14 |
Coverage is uneven within each row: Python 3.9 appears only against PyTorch 2.7 and 2.8, and 3.14 only against 2.10 and newer. The cu118, cu121, and cu124 indexes carry no deepspeed at all, and the newest release on the index trails the newest on PyPI. wheels.astral.sh is the current manifest.
Build from source
Outside the index’s CUDA and PyTorch matrix, DeepSpeed builds from the PyPI source distribution. This path needs a C++ compiler, the CUDA toolkit with nvcc on PATH, and CUDA_HOME set to the toolkit root, because setup.py checks for the toolkit while generating metadata.
DeepSpeed’s setup.py imports torch at the top level, so PyTorch must be present before installation. The --no-build-isolation flag tells the installer to use the current environment’s torch instead of creating a clean build environment:
uv pip install deepspeed --no-build-isolationThis installs the Python package without compiling any CUDA kernels. Ops are compiled at first use via JIT, which adds a one-time delay (seconds to minutes depending on the op) the first time DeepSpeed runs a training job.
Pre-compile ops at install time
To avoid JIT compilation delays at runtime, set DS_BUILD_OPS=1 to compile all compatible ops during installation:
DS_BUILD_OPS=1 uv pip install deepspeed --no-build-isolationThis requires nvcc on PATH and a working C++ compiler. The build takes several minutes.
To compile only specific ops, use individual environment variables instead:
| Variable | Op |
|---|---|
DS_BUILD_CPU_ADAM |
CPU Adam optimizer |
DS_BUILD_FUSED_ADAM |
Fused Adam (CUDA) |
DS_BUILD_AIO |
Async I/O for NVMe offload |
DS_BUILD_TRANSFORMER_INFERENCE |
Transformer inference kernels |
DS_BUILD_SPARSE_ATTN |
Sparse attention |
Set any of these to 1 to pre-compile that op. For example, to compile only the fused Adam optimizer:
DS_BUILD_FUSED_ADAM=1 pip install deepspeed --no-build-isolationAdd a source build to a uv project
For projects managed with uv using uv add and uv sync, use extra-build-dependencies to inject torch into the isolated build environment. The match-runtime = true option ensures the build uses the same torch version the project resolves at runtime:
[project]
dependencies = ["deepspeed", "torch"]
[tool.uv.extra-build-dependencies]
deepspeed = [{ requirement = "torch", match-runtime = true }]Then run uv sync as normal. uv handles build isolation and torch injection automatically.
To pre-compile ops during the build, pass environment variables with extra-build-variables:
[tool.uv.extra-build-variables]
deepspeed = { DS_BUILD_OPS = "1" }Install with conda-forge or pixi
DeepSpeed is available on conda-forge, though the version may lag behind PyPI. The conda-forge build handles CUDA toolkit dependencies through the solver:
pixi add deepspeedFor more on when conda-based tools are the better choice for GPU workloads, see uv vs pixi vs conda for Scientific Python.
Verify the installation
Run one training step to confirm the package imports, its ops load, and the engine drives a backward pass:
import torch, deepspeed
model = torch.nn.Linear(64, 64)
config = {
"train_batch_size": 8,
"optimizer": {"type": "AdamW", "params": {"lr": 1e-3}},
"zero_optimization": {"stage": 1},
"bf16": {"enabled": True},
}
engine, _, _, _ = deepspeed.initialize(
model=model, model_parameters=model.parameters(), config=config
)
loss = engine(torch.randn(8, 64, device=engine.device, dtype=torch.bfloat16)).sum()
engine.backward(loss)
engine.step()
print("training step OK", deepspeed.__version__)$ DS_IGNORE_CUDA_DETECTION=1 uv run python check_deepspeed.py
training step OK 0.19.2+cu.12.8.torch.2.11
deepspeed.initialize expects the distributed environment variables a launcher normally sets. Run the script under deepspeed check_deepspeed.py, or set RANK=0 LOCAL_RANK=0 WORLD_SIZE=1 MASTER_ADDR=127.0.0.1 MASTER_PORT=29500 for a single-process check.
Troubleshooting
CUDA_HOME does not exist, unable to compile CUDA op(s). On a prebuilt wheel this fires at import, from the op compatibility probe; set DS_IGNORE_CUDA_DETECTION=1. On a source build it fires at metadata generation, before any op is compiled, and needs a real toolkit: export CUDA_HOME=/usr/local/cuda. NVIDIA’s CUDA devel Docker images set this automatically, but slim Python images do not.
FileNotFoundError: .../bin/nvcc at import. CUDA_HOME points at a directory holding no nvcc. The nvidia-cuda-nvcc-cu12 wheel is the common cause, since it ships ptxas alone. Unset CUDA_HOME and use DS_IGNORE_CUDA_DETECTION=1, or point it at a full toolkit.
Undefined symbol errors from a DeepSpeed .so at import. The wheel was built against a different PyTorch than the one installed. Compare deepspeed wheel compiled w. in ds_report against torch.__version__, and route torch to an index on the same CUDA line as the DeepSpeed index.
ModuleNotFoundError: No module named 'torch' during install. The installer is building the PyPI source distribution rather than downloading a wheel, and the isolated build has no torch. Point it at an index, or pass --no-build-isolation with torch already installed.
Learn More
- Why Installing GPU Python Packages Is So Complicated for context on CUDA toolkit requirements and GPU wheel coverage
- How to Install PyTorch with uv for setting up PyTorch before adding DeepSpeed
- How to Install Flash-Attention for another GPU package requiring custom index configuration
- How to Install RAPIDS with uv for similar index-based GPU wheel installation
- uv vs pixi vs conda for Scientific Python to compare tooling for GPU workloads
- Astral GPU indexes for the current wheel manifest across CUDA versions
RuntimeError: ninja is not available at runtime. DeepSpeed’s JIT compilation uses ninja as its build backend. Install it with pip install ninja or apt install ninja-build.
libaio.h: No such file or directory when building the async I/O op. Install the development headers: apt install libaio-dev on Debian/Ubuntu, or yum install libaio-devel on RHEL/CentOS.
CUDA version mismatch errors. The CUDA toolkit version used to compile ops must be compatible with the CUDA version PyTorch was built against. Check uv run python -c "import torch; print(torch.version.cuda)" and ensure nvcc --version reports a compatible version.
error: invalid command 'bdist_wheel' during install. The wheel package is missing from the environment. Run pip install wheel first, then retry. This happens on minimal base images that don’t ship wheel by default.
DS_BUILD_OPS=1 fails on a machine without a GPU. Pre-compilation requires CUDA headers and a GPU-compatible toolchain even if no physical GPU is present. On CPU-only machines, take the wheel from the index, or skip DS_BUILD_OPS and let ops JIT-compile on the GPU machine at runtime.
Related
Handbook articles:
- Why Installing GPU Python Packages Is So Complicated explains the wheel format limitations that affect DeepSpeed packaging
- How to Install Flash-Attention covers the same index for the other package most training stacks compile
- How to Install PyTorch with uv covers getting PyTorch installed before adding DeepSpeed
- uv vs pixi vs conda for Scientific Python compares tooling choices for GPU workloads
External resources:
- Astral GPU indexes for the current wheel manifest across CUDA versions
- uv’s PyTorch integration guide for the index configuration uv recommends
- DeepSpeed GitHub repository for documentation and issue tracker
- deepspeed on PyPI (source distributions only)
- DeepSpeed installation guide for the official docs