From 8faa5258fd7d79fc64012e85e4ecd2f9f5b48c2a Mon Sep 17 00:00:00 2001 From: Dima Molodenskiy Date: Tue, 11 Aug 2026 17:34:16 +0200 Subject: [PATCH] Support Blackwell GPUs and MIG slices for structure inference Size the unified-memory fraction from the MIG slice rather than its parent card. structure_inference_xla_mem_fraction: auto computes host RAM / GPU VRAM from `nvidia-smi --query-gpu=memory.total`, which on a MIG slice reports the whole physical card - 32623 MiB for a 16 GB 1g.16gb instance. That roughly halves the fraction and so switches off host spill exactly on the small slices that need it most: with 32 GB of host RAM the fraction came out 0.981 (no spill past the ~16 GB slice) instead of 1.953. Read the slice's own profile from `nvidia-smi -L` when CUDA_VISIBLE_DEVICES is a MIG UUID, falling back to --query-gpu on whole cards. Measured on EMBL gpu-el8 with 32000 MiB host RAM: GPU gpu_mem_mb fraction jax sees RTX PRO 4500 MIG 1g.16gb 16384 1.953 ~16032 MiB (was) 32623 0.981 RTX PRO 6000 Blackwell 96GB 97887 0.327 ~97252 MiB RTX 3090 24576 1.302 ~24126 MiB Whole cards are unchanged, so this only affects MIG nodes. Also document Blackwell as verified rather than expected. AlphaPulldown 2.5.0 containers run on RTX PRO 6000 (gpu50-53) and on the RTX PRO 4500 16 GB MIG slices (gpu60-68) for both AF3 and AF2, with confidence scores matching A100/H100/3090; only pre-2.5.0 images fail there, at the first kernel compilation with "ptxas too old" / UNIMPLEMENTED. Add both node groups to the gpu_tiers example (a 16 GB tier for monomers and small complexes, a 96 GB tier for large ones) and note that a plain gpu:1 gres already lands on a MIG slice, so no gres change is needed to use them. Co-Authored-By: Claude Opus 5 --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++--- config/config.yaml | 21 ++++++++++++------ workflow/Snakefile | 25 +++++++++++++++++++--- 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9c66b13..a3a1571 100644 --- a/README.md +++ b/README.md @@ -270,10 +270,12 @@ you hit these. # Example for EMBL gpu-el8 — replace nodes with your cluster's (nothing is hard-coded): structure_inference_gpu_vram_headroom: 1.0 # <1.0 tolerates that fraction of host spill structure_inference_gpu_tiers: + - {min_vram_gb: 16, nodes: "gpu60,gpu61,gpu62,gpu63,gpu64,gpu65,gpu66,gpu67,gpu68"} # RTX PRO 4500, 16GB MIG - {min_vram_gb: 24, nodes: "gpu21,gpu22,gpu29,gpu30,gpu31,gpu32,gpu33,gpu34,gpu35,gpu36,gpu37"} - {min_vram_gb: 40, nodes: "gpu25,gpu26,gpu27,gpu28"} - {min_vram_gb: 48, nodes: "gpu40,gpu41,gpu42,gpu43,gpu44,gpu45,gpu46,gpu47,gpu48"} - {min_vram_gb: 80, nodes: "gpu38,gpu39"} + - {min_vram_gb: 96, nodes: "gpu50,gpu51,gpu52,gpu53"} # RTX PRO 6000 Blackwell ``` When set this drives `--exclude` per job and **overrides** `structure_inference_gpu_model` (the two @@ -285,9 +287,10 @@ you hit these. - **Exclude specific nodes** with `slurm_exclude_nodes` → passed verbatim to `sbatch --exclude` (e.g. `"gpu50,gpu51"`). Use it as a fallback for nodes whose GPU the container can't use — e.g. a CUDA compute capability newer than the container's bundled `ptxas` (fails `ptxas too old` / - `UNIMPLEMENTED`). The RTX PRO 6000 / Blackwell failure mode seen on EMBL `gpu50-53` was an - old/pre-Tokamax AlphaFold 3 image issue; updated AF3 v3.0.2/Tokamax images should run on those - cards, so excluding them is not proof of RTX compatibility. + `UNIMPLEMENTED`). For Blackwell (sm_120) that is purely an image-age problem: AlphaPulldown + **2.5.0 containers are verified working** on RTX PRO 6000 (`gpu50-53`) and on the RTX PRO 4500 + 16 GB MIG slices (`gpu60-68`) for both AF3 and AF2 — see [Blackwell GPUs](#blackwell-gpus). Only + exclude those nodes while you are still on a pre-2.5.0 image. `--exclude` is allowed in `slurm_extra` whereas `--constraint`/`--gres`/`--gpus` are not, so it is the supported way to drop a few nodes while keeping the rest of the partition. - **`structure_inference_max_runtime`** caps per-job wall time (minutes). Wall time scales as @@ -297,6 +300,50 @@ you hit these. +
+Blackwell GPUs (sm_120) and MIG slices + +#### Blackwell GPUs + +Blackwell cards (compute capability 12.0 / sm_120 — RTX PRO 4500 and RTX PRO 6000) need an +AlphaPulldown **2.5.0 or newer** container. Support comes from the image, not the driver: the +containers ship their own CUDA runtime as pip `nvidia-*` wheels, and pre-2.5.0 AlphaFold 3 images +bundle jaxlib 0.4.34 on CUDA 12.6, whose `ptxas` cannot target sm_120. Those images die at the very +first kernel compilation with `ptxas does not support CC 12.0` / `UNIMPLEMENTED: ptxas too old`, +before any inference runs. You cannot patch around it from outside the container — jaxlib calls its +own bundled `ptxas`, so `XLA_FLAGS=--xla_gpu_cuda_data_dir` and `PATH` have no effect, and swapping +in only a newer `ptxas` still leaves the CUDA runtime and cuDNN too old for the real kernels. + +Verified with real inference on 2.5.0 containers, with confidence scores matching the older cards: + +| GPU | Compute capability | AlphaFold 3 | AlphaFold 2 | +|-----|--------------------|-------------|-------------| +| RTX PRO 4500 Blackwell (16 GB MIG slice) | 12.0 | ✅ | ✅ | +| RTX PRO 6000 Blackwell (96 GB) | 12.0 | ✅ | ✅ | +| H100 PCIe | 9.0 | ✅ | — | +| A100 40 GB | 8.0 | ✅ | ✅ | +| RTX 3090 | 8.6 | ✅ | ✅ | + +For AF3 all three attention implementations (`triton`/Tokamax, `cudnn`, `xla`) work on Blackwell, +so no `--flash_attention_implementation` override is needed. + +#### MIG slices + +Nodes sliced with MIG (at EMBL, `gpu60-68` are RTX PRO 4500 cards split into 16 GB `1g.16gb` +instances) need no special `slurm_gres`: a plain `gpu:1` request lands on one slice and SLURM sets +`CUDA_VISIBLE_DEVICES=MIG-`. Route work to them by size with `structure_inference_gpu_tiers` +(a `min_vram_gb: 16` tier) — they suit monomers and small complexes, while larger jobs should land +on the 96 GB RTX PRO 6000 tier. + +One MIG caveat this workflow already handles: `nvidia-smi --query-gpu=memory.total` reports the +**parent card** (e.g. 32623 MiB) rather than the slice (~16 GB). Since `structure_inference_xla_mem_fraction: +auto` is `host RAM / GPU VRAM`, taking that number at face value would roughly halve the fraction and +effectively switch off host spill exactly where it is most needed. The workflow therefore reads the +slice's own profile from `nvidia-smi -L` when `CUDA_VISIBLE_DEVICES` is a MIG UUID, and falls back to +`--query-gpu` on whole cards. + +
+
Unified memory for large complexes (structure_inference_unified_memory) diff --git a/config/config.yaml b/config/config.yaml index b7be0bf..a615e7f 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -172,19 +172,28 @@ structure_inference_gpu_model: "" # gpu-el8 partition - replace nodes with your cluster's; nothing is hard-coded. # structure_inference_gpu_vram_headroom: 1.0 # <1.0 tolerates that fraction of host spill # structure_inference_gpu_tiers: +# - {min_vram_gb: 16, nodes: "gpu60,gpu61,gpu62,gpu63,gpu64,gpu65,gpu66,gpu67,gpu68"} # RTX PRO 4500 Blackwell, 16GB MIG slices # - {min_vram_gb: 24, nodes: "gpu21,gpu22,gpu29,gpu30,gpu31,gpu32,gpu33,gpu34,gpu35,gpu36,gpu37"} # RTX 3090 # - {min_vram_gb: 40, nodes: "gpu25,gpu26,gpu27,gpu28"} # A100 40GB # - {min_vram_gb: 48, nodes: "gpu40,gpu41,gpu42,gpu43,gpu44,gpu45,gpu46,gpu47,gpu48"} # L40s/A40 48GB # - {min_vram_gb: 80, nodes: "gpu38,gpu39"} # H100 PCIe 80GB -# Note: RTX PRO 6000 / Blackwell nodes (gpu50-53, 96GB at EMBL) were incompatible -# with pre-Tokamax AlphaFold 3 containers that bundled an old JAX/JAX-Triton/ptxas -# stack. Updated AF3 v3.0.2/Tokamax containers should run there; keep those nodes -# in slurm_exclude_nodes only when using old images or locally built containers that -# still fail with "ptxas too old" / UNIMPLEMENTED. +# - {min_vram_gb: 96, nodes: "gpu50,gpu51,gpu52,gpu53"} # RTX PRO 6000 Blackwell 96GB +# Blackwell (compute capability 12.0 / sm_120): RTX PRO 6000 (gpu50-53, 96GB) and +# RTX PRO 4500 (gpu60-68, sliced into 16GB MIG instances) are verified working with +# AlphaPulldown 2.5.0 containers - AF3 (jax 0.9.1/ptxas 12.9/cuDNN 9.17/Tokamax, all +# three attention implementations) and AF2 (jax 0.5.3 on ptxas 12.9/cuDNN 9.2x), with +# confidence scores matching A100/H100/3090. Only PRE-2.5.0 images fail there, at the +# first kernel compilation with "ptxas too old" / UNIMPLEMENTED; that is an image +# problem, so exclude those nodes only while you are still on an old image. +# The 16GB MIG slices suit monomers and small complexes; send bigger jobs to the +# 96GB RTX PRO 6000 cards via the tiers above. A plain "gpu:1" gres lands on a MIG +# slice correctly (SLURM sets CUDA_VISIBLE_DEVICES=MIG-...), so no gres change is +# needed to use them. # H100-SXM/H200/B200 live on the separate gpu-training partition (not routed here). # Optional: comma-separated nodes to keep structure_inference OFF, passed to sbatch # as --exclude. Useful as a fallback for GPUs the prediction container cannot use -# (e.g. a CUDA compute capability the bundled ptxas is too old for). Example: +# (e.g. a CUDA compute capability the bundled ptxas is too old for - which for +# Blackwell means a pre-2.5.0 image; see the note above). Example: # slurm_exclude_nodes: "gpu50,gpu51,gpu52,gpu53" # slurm_exclude_nodes: "" # Cap structure_inference wall time (minutes) so retry scaling (1440 * attempt) cannot diff --git a/workflow/Snakefile b/workflow/Snakefile index 29e5a7a..5ae1f41 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -679,9 +679,28 @@ rule structure_inference: unset XLA_PYTHON_CLIENT_MEM_FRACTION _aj_frac="{params.xla_mem_fraction}" if [ "$_aj_frac" = "auto" ]; then - _aj_gpu_query=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null || true) - _aj_gpu_mb="${{_aj_gpu_query%%$'\n'*}}" - _aj_gpu_mb="${{_aj_gpu_mb//[!0-9]/}}" + # On a MIG slice --query-gpu reports the *parent* card (e.g. 32623 MiB + # for a 16 GB 1g.16gb slice), which would roughly halve the fraction and + # so switch off host spill exactly where it is most needed. Read the + # slice's own profile out of `nvidia-smi -L` first, and fall back to + # --query-gpu on whole (non-MIG) cards. + _aj_gpu_mb="" + case "${{CUDA_VISIBLE_DEVICES:-}}" in + MIG-*) + _aj_mig_gb=$(nvidia-smi -L 2>/dev/null \ + | grep -F "${{CUDA_VISIBLE_DEVICES}}" \ + | sed -n 's/.*MIG [0-9]\+g\.\([0-9]\+\)gb.*/\1/p' \ + | head -1) + if [ -n "$_aj_mig_gb" ]; then + _aj_gpu_mb=$(( _aj_mig_gb * 1024 )) + fi + ;; + esac + if [ -z "$_aj_gpu_mb" ]; then + _aj_gpu_query=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null || true) + _aj_gpu_mb="${{_aj_gpu_query%%$'\n'*}}" + _aj_gpu_mb="${{_aj_gpu_mb//[!0-9]/}}" + fi if [ -n "$_aj_gpu_mb" ] && [ "$_aj_gpu_mb" -gt 0 ]; then _aj_frac=$(awk -v r={resources.mem_mb} -v g="$_aj_gpu_mb" 'BEGIN{{printf "%.3f", r/g}}') else