Files
Zhipeng Wang 64fcec6ba7 Enable DeepSpeed support on Apple Silicon (MPS) with ZeRO Stage 1-3 (#8293)
## Summary

This PR is the first step (phase 0) of enabling Apple Silicon support
for DeepSpeed: make single-device training work end to end with
pure-PyTorch ops.

[**To-Do in phase 1**] Metal kernels will come later and plug into the
`op_builder/mps` classes added here.

The MPS accelerator was a stub: memory queries returned `None`, no
communication backend was set, `fp16/bf16` were reported unsupported,
and every op builder resolved to `NotImplementedBuilder`.
`deepspeed.initialize` + one training step failed for every ZeRO stage
on an Apple Silicon machine. This PR aims on enabling capabilities.

### Changes

- **`accelerator/mps_accelerator.py`** — real `torch.mps` memory stats,
fp16/bf16 support (bf16 gated on macOS 14+), `torch.mps.Event`, `gloo`
as the comm backend, and `is_synchronized_device() = True` (PyTorch's
MPS backend effectively exposes a single in-order execution stream and
currently provides no public CUDA-style stream API or `record_stream`
mechanism.). Unified memory makes `pin_memory` a no-op (torch's
`pin_memory()` also raises under MPS).
- **`deepspeed/comm/torch.py`** — gloo cannot operate on MPS tensors
(even at world size 1), so collectives stage MPS tensors through CPU
copies via a `stage_on_cpu` decorator; async ops copy back on `wait()`.
- **`accelerator/abstract_accelerator.py` + `runtime/zero`** — MPS has
no fp64. Gradient-norm accumulation now picks its dtype via a new
concrete `is_fp64_supported()` (default `True`) and `get_norm_dtype()`
instead of hard-coded `.double()`.
- **`op_builder/mps/`** — new backend package (`MPSOpBuilder`,
`NotImplementedBuilder`, `FusedAdamBuilder`). `FusedAdam` is implemented
with `torch._foreach_*` ops and mirrors the math in
`csrc/adam/multi_tensor_adam.cu`, following the HPU precedent of
Python-backed builders.
- **`tests/unit/common.py`** — MPS must use `spawn` (Metal's compiler
service is lost in `forkserver` children, which hangs the harness) and
reports its device count via the accelerator.
- **`tests/unit/ops/adam/test_adamw.py`** —
`test_fused_adam_matches_torch` checks `FusedAdam` against
`torch.optim.Adam/AdamW` on the active accelerator (fp32/bf16 ×
Adam/AdamW), so it also guards the CUDA kernel.

### Verified on an M5 Max (macOS 26.3, torch 2.13.0)

- ZeRO 1/2/3 × fp32/bf16/fp16 train end to end with
`deepspeed.initialize` (single process). Also tested on ZeRO stage 0
which disables ZeRO completely and falling back to standard data
parallelism.
- MPS `FusedAdam` matches `torch.optim` to 2e-7 in fp32.
- `DS_ACCELERATOR=mps pytest unit/runtime/test_ds_config_dict.py
unit/runtime/test_ds_initialize.py
unit/runtime/half_precision/test_fp16.py
unit/runtime/half_precision/test_dynamic_loss_scale.py
unit/runtime/zero/test_zero_grad_clip.py
unit/runtime/zero/test_zero_context.py
unit/checkpoint/test_zero_optimizer.py`: 132 passed, 0 failed, 126
skipped (multi-device tests; `device_count() == 1`).

### Known limitations / follow-ups

- bf16 `FusedAdam` differs from the CUDA kernel by ~1 bf16 ulp (CUDA
computes in fp32 and stores bf16; the `_foreach` path rounds in bf16).
- The CPU-staged gloo path is only exercised at world size 1 here;
multi-Mac runs are untested.
- Follow-ups: macOS arm64 CI workflow, arm64 build of CPU Adam for
ZeRO-Offload, Metal kernels via `torch.mps.compile_shader`, and an Apple
Silicon tutorial page.

---------

Signed-off-by: PKUWZP <zhipeng.rainbowserie@gmail.com>
Co-authored-by: Ma, Guokai <guokai.ma@gmail.com>
2026-08-23 09:13:43 +00:00
..
2026-06-11 17:42:19 +00:00
2025-02-05 00:56:50 +00:00
2024-09-04 15:31:31 +00:00
2023-09-18 22:16:08 +00:00
2020-03-17 13:49:48 -07:00
2025-02-05 12:16:37 -08:00
2024-08-05 08:51:26 -07:00
2024-08-05 08:51:26 -07:00

DeepSpeed Documentation

This directory includes the source code for the website and documentation of DeepSpeed. The code-docs/ directory is used to build deepspeed.readthedocs.io.

deepspeed.ai is the recommended way to read all DeepSpeed documentation. Directly viewing the Markdown files in this directory will not include images and other features.

Building the documentation locally

You can serve the DeepSpeed website locally. This is especially useful for development.

Prerequisites

The DeepSpeed website relies on Jekyll. There are several guides for installation. The instructions below assume you are in an Ubuntu environment and have been tested on WSL.

First ensure that you have the necessary packages (e.g., make and zlib).

sudo apt-get install build-essential zlib1g-dev ruby-full

Add these lines to your .bashrc or equivalent to ensure you have permissions to install Ruby packages without sudo.

export GEM_HOME="$HOME/gems"
export PATH="$HOME/gems/bin:$PATH"

Don't forget to source ~/.bashrc afterward 😊.

Now we can install Jekyll and Bundler:

gem install jekyll bundler

Start a local webserver

We now need to install the required Ruby packages for the website.

NOTE: you should change to this folder (i.e., docs) before running the installation command to avoid this error:

Could not locate Gemfile

NOTE: This step frequently hangs when connected to a VPN (including MSVPN). Simply disconnect for the package installation.

bundle install

Depending on your environment, you may need to add webrick to avoid the following error:

gems/gems/jekyll-3.9.5/lib/jekyll/commands/serve/servlet.rb:3:in `require': cannot load such file -- webrick (LoadError)

bundle add webrick

You can now start a local webserver via:

bundle exec jekyll serve

The website should now be accessible at http://localhost:4000

Update the Readthedocs.io API documentation

Use the following steps to update the public API documentation.

  1. Make your documentation changes and push them to the rtd-staging branch. This will rebuild the docs in the staging branch. NOTE: It is acceptable to force push to this branch to overwrite previous changes.
  2. View the result of the result of the build here
  3. Once the build is complete view the newly modified API documentation here
  4. Once you are satisfied with the changes create a new branch off of rtd-staging to push into master.