How scFoundry works¶
Single-cell foundation models are published as independent research codebases. Each one pins its own PyTorch version, expects its own gene vocabulary, tokenises expression its own way, and writes its embedding somewhere different. Reproducing a comparison across even three of them normally means three conda environments, three preprocessing scripts, and three sets of assumptions you have to trust.
scFoundry removes that work. Every method is wrapped in a container image, every task takes
the same .h5ad input contract, and every result lands in a predictable place under
results/. Switching models means changing one word on the command line.
scfoundry embed --method scgpt --data demo/colon_1000.h5ad
scfoundry embed --method geneformer --data demo/colon_1000.h5ad
Two layers: a command and a pipeline¶
scfoundry is a small Python program with no dependencies beyond the standard library. It
does three things: it keeps a workspace (your weights, image cache, results and run
logs), it turns a command line into a parameter file, and it launches Nextflow on the
pipeline that ships inside the package.
Nextflow is the execution engine. It pulls the container image a method needs, stages the
inputs, runs the method’s own code, publishes the outputs, and — on a cluster — submits
each process to the scheduler. You never call it directly, but everything it can do
(resume, executors, resource limits) is reachable through scfoundry.
scfoundry embed --method scgpt --data cells.h5ad
│
├─ finds the workspace, writes runs/embed/<time>_scgpt_cells/params.json
│
└─ nextflow run <pipeline>/main.nf --task embed -params-file params.json
│
└─ process embed_by_scgpt, in housy17/scgpt:0.2.4, on the GPU
│
└─ results/embeddings/scgpt/cells.h5ad
The pipeline is the same code the paper’s benchmark ran; the command is what makes it usable without reading it.
The tasks¶
Task |
What it does |
Guide |
|---|---|---|
|
Fetches a model’s official pretrained checkpoint into the workspace. Run once per model. |
|
|
Reports whether an |
|
|
Cell embeddings: zero-shot with a frozen scFM or the pretrained Census scVI, with PCA, or with a batch-integration method trained on your data. |
|
|
Labels a query set from a labelled reference using frozen embeddings and a lightweight classifier. No model parameters change. |
|
|
Updates a model’s parameters on labelled cells following its authors’ recipe, then predicts labels. |
|
|
Scores embeddings against cell-type and batch labels with the thirteen metrics of the paper. |
|
|
Measures the geometry of an embedding: effective dimension, anisotropy, neighbourhood preservation, intrinsic dimension, variance decomposition. |
The shape of every run: one input contract, one method flag, one predictable output path.¶
One container per method¶
--method does two things at once: it picks which code path runs, and it picks which
container image that code runs inside. scGPT executes in {{ registry }}/scgpt:0.2.4;
Geneformer executes in {{ registry }}/geneformer:latest. The two never share a Python
environment, so their conflicting dependency pins cannot interfere.
Nextflow bind-mounts exactly two host directories into every container:
<pipeline>/bin/ → /code model code and helper scripts
<workspace>/data/model_weights/ → /data/model_weights pretrained checkpoints
This is the whole host–container contract, and it is why a checkpoint is always referred
to as scGPT/scGPT_human — a path under /data/model_weights — regardless of where your
workspace lives.
See also
The full method-to-image mapping is in the method reference.
Three kinds of method¶
scfoundry list methods groups the 22 methods into three categories, and the
distinction matters when you read results:
zero-shot — the pretrained foundation models themselves, more than a dozen of them. Frozen weights, no labels, no batch information. This is what the benchmark ranks.
reference —
pca, a per-dataset HVG PCA: the cheap yardstick every foundation model has to beat.scvisits here too: zero-shot projection onto the CELLxGENE Census scVI, a model pretrained on tens of millions of cells — not a baseline, but not one of the transformer scFMs the paper counts either.integration —
scgpt_integrated,scvi_denovo,harmony,seurat_cca,seurat_rpca. Trained on your data using its batch labels, and nothing else. They see information the zero-shot methods never do, so they are ranked separately.
Minimal preprocessing, on purpose¶
scFoundry does almost nothing to your data before handing it to a model. That is a design decision, not an omission.
Foundation models are pretrained on raw counts across the full transcriptome, and each one maps genes to tokens using its own vocabulary. If the framework silently normalised, scaled, or subset your matrix, every model would receive input outside its pretraining distribution — and the resulting benchmark would measure the preprocessing, not the model.
So the contract is narrow and strict: raw counts in adata.X, every gene retained,
HGNC symbols in var. Quality control — filtering low-quality cells, removing doublets
— is yours to do beforehand.
Warning
Input must be raw counts over the full transcriptome. Passing log-normalised values, or an object already subset to highly variable genes, does not raise an error — it produces a plausible-looking embedding that is silently wrong. See Input data format.
Where results go¶
Everything is written under results/ in the workspace (or under --outdir). Directory
names are the method ids you typed, so a script that loops over methods can predict every
path.
results/
├── embeddings/<method>/<dataset>.h5ad embedding in adata.X
├── transfer/
│ ├── models/<method>/<classifier>/<reference>/ fitted classifier
│ └── predictions/<method>/<classifier>/<query>_predicted_labels.tsv
├── finetune/
│ ├── finetuned_models/<method>/<reference>/ fine-tuned weights
│ └── prediction/<method>/<query>_predicted_labels.tsv
├── benchmark/<method>_bio_conservation_leiden_metrics_wide.csv
└── geometry/<method>/<dataset>_<method>.csv
Every launch also leaves a record under runs/<task>/ — the exact parameters, the Nextflow
command and log — so a result can always be traced back to how it was made.
What scFoundry is not¶
It is not an analysis pipeline. There is no clustering for its own sake, no differential expression, no trajectory inference. It produces embeddings, label predictions and metric tables; what you do with them is your analysis.
It does not tune models for you. Every method runs with its authors’ defaults. That is the point of a benchmark, and it is also why a method that performs badly out of the box performs badly here.
It does not second-guess your data. If you pass log-normalised values or an HVG-subset object, the tasks will run to completion and give you a wrong answer.
Next steps¶
Install — the three requirements and the first run.
The workspace — where things live and how runs are recorded.
Quickstart — embed, score and annotate the demo data.