Skip to content

Quickstart

This page runs M3 end to end on the built-in demo dataset — no downloads. Every snippet uses the real public API; for fully rendered, executed versions (with figures and outputs) see the tutorials.

Prerequisites

pip install m3-sc — that is all. PyTorch, scanpy, umap-learn and matplotlib all come along with it; see Installation.

0. Load the demo data

m3.datasets.liu_demo() returns a ready-to-use Dataset: a stratified subsample of the Liu et al. COVID-19 dataset (RNA + ADT, three batches).

import m3

data = m3.datasets.liu_demo()
print(data)
# Dataset(n_cells=30534, batches=['B1', 'B2', 'B3'], modalities=[rna:1000, adt:192])

The relevant obs columns are cond_group (HC / Severe), mergedcelltype, sample_id (donor), batch, and Age_interval.

1. Representation learning

Build a model by declaring which obs columns play which role, then train. For pure embedding, switch the donor predictor off.

model = m3.M3(
    data,
    condition_keys=["cond_group", "Age_interval"],
    celltype_key="mergedcelltype",
    embedding_dim=30,
)
model.train(max_epochs=500, donor_prediction=False)

emb = model.embedding(part="bio")        # (n_cells, d) condition-aware embedding
meta = model.cell_metadata               # row-aligned metadata
print(emb.shape)

Feed emb straight into a UMAP coloured by cell type (biology preserved) and by batch (mixed). See Tutorial 1 for the plotting code.

2. Patient-level disease prediction

Hold a batch out as an unlabelled query, supply donor_key + celltype_key (which auto-enables the donor predictor), and tune it via donor_predictor.

model = m3.M3(
    data,
    condition_keys=["cond_group", "Age_interval"],
    target_condition="cond_group",
    celltype_key="mergedcelltype",
    donor_key="sample_id",
    batch_key="batch",
    held_out=["B3"],                 # B3 labels are masked during training
    embedding_dim=30,
)
model.train(
    max_epochs=500,
    donor_predictor={"glr": 3e-3, "n_epochs": 120, "adv_max": 10,
                     "adv_warmup": 7, "n_disc": 21, "patient_w": 10},
)

preds = model.predict_donors()           # held-out donors only
print(preds[["donor", "predicted_label", "prob_Severe"]])

predict_donors() returns one row per held-out donor with the predicted label and a probability per class. The corrected per-donor vectors are available from donor_embedding() for a patient-level UMAP. Full walkthrough: Tutorial 2.

3. Feature attribution

Train with the donor predictor (the default when donor_key + celltype_key are set), then attribute the disease condition against a healthy baseline.

model = m3.M3(
    data,
    condition_keys=["cond_group", "Age_interval"],
    target_condition="cond_group",
    celltype_key="mergedcelltype",
    donor_key="sample_id",
    batch_key="batch",
    embedding_dim=30,
)
model.train(max_epochs=500)

attr = model.attribute(reference_labels=["HC"])      # Severe vs HC
attr.top_celltypes(min_cells_per_condition=200)      # ranked cell types
attr.top_genes(n=100, min_cells_per_condition=200, modality="rna")

top_genes applies the publication recipe (per–cell-type balancing, housekeeping-gene exclusion); attr.gene_celltype_matrix is the signed cell-type × gene matrix behind it. See Tutorial 3.

4. Data augmentation

Synthesise new donors per condition — optionally stratified by batch — or posterior-resample cells 1:1.

aug = model.augment(conditions=["HC", "Severe"], n_donors=[3, 3], tau=0.8)
syn_rna = aug["expression"]["rna"]       # (n_synth_cells, n_genes)
syn_obs = aug["obs"]                     # condition / donor / cell-type labels

gen = model.generate(tau=0.8)            # one synthetic cell per reference cell

Pass batch="B1" to augment to template only from that batch. Full example with the batch-stratified UMAP: Tutorial 4.


Where to next

  • The four tutorials — the same workflow, fully executed with figures.
  • The API reference — every argument and return type.
  • How M3 works — the model and the six tasks.