Skip to content

Feature/batch small jobs#49

Merged
DimaMolod merged 10 commits into
mainfrom
feature/batch-small-jobs
Jul 9, 2026
Merged

Feature/batch small jobs#49
DimaMolod merged 10 commits into
mainfrom
feature/batch-small-jobs

Conversation

@DimaMolod

Copy link
Copy Markdown
Collaborator

No description provided.

DimaMolod and others added 10 commits June 29, 2026 09:51
Group folds into size-binned batches that share a single structure_inference
Slurm job. The job runs run_structure_prediction.py once over the whole batch,
so the model is loaded/compiled once and the queue is waited on once, instead of
per fold. Composition is decided at parse time (sequence lengths are already
resolved for length filtering / memory sizing), so no checkpoint is needed.

- common.smk: add pure, unit-tested bin_folds() that groups (fold, tokens) pairs
  by size up to batch_size folds (and an optional batch_max_tokens cap).
- Snakefile: compute BATCH_FOLDS / FOLD_BATCH at parse time. A batch's id is its
  first member, so batch_size=1 yields one singleton batch per fold whose id IS
  the fold -> identical prediction paths and DAG to before. structure_inference
  is re-keyed on {batch}: comma-joined --input/--output_directory (absl lists),
  memory sized from the largest fold, walltime scaled by fold count, GPU tier from
  the largest fold. analyze_structure stays per fold but depends on the shared
  batch sentinel via FOLD_BATCH.
- config.yaml: add batch_size (default 1, unchanged behaviour) and batch_max_tokens.
- Remove workflow/scripts/cluster_sequence_length.py (superseded by bin_folds;
  it relied on heavyweight AlphaPulldown imports and the injected snakemake object).
- test/test_bin_folds.py: unit tests for the binning logic.

Verified with snakemake dry-runs: batch_size=1 reproduces the baseline DAG
(6/6/6), batch_size=3 yields size-grouped batched jobs with per-fold analysis,
complex folds batch correctly (+ within a fold, , between folds), the
analysis-off target path resolves to batch sentinels, and non-representative
folds depend on their batch's representative sentinel.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Snakefile: when batch_size>1, ensure --allow_resume is on so a rerun of a
  crashed batch skips folds whose outputs already exist (both AF2 and AF3
  backends honour it per fold). An explicit user value is left untouched.
- README: add "Batching small jobs into one SLURM job" section.

Validated end to end (no GPU): a real Snakemake run batched two AF3 complexes
into one structure_inference job (comma-joined --input/--output_directory fanned
out to both fold dirs), the non-representative fold's analyze_structure chained
off the representative batch sentinel, and real AlphaJudge produced both
interfaces.csv + report.pdf plus the aggregated summary.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Real GPU validation on SLURM (AF3, two complexes, batch_size=2) surfaced three
issues the local/dry/no-GPU tests could not:

1. Parse-stable batch grouping. The Slurm executor re-parses the Snakefile on the
   compute node, where features are already staged, so size-grouping read from live
   token counts diverged from the login-node grouping that named the job -> the
   job's {batch} wildcard was an unknown batch id (KeyError). Group on the persisted
   sequence-length cache only (identical at every parse); empty cache -> group by
   name. Added _fold_grouping_tokens.

2. AF3 rejects --allow_resume ("not supported by backend 'alphafold3'"). Inject it
   for AlphaFold2 only.

3. AF3 merges folds passed together in one CLI call into a single combined complex
   (alphafold3_backend.predict: "merging ... into a single job"). The original
   comma-joined --input therefore produced one wrong N-chain complex for AF3.
   Redesign structure_inference to run run_structure_prediction.py ONCE PER FOLD in
   a shell loop sharing the one allocation -- correct for AF2 and AF3, still pays the
   queue wait once (issue #48's main goal). A shared --jax_compilation_cache_dir is
   set for batches so later folds reuse earlier compilations (esp. AF3 buckets).

Verified end to end on GPU: one batched job predicted both folds SEPARATELY (two
2-chain complexes, not a 4-chain merge), AlphaJudge wrote per-fold interfaces.csv +
report.pdf, and the recursive summary aggregated both. README updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
`slurm_partition` in config.yaml accepted only a single partition, so GPU
inference jobs were pinned to one queue. SLURM's `sbatch -p` natively takes a
comma-separated partition list and starts the job on whichever partition frees
up first, so support that here.

Add `normalize_partitions()` in common.smk: it accepts a single name, a
comma/space-separated string, or a YAML list and emits a de-duplicated,
comma-joined string (no spaces, so it survives the plugin's shlex.quote and
reaches sbatch verbatim). The Snakefile runs the config value through it before
setting the `slurm_partition` resource; only structure_inference uses it.

Documented in config.yaml and README; removed the now-obsolete "multi-partition
routing is out of scope" note. Added unit tests (test_normalize_partitions.py).

Verified on the EMBL cluster: config `[gpu-el8, transform]` produced
`sbatch -p gpu-el8,transform`, and SLURM scheduled the job onto the free
`transform` partition (H100 node) to COMPLETED.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Allow multiple SLURM partitions for structure inference
The multiple-partitions feature was only described in a collapsed "avoiding
unsuitable GPUs" details block, and both the README bullet and config.yaml
comment were self-contradictory ("every listed partition must accept the job"
vs "a partition the job doesn't fit is skipped"). Give it its own visible
subsection under "SLURM defaults for structure inference" with a YAML example,
and state the rule precisely: SLURM runs the job on the first listed partition
that fits and skips the rest, so at least one must accommodate it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Batched inference (batch_size > 1) added --jax_compilation_cache_dir for every
backend, but that flag is AlphaFold3-only (a JAX/XLA compile-cache path).
run_structure_prediction.py validates flags per backend and hard-errors on any
it doesn't accept, so every batched AlphaFold2 job died immediately with
`ValueError: The following flags are not supported by backend 'alphafold2':
['jax_compilation_cache_dir']`. AF2 batching was completely broken.

Gate --jax_compilation_cache_dir to AlphaFold3 only, mirroring how --allow_resume
is already gated to AlphaFold2 only. Extract the gating into a testable
common.smk helper (batch_inference_args) and add regression tests pinning each
batch-only flag to the backend that accepts it.

Found by an end-to-end AF2 run (batch_size 2, slurm_partition [gpu-el8,transform])
which now completes: both batched jobs COMPLETED and all four folds produced
structures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…ists

The per-backend flag lists were marked "common options", incomplete, and gave no
warning that run_structure_prediction.py hard-errors on a flag the selected
backend doesn't accept (ValueError "not supported by backend '<name>'") -- the
same class of issue that broke batched AF2 (--jax_compilation_cache_dir is
AF3-only). Add an IMPORTANT callout stating flags are backend-exclusive, note
that batching auto-adds the correct one per backend, point to the authoritative
per-image list (run_structure_prediction.py --help), and fill in the missing AF2
relaxation flags and the shared --use_ap_style AF3 flag.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
run_structure_prediction.py aborts the inference job on the first
structure_inference_arguments flag outside its per-backend allow set (e.g.
--allow_resume on AF3, --jax_compilation_cache_dir on AF2), deep inside a Slurm
job. Add a parse-time guard: unknown_inference_flags() mirrors the container's
_validate_flags_for_backend allow-sets and lists any user flag the selected
--fold_backend does not accept; the Snakefile logs a clear warning on the head
node in seconds. Kept a warning (not a hard error) since the container is the
source of truth, so list drift only ever produces a spurious note. Uses the raw
--fold_backend so alphalink's --crosslinks is not mis-flagged. Adds unit tests.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Batched AlphaFold3 shares one --jax_compilation_cache_dir under output_directory;
with recent tokamax-based AF3 images this can fail on some clusters (XLA autotune
cache "Device or resource busy" on BeeGFS; H100 tokamax autotuning cache aborts at
load). Advise batch_size: 1 for AF3 when jobs crash during compilation. AF2
batching is unaffected.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@DimaMolod
DimaMolod merged commit ed56993 into main Jul 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant