actionet-python/docs/svd_algorithm_benchmark.md at main · KellisLab/actionet-python · GitHub
Skip to content

Latest commit

 

History

History
154 lines (122 loc) · 7.05 KB

File metadata and controls

154 lines (122 loc) · 7.05 KB

SVD algorithm benchmark

PRIMME and Feng have been deleted from the codebase. The tables and discussion of Feng in this document are retained as the empirical basis for the retirement decision (see context/DECISIONS.md, "SVD algorithm strategy") and to keep the in-memory and backed defaults' rationale reproducible. The Feng C++ paths are no longer available; the benchmark harnesses no longer accept --include-retired. run_svd(..., algorithm="feng") and algorithm="primme" raise ValueError.

Empirical basis for the SVD auto-selection routing in _select_svd_algorithm_inmemory and _select_svd_algorithm_backed. Two benchmark harnesses feed this document:

Both harnesses run each (tier, storage, algorithm, trial) combination in a fresh subprocess so peak RSS is a clean per-case delta.

Setup

  • Dataset: stratified subsets of data/adata_agg_Scn4b_OX_fil.h5ad, generated by tests/benchmark_support.generate_all_subsets() and written to data/actionet_benchmark/scale_subset_<tier>.h5ad. Tiers: 25k, 50k, 100k, 150k, 200k cells; n_vars = 31,728 before filtering.
  • Preprocessing per run: filter_anndata(min_cells_per_feat=0.01) and normalize_anndata(target_sum=1e4, log_transform=True, log_base=2). The preprocessing wall time is not counted in the SVD timing.
  • SVD parameters: n_components = 30, seed = 42, max_iter = 0 (solver default).
  • Trials: 2 per configuration. Reference algorithm for sigma_corr is algorithm-specific: IRLB for in-memory, Halko for backed.
  • Accuracy probe: random 500-row sample for the Frobenius reconstruction error ||A_probe - U D V'||_F / ||A_probe||_F.
  • Dense in-memory cases capped at 100k cells; larger tiers would exceed the ~50 GB float64 matrix that fits in a typical HPC compute node.
  • Hardware for the reference run: macOS arm64, single node, portable build.

Raw JSONL, CSVs, and auto-generated reports live under tests/benchmark_results/svd_backed_full/ and tests/benchmark_results/svd_inmem_full/.

Results — in-memory (sparse)

Wall time (mean of 2 trials, seconds). Ratios are relative to IRLB.

tier IRLB (s) Halko (s) Feng (s) Halko / IRLB Feng / IRLB
25k 4.33 14.25 16.34 3.29 3.77
50k 8.71 28.26 34.54 3.24 3.96
100k 17.57 75.37 98.61 4.29 5.61
150k 28.15 148.85 188.17 5.29 6.68
200k 43.52 216.19 264.58 4.97 6.08

Accuracy: all three algorithms produce singular values with sigma_corr >= 0.999998 at every tier; reconstruction error agreement across algorithms is <= 1e-4 in relative Frobenius norm.

Conclusion. IRLB dominates the sparse path by 3-6x across the full tier range while remaining numerically indistinguishable from the alternatives. Default: IRLB.

Results — in-memory (dense)

Wall time (mean of 2 trials, seconds). Ratios are relative to IRLB.

tier IRLB (s) Halko (s) Feng (s) Halko / IRLB Feng / IRLB
25k 2.67 1.12 1.30 0.42 0.49
50k 5.49 2.35 2.58 0.43 0.47
100k 15.17 9.11 9.60 0.60 0.63

Accuracy: sigma_corr >= 0.999998 across all algorithms and tiers.

Conclusion. Halko is the fastest dense in-memory algorithm at every tier, beating Feng by 5-9% median wall time and IRLB by roughly 2x. The user-proposed dense = Feng routing is not supported: Feng is consistently a step behind Halko on our dense benchmark data. Default: Halko.

Results — backed (HDF5-streamed)

Wall time (mean of 2 trials, seconds). Ratios are relative to Halko.

tier Halko (s) IRLB (s) Feng (s) IRLB / Halko Feng / Halko
25k 4.41 31.37 4.47 7.11 1.01
50k 8.59 63.02 8.99 7.34 1.05
100k 17.23 125.74 18.01 7.30 1.05
150k 25.79 187.76 27.20 7.28 1.05
200k 42.18 272.76 36.77 6.47 0.87

Accuracy: sigma_corr >= 0.999998 across all algorithms and tiers vs the Halko reference.

Conclusion. IRLB's iterative refinement inflates I/O passes over backed matrices to the point of a 6.5-7.3x wall-time penalty vs Halko. Feng tracks Halko to within ~5% at tiers <=150k and edges out Halko by ~13% at 200k. Halko remains the default: its median wall time still wins across the tiers benchmarked (17.23s vs Feng 18.01s), the fixed 2*(iters+1) matvec count gives a more predictable I/O cost model at atlas scale, and Feng's crossover at 200k does not clear the 10% wall-time threshold we require for switching a documented default. Default: Halko.

Auto-selection summary

storage form matrix form auto-selected algorithm benchmark evidence
in-memory sparse IRLB 3-6x faster than Halko/Feng at 25k-200k cells
in-memory dense Halko ~5% faster than Feng, ~2x faster than IRLB at 25k-100k cells
backed any Halko ~5% faster than Feng at <=150k cells; 6.5x faster than IRLB at every tier

Reproducing

Prerequisites (one-time):

# Generate stratified tier subsets from data/adata_agg_Scn4b_OX_fil.h5ad
python -c "
import sys; sys.path.insert(0, 'tests')
from benchmark_support import generate_all_subsets
generate_all_subsets(tiers=[25000, 50000, 100000, 150000, 200000])
"

Backed benchmark:

python tests/benchmark_backed_svd_algorithm.py \
    --tiers 25k 50k 100k 150k 200k \
    --trials 2 \
    --output-dir tests/benchmark_results/svd_backed_full

In-memory benchmark (dense capped at 100k to fit typical HPC node RAM):

python tests/benchmark_svd_inmemory_defaults.py \
    --tiers 25k 50k 100k 150k 200k \
    --trials 2 \
    --skip-dense-above 100k \
    --output-dir tests/benchmark_results/svd_inmem_full

Both scripts write raw_results.jsonl, a CSV summary, and a markdown report with an automated recommendation block into the output directory.