Skip to content

Commit e9ef57c

Browse files
Add experimental Apple Silicon GPU (Metal/MPS) inference support
Enable AlphaFold 3 inference on the Apple Silicon integrated GPU via the community jax-mps Metal plugin for JAX. The NVIDIA CUDA path is unchanged and remains the reference; MPS is an opt-in, experimental feasibility path. run_alphafold.py: * Add --jax_backend {gpu,mps} to explicitly select the accelerator backend (default 'gpu' preserves existing behavior). * Add the portable, linear-memory 'xla_chunked' flash-attention option alongside 'xla'; both are the only implementations valid on CPU/MPS (triton/cudnn remain NVIDIA-only). * Refactor device selection/validation into _select_inference_device and _validate_inference_device: CPU and MPS require xla/xla_chunked; the CUDA compute-capability checks (>=6.0, 7.x XLA_FLAGS workaround) are preserved unchanged; unvalidated accelerators are rejected with actionable errors. run_alphafold_device_test.py: * New unit tests (31 cases) covering backend selection, index bounds, attention validation, and explicit CUDA-path-preservation checks. requirements/apple-silicon-gpu.txt: * Pinned Metal backend (jax==0.10.2, jaxlib==0.10.2, jax-mps==0.10.9), installed as a post-install override of the base jax==0.9.1 pin. docs/installation_apple_silicon_gpu.md: * Native (non-Docker) macOS build and run guide, including HMMER build, build_data, the MPS backend install, run flags, and measured memory/performance guidance from a 52-target validation campaign.
1 parent f43a5c4 commit e9ef57c

5 files changed

Lines changed: 650 additions & 56 deletions

File tree

docs/installation.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ Since JAX doesn't support running natively on Mac GPU as of 2026, you have to
496496
resort to running AlphaFold 3 in the slow CPU-only mode even though it has a GPU
497497
(`jax-metal` is unfinished as of July 2026).
498498
499+
> **Experimental Apple Silicon GPU (Metal / MPS) inference.** As an alternative
500+
> to CPU-only mode, AlphaFold 3 inference can run on the Apple Silicon GPU
501+
> through the community `jax-mps` Metal plugin. This is an unofficial,
502+
> experimental feasibility path (not numerically certified), but it is
503+
> substantially faster than CPU for small and medium structures. See
504+
> [installation_apple_silicon_gpu.md](installation_apple_silicon_gpu.md).
505+
499506
1. Download all required databases and AlphaFold 3 weights (see above).
500507
2. Install the [HMMER Suite](http://hmmer.org/). See
501508
http://hmmer.org/documentation.html for installation instructions.
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
# Running AlphaFold 3 on Apple Silicon GPU (Metal / MPS)
2+
3+
> **Status: experimental feasibility path.** This mode runs AlphaFold 3
4+
> inference natively on the Apple Silicon integrated GPU through the community
5+
> [`jax-mps`](https://pypi.org/project/jax-mps/) Metal plugin for JAX. It is
6+
> **not** an officially supported or numerically certified configuration. The
7+
> NVIDIA CUDA path is unchanged and remains the reference. Use this for research,
8+
> local development, and prototyping on Macs — not for production or benchmarking
9+
> against the published CUDA results.
10+
11+
This guide describes a **native build with no Docker**. Docker Desktop on macOS
12+
runs a Linux VM that cannot see the Mac GPU, so the containerized recipe in
13+
[`installation.md`](installation.md) can only ever reach the CPU. To use the
14+
Apple GPU you must build AlphaFold 3 natively, as described below.
15+
16+
If you only want CPU-only inference on a Mac (much slower, but officially
17+
described), follow the "Running AlphaFold 3 without a GPU" section of
18+
[`installation.md`](installation.md) instead.
19+
20+
## What works and what to expect
21+
22+
Validated in July 2026 across a 52-target campaign (all 12 molecule-type classes:
23+
monomers, homo/hetero oligomers, protein–DNA, protein–RNA, and ligand/ion
24+
complexes, plus token-scaling targets up to ~2,200 tokens) on an **M2 Ultra Mac
25+
Studio (24-core CPU, 76-core GPU, 192 GB unified memory)**, macOS 15.
26+
27+
- **Correctness:** the full data pipeline (HMMER MSA + templates) and inference
28+
run end to end; predictions match the CUDA reference closely for the cases
29+
tested. Inference is **bit-reproducible run-to-run** with fixed seeds.
30+
- **Attention:** only the portable `xla` and `xla_chunked` implementations work
31+
on Metal. `triton` and `cudnn` require NVIDIA GPUs and are rejected early.
32+
- **Memory is the main limit** (see [Performance and memory](#performance-and-memory)).
33+
Peak GPU (unified) memory grows with the model's padded token bucket and
34+
reaches ~167 GiB at ~2,200 tokens on a 192 GB machine — that is the practical
35+
single-structure ceiling on this hardware.
36+
- **Large targets are slow.** Per-seed inference scales roughly cubically with
37+
tokens and hits a steep Metal-specific penalty above ~1,500 tokens.
38+
39+
## Prerequisites
40+
41+
- Apple Silicon Mac (M1/M2/M3/M4 family). More unified memory = larger tractable
42+
structures; 64 GB is a reasonable floor, 128–192 GB recommended for large
43+
complexes.
44+
- macOS 14 or newer.
45+
- Xcode Command Line Tools (provides `clang`, `make`, `patch`):
46+
47+
```sh
48+
xcode-select --install
49+
```
50+
51+
- A recent CMake (≥ 3.28) and a Python 3.11–3.13 toolchain. The steps below use
52+
[`uv`](https://docs.astral.sh/uv/); a Conda/Miniforge environment works
53+
equally well (see [Alternative: Conda](#alternative-conda-environment)).
54+
55+
## Step 1 — Install the HMMER suite (for the MSA data pipeline)
56+
57+
HMMER is only needed if you run the data pipeline (i.e. not with
58+
`--norun_data_pipeline`). Prefer a user-local source build of HMMER 3.4 with the
59+
sequence-truncation patch that ships in this repository
60+
(`docker/jackhmmer_seq_limit.patch`); a plain HMMER build also works but is not
61+
the preferred configuration.
62+
63+
```sh
64+
# Pick a location OUTSIDE the git checkout.
65+
export AF3_REPO="$PWD" # path to your alphafold3 clone
66+
export HMMER_PREFIX="$HOME/af3-tools/hmmer-3.4"
67+
mkdir -p "$HOME/af3-tools/hmmer-source" && cd "$HOME/af3-tools/hmmer-source"
68+
69+
curl -LO http://eddylab.org/software/hmmer/hmmer-3.4.tar.gz
70+
echo "ca70d94fd0cf271bd7063423aabb116d42de533117343a9b27a65c17ff06fbf3 hmmer-3.4.tar.gz" | shasum -a 256 -c
71+
tar -xzf hmmer-3.4.tar.gz
72+
cd hmmer-3.4
73+
patch -p0 < "$AF3_REPO/docker/jackhmmer_seq_limit.patch"
74+
./configure --prefix="$HMMER_PREFIX"
75+
make -j"$(sysctl -n hw.perflevel0.logicalcpu)"
76+
make install
77+
"$HMMER_PREFIX/bin/jackhmmer" -h | head -1 # sanity check
78+
```
79+
80+
You will pass the binaries to `run_alphafold.py` in Step 6 via the
81+
`--jackhmmer_binary_path`, `--nhmmer_binary_path`, `--hmmalign_binary_path`,
82+
`--hmmsearch_binary_path`, and `--hmmbuild_binary_path` flags (or put
83+
`$HMMER_PREFIX/bin` first on your `PATH`).
84+
85+
## Step 2 — Get the code, model weights, and databases
86+
87+
1. Clone the repository (if you have not already):
88+
89+
```sh
90+
git clone https://github.com/google-deepmind/alphafold3.git
91+
cd alphafold3
92+
```
93+
94+
2. Obtain the model weights by following the process in the
95+
[main README](https://github.com/google-deepmind/alphafold3). Keep the
96+
weights **outside** the git checkout.
97+
3. Download the genetic databases (see [`installation.md`](installation.md) and
98+
`fetch_databases.py`). These are large (hundreds of GB); place them on fast
99+
local storage.
100+
101+
## Step 3 — Build and install AlphaFold 3 natively
102+
103+
This compiles the AlphaFold 3 C++/CMake extension and installs the Python
104+
package. Upstream already supports the `darwin arm64` build environment.
105+
106+
```sh
107+
uv venv --python 3.12
108+
source .venv/bin/activate
109+
uv sync # builds and installs alphafold3 (scikit-build-core + cmake)
110+
uv run build_data # builds the CCD / chemical-component data used at runtime
111+
```
112+
113+
`uv sync` installs the base dependencies, which pin `jax==0.9.1` (CPU wheel on
114+
macOS). That JAX cannot reach the Apple GPU — Step 4 replaces it.
115+
116+
Verify the base install with the data-pipeline test:
117+
118+
```sh
119+
uv run python run_alphafold_data_test.py
120+
```
121+
122+
## Step 4 — Install the Apple Silicon GPU backend
123+
124+
Replace the base JAX with the Metal-capable stack pinned in
125+
[`requirements/apple-silicon-gpu.txt`](../requirements/apple-silicon-gpu.txt):
126+
127+
```sh
128+
uv pip install -r requirements/apple-silicon-gpu.txt
129+
# equivalently: uv pip install jax==0.10.2 jaxlib==0.10.2 jax-mps==0.10.9
130+
```
131+
132+
Confirm JAX now sees the Metal device:
133+
134+
```sh
135+
python -c "import jax; print([d.platform for d in jax.local_devices()])"
136+
# -> ['mps'] (a one-time 'Platform mps is experimental' warning is expected)
137+
```
138+
139+
`pip check` will report exactly one warning that AlphaFold 3 pins `jax==0.9.1`.
140+
That single mismatch is expected; any other mismatch means the environment is
141+
inconsistent.
142+
143+
## Step 5 — Verify device selection
144+
145+
Run the launcher's device-selection unit tests (fast, no GPU needed):
146+
147+
```sh
148+
uv run python run_alphafold_device_test.py
149+
```
150+
151+
These confirm the MPS backend is selectable and — importantly — that the CUDA
152+
path is unchanged.
153+
154+
## Step 6 — Run inference on the Apple GPU
155+
156+
Select the Metal backend with `--jax_backend mps` and a portable attention
157+
implementation. `xla` is the validated choice; `xla_chunked` uses less memory
158+
but is slower.
159+
160+
```sh
161+
uv run python run_alphafold.py \
162+
--json_path=/path/to/fold_input.json \
163+
--model_dir=/path/to/weights \
164+
--db_dir=/path/to/databases \
165+
--output_dir=/path/to/output \
166+
--jax_backend=mps \
167+
--gpu_device=0 \
168+
--flash_attention_implementation=xla \
169+
--jackhmmer_binary_path="$HMMER_PREFIX/bin/jackhmmer" \
170+
--nhmmer_binary_path="$HMMER_PREFIX/bin/nhmmer" \
171+
--hmmalign_binary_path="$HMMER_PREFIX/bin/hmmalign" \
172+
--hmmsearch_binary_path="$HMMER_PREFIX/bin/hmmsearch" \
173+
--hmmbuild_binary_path="$HMMER_PREFIX/bin/hmmbuild"
174+
```
175+
176+
For inference on a pre-computed input (skipping the MSA pipeline and HMMER), add
177+
`--norun_data_pipeline` and drop the HMMER flags.
178+
179+
## Performance and memory
180+
181+
Measured on the M2 Ultra (192 GB). Numbers are per diffusion sample ("seed") and
182+
scale with the **padded token bucket**, not the exact token count. Treat them as
183+
order-of-magnitude guidance; other Apple Silicon chips will differ.
184+
185+
| Padded tokens | Peak GPU (unified) memory | Inference time / seed |
186+
| ------------: | ------------------------: | --------------------: |
187+
| 256 | ~36 GiB | ~29 s |
188+
| 512 | ~50 GiB | ~90 s |
189+
| 768 | ~73 GiB | ~3.9 min |
190+
| 1,024 | ~101 GiB | ~8.6 min |
191+
| 1,536 | ~155 GiB | ~26.6 min |
192+
| ~2,180 | ~167 GiB (+ ~11 GiB swap) | ~3.9 hours |
193+
194+
Key points:
195+
196+
- **Unified memory is the ceiling.** GPU tensors live in unified memory and are
197+
reported by macOS as "Memory Used"; they are **not** visible as process RSS
198+
(the Python process itself stays near ~7 GiB). Do not rely on an RSS-based
199+
memory limiter to cap GPU use. On a 192 GB machine, ~2,200 tokens
200+
(~167 GiB + light swap) is the practical single-structure limit; larger
201+
structures will run out of memory. Scale your expectation to your Mac's memory.
202+
- **Inference cost is roughly cubic** in tokens (triangle attention dominates),
203+
with an additional steep Metal-specific penalty beyond ~1,500 tokens. Small to
204+
medium structures (≤ ~1,000 tokens) are comfortable; multi-thousand-token
205+
complexes are expensive. Use `xla_chunked` to trade speed for lower memory.
206+
- **The MSA / data pipeline runs on the CPU** and its cost depends on the number
207+
of unique chains and whether RNA is present (≈ 7–35 min in the campaign), not
208+
on token count. Set the HMMER thread counts so that
209+
(concurrent searches × threads-per-search) ≈ the number of performance cores
210+
to avoid oversubscription (`sysctl hw.perflevel0.logicalcpu`).
211+
- **No persistent JAX compilation cache on Metal.** `--jax_compilation_cache_dir`
212+
does not persist across processes on the MPS backend, so every process pays the
213+
compile cost for each new token bucket. Amortize it by folding many inputs in
214+
one process (e.g. `--input_dir`) rather than launching one process per target.
215+
- **Thermals** were nominal on the Mac Studio throughout a ~40 h campaign (no
216+
throttling). Laptops with less cooling headroom will behave differently.
217+
218+
## Alternative: Conda environment
219+
220+
If you prefer Conda/Miniforge over `uv`, the same result is achieved with:
221+
222+
```sh
223+
conda create -n af3-mps python=3.13 cmake -y
224+
conda activate af3-mps
225+
pip install --no-build-isolation -e . # or: pip install .
226+
build_data
227+
pip install -r requirements/apple-silicon-gpu.txt
228+
```
229+
230+
Then run `run_alphafold.py` with the same MPS flags as in Step 6.
231+
232+
## Troubleshooting
233+
234+
- **`No local MPS device was found for --jax_backend=mps`**`jax-mps` is not
235+
installed or JAX was not upgraded. Re-run Step 4 and re-check
236+
`jax.local_devices()`.
237+
- **`--flash_attention_implementation must be set to "xla" or "xla_chunked"`**
238+
`triton`/`cudnn` are NVIDIA-only; use `xla` (or `xla_chunked`) on Metal.
239+
- **Out-of-memory / heavy swapping on large targets** — reduce the structure
240+
size, switch to `--flash_attention_implementation=xla_chunked`, or run on a Mac
241+
with more unified memory. See the memory table above.
242+
- **`pip check` reports a jax version mismatch** — one warning about the
243+
`jax==0.9.1` pin is expected (see Step 4); investigate any other mismatch.

requirements/apple-silicon-gpu.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Experimental AlphaFold 3 Apple Silicon GPU (Metal / MPS) backend.
2+
#
3+
# Install these *after* the base AlphaFold 3 install. The base project pins
4+
# jax==0.9.1 for the CUDA / CPU path; the experimental `jax-mps` Metal plugin
5+
# requires a newer JAX, so these pins upgrade JAX to 0.10.2. After installing,
6+
# `pip check` reports exactly one expected warning that AlphaFold 3 pins
7+
# jax==0.9.1 -- that single mismatch is expected and the MPS path is validated
8+
# with the versions below. Any *other* mismatch means something is wrong.
9+
#
10+
# Validated on macOS (Apple Silicon, M2 Ultra, 192 GB), Python 3.13, July 2026.
11+
# See docs/installation_apple_silicon_gpu.md for the full guide.
12+
jax==0.10.2
13+
jaxlib==0.10.2
14+
jax-mps==0.10.9

0 commit comments

Comments
 (0)