Skip to content

Fix/scbutterfly - #81

Merged
rcannood merged 8 commits into
mainfrom
fix/scbutterfly-cell-scale
Oct 9, 2026
Merged

rcannood merged 8 commits into
mainfrom
fix/scbutterfly-cell-scale

Conversation

@VladimirShitov

@VladimirShitov VladimirShitov commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Describe your changes

Fix incorrect and suboptimal behavior of scbutterfluy:

  • Fixes incorrect chromosome parsing that caused OOM error
  • Applies scaling, similar to Restore the per-cell scale of senkin_tmp and ss_opm predictions #80 to maximise metrics that depend on scale
  • Predicts the entire set of genes instead of HVGs
  • Applies a bunch of optimisations (most are in common_butterfly.py to make scbutterfly calculation feasible on 2022 dataset

Checklist before requesting a review

  • I have performed a self-review of my code

  • Check the correct box. Does this PR contain:

    • Breaking changes
    • New functionality
    • Major changes
    • Minor changes
    • Bug fixes
  • Proposed changes are described in the CHANGELOG.md

  • CI Tests succeed and look good!

Vladimir Shitov and others added 7 commits October 5, 2026 03:02
Both 2022 competition solutions predict a z-scored profile per cell (the
competition scored per-cell Pearson only). Mapping that back with one global
slope and intercept gave every predicted cell the same mean and standard
deviation, so per-gene correlations, overall correlations and RMSE/MAE scored
the missing per-cell level rather than the methods.

src/utils/cell_scale.py predicts each cell's target mean and log standard
deviation from its input (ridge regression on a truncated SVD of the
normalized input plus two sequencing-depth features) and restores them, with
the spread shrunk by one least-squares factor fitted on training-cell
predictions (out-of-fold for senkin_tmp). Per-cell correlations are
unchanged. ss_opm_predict keeps the old global map for model bundles trained
before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… on the scored scale

- chrom_utils.parse_chrom: split peak names on the first ':' or '-'. NeurIPS 2022 names
  peaks chr1:start-end, so every peak became its own chromosome with its own encoder
  block: pbmc_multiome was OOM-killed (ATAC -> GEX, 174,978 "chromosomes") or hit the
  8 h limit (GEX -> ATAC, 7,002 "chromosomes") on rc7.
- Keep scButterfly's HVG selection and peak filter for the input modality only, so every
  target gene/peak is modelled instead of zero-filled.
- target_scale.py: convert GEX predictions exactly from scButterfly's median-library-size
  log1p to log CP10k; map ATAC predictions onto the dataset's TF-IDF with one
  least-squares line per peak (slope >= 0), fitted on the held-out validation cells.
- Patch Model.__init__ to serve cells as dense rows of the sparse matrix instead of
  densifying both modalities (92 GB for the 2022 ATAC input).
- Model bundles without metadata["model_all_target_features"] keep the old preprocessing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ll in DataLoader workers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e labels

- target_scale.ScaleCalibration: map both GEX and ATAC predictions with one
  least-squares line fitted on the held-out validation cells. On the 2021 and 2022
  Multiome datasets it matched or beat per-feature lines and, for GEX, the exact
  log CP10k conversion (which inflates the decoder's conditional means for sparse
  genes: RMSE 0.553 vs 0.518 on bmmc_multiome); it leaves every correlation as is.
- predict_cells: give the direction Model.test does not need a single cell.
- read_modality drops unused layers/obsm; _to_counts_X takes the counts layer out
  of its input; build_butterfly frees intermediate copies.
- train: veryhighmem + veryhightime; predict: veryhighmem.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lls show no positive association

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace scbutterfly's own scale map (target_scale.py) with CellScale, which ss_opm and
senkin_tmp already use: scbutterfly_train fits its ridge model on the training cells and
its spread shrinkage on the held-out validation cells (predicted with the saved
weights) and saves cell_scale.npz; scbutterfly_predict applies it. Bundles without the
file keep scButterfly's own output.

Also reuse library functions in chrom_utils: np.argsort/np.unique for the chromosome
order and counts, itertools.groupby for run lengths, pd.Index.get_indexer to scatter
predictions by name; and share the held-out split through validation_cells().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- type: nextflow
directives:
label: [highmem, hightime, midcpu, highsharedmem, gpu]
label: [veryhighmem, hightime, midcpu, highsharedmem, gpu]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

veryhighmem likely won't affect the execution of this component, because the gpu nodes are constrained in memory. you could switch to a different node using biggpu.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll change it to biggpu. It might actually not be needed after the optimizations, but let's go big to be on the safe side and then roll back if we can

Base automatically changed from fix/per-cell-scale to main October 8, 2026 07:29
Comment thread src/methods/scbutterfly/scbutterfly_predict/config.vsh.yaml Outdated
@rcannood
rcannood merged commit a065cbb into main Oct 9, 2026
6 checks passed
@rcannood
rcannood deleted the fix/scbutterfly-cell-scale branch October 9, 2026 08:09
@rcannood rcannood mentioned this pull request Oct 9, 2026
3 of 8 tasks
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.

2 participants