DeepSpeed
715965e0 - [Apple Silicon Support Phase 1] Add Metal FusedAdam kernel and CPU Adam build for Apple Silicon (#8300)

Commit
43 days ago
[Apple Silicon Support Phase 1] Add Metal FusedAdam kernel and CPU Adam build for Apple Silicon (#8300) ## Summary This PR implements the Phase 1 work of Apple Silicon support for DeepSpeed (follow-up to #8293, which made single-device ZeRO 1–3 training work with pure-PyTorch ops). This PR adds the **op-builder layer**: - Metal kernels compiled at runtime, - a first real Metal kernel (FusedAdam), - and the C++ CPU Adam build so ZeRO-Offload works on Macs. ### Changes - **`op_builder/mps/builder.py`** — new `MetalOpBuilder`. Subclasses list `.metal` files in `metal_sources()`; the shader is compiled at `load()` through `torch.mps.compile_shader`, which dispatches kernels on PyTorch's own MPS command stream. No Xcode project, `.metallib` packaging, or C++ extension build is involved. `is_compatible()` additionally requires `torch.mps.compile_shader`. - **`csrc/mps/fused_adam.metal` + `op_builder/mps/fused_adam.py`** — `FusedAdam` becomes a Metal kernel (one launch per tensor). It does all math in fp32 and stores in the parameter dtype, the same contract as `csrc/adam/multi_tensor_adam.cu`; this also closes the bf16 ulp gap noted in #8293. The `torch._foreach_*` implementation remains as a fallback for torch builds without `compile_shader` and for non-contiguous tensors. - **`op_builder/mps/cpu_adam.py`** — builds `csrc/adam/cpu_adam*.cpp` with the system clang (`-D__SCALAR__` on arm64). Apple clang has no OpenMP, so the build uses Homebrew `libomp` when `brew --prefix libomp` resolves and omits it otherwise; both paths verified. This enables `DeepSpeedCPUAdam` and therefore ZeRO-Offload on Apple Silicon. Unified memory means offloading does not copy parameters between separate memories. - **`tests/unit/ops/adam/test_adamw.py`** — `test_fused_adam_matches_reference` checks `FusedAdam` against an explicit fp32-math / storage-dtype-rounding reference for fp32, bf16, and fp16 × Adam/AdamW (replaces the `torch.optim` comparison from #8293, whose bf16 reference computes in bf16 and is a worse baseline). Tolerance is 8 ulp of the storage dtype at tensor scale, which covers measured fp32 op-order drift over 5 steps. - **`tests/unit/ops/adam/test_cpu_adam.py`, `test_hybrid_adam.py`** — `py-cpuinfo` has no `vendor_id_raw` on Apple Silicon; use `.get()`. - **`MANIFEST.in`** — ship `.metal` sources. **Docs** — accelerator setup guide updated for offload and the Metal/OpenMP notes. ### Verified on an M5 Max (macOS 26.3, torch 2.13.0) - `DeepSpeedCPUAdam` matches `torch.optim` to ~1e-6; ZeRO-Offload trains end to end for stage 1/2/3 × fp32/bf16/fp16 (optimizer offload; plus param offload for stage 3). - Metal `FusedAdam` vs foreach fallback, 4×100k params: 0.08 vs 0.27 ms/step (fp32), 0.03 vs 0.16 ms/step (bf16). Both implementations pass the new reference test in all 6 cases. - `DS_ACCELERATOR=mps pytest unit/ops/adam/test_cpu_adam.py unit/ops/adam/test_hybrid_adam.py unit/ops/adam/test_adamw.py`: 74 passed, 7 skipped. - `op_builder.mps` imports with torch absent (the sdist/install-smoke path). ### Follow-ups - macOS arm64 CI workflow so these paths are exercised upstream. - Further Metal kernels (quantizer for ZeRO++). --------- Signed-off-by: PKUWZP <zhipeng.rainbowserie@gmail.com>
Author
Parents
Loading