FrancescaDr's picture
Update ovarian_xenium/heldout_split/README.md
86ab4de verified
|
Raw History Blame Contribute Delete
5.2 kB
metadata
license: bsd-3-clause
library_name: interscale
tags:
  - spatial-transcriptomics
  - xenium
  - cell-cell-communication
  - graph-neural-network
  - transformer
  - single-cell

InterScale — 10x Xenium human ovarian adenocarcinoma (held-out-split model)

Pre-trained InterScale model (Drummer, Jiménez et al., bioRxiv 2026) for the 10x Xenium human ovarian adenocarcinoma section used in the cell–cell communication chapter of the single-cell best-practices book. It is the model trained in the tutorial notebook notebooks/psls_ccc/interscale_ovarian.ipynb. Loading it lets you skip training and go straight to the net-flow and gene-programme analyses.

InterScale combines a local GCN over the spatial neighbour graph with a global transformer over all cells of a tissue window. Each component reconstructs masked expression through its own decoder (dual_decoder: true). The transformer's cell-by-cell attention is what the net-flow analysis reads as directed communication between cell types.

Files

file contents
model.pt trained weights, InterScale save format ({"model_state_dict": ...}), 20 MB
config.yaml full resolved config the weights were trained with; only the two local paths are blanked
genes.tsv the 3,000 input genes in model order, with their Moran's I
metrics.json scores of this exact file on the held-out test windows

Loading

Needs interscale from main at or after commit c98a307, the version it was trained with.

from huggingface_hub import snapshot_download
import interscale
from interscale.config import load_config

d = snapshot_download("theislab/InterScale", allow_patterns="ovarian_xenium/heldout_split/*")
d = f"{d}/ovarian_xenium/heldout_split"

cfg = load_config(f"{d}/config.yaml")

# `adata` must be prepared as described under "Input" below
interscale.model.CombinedModel._setup_anndata(
    adata=adata,
    prediction_task="regression",
    layer_key="log1p_norm",
    sample_key_list=["sliding_window"],
    split_key=None,
)
model = interscale.model.CombinedModel.load(
    d, adata, cfg, model_name="", local_component=True, global_component=True
)
result = model.get_model_output(adata)  # .obsm["_attn_matrix"], ["_local_emb"], ["_global_emb"],
                                        # .layers["_y_pred_local"], ["_y_pred_global"]

load raises if the config does not describe the checkpoint, so a model that loads is the trained model. It will not silently keep random weights. The recipe above was checked by reloading this folder and comparing all weights bit for bit.

Input

The model expects the tutorial's preprocessing. Section 2 of interscale_ovarian.ipynb does all of it:

  • Expression: adata.layers["log1p_norm"] = log1p(normalize_total(counts)).
  • Genes: exactly the 3,000 genes of genes.tsv, in that order (adata = adata[:, genes].copy()). They are the most spatially variable genes of the 4,447-gene panel by Moran's I (radius-30 µm graph, whole slide).
  • Windows: adata.obs["sliding_window"], 600 µm non-overlapping tiles of the slide made with interscale.pp.sliding_window, with windows of fewer than 50 cells dropped. The model builds a radius-30 µm neighbour graph inside each window.
  • Window size limit: the largest window must have at most 3,167 cells, the config's max_seq_len. For larger windows, raise model.global_component.parameters.max_seq_len in the config. A too-small value silently subsamples windows.
  • adata.obsm["spatial"] in µm.

Training

data one section, 400,600 cells, 199 windows (mean 2,013 cells)
split over windows, 70 / 15 / 15 → 139 train / 29 val / 31 test, seed 44
objective node-level reconstruction, cell masking at 30 %, SmoothL1 on the masked cells
architecture 2-layer GCN (hidden 512, dropout 0.1) → 2-layer transformer (4 heads, FF 512, dropout 0) → linear decoders, latent width 256
optimisation lr 0.003, weight decay 0.001, cosine schedule with 10-epoch warm-up, batch 2 windows, early stopping on val loss (stopped at epoch 242 of max 600)
hardware 1× NVIDIA H100 80 GB, ~17 min

The hyperparameters are the best of a 48-trial random sweep over masking strategy (cell 10/30/50 %, gene 25/50/75 %), latent width (32–256), GCN/transformer size, dropout, learning rate, weight decay and batch size. The best config was then re-trained at three seeds and was stable across them, with a spread under 0.01 in r.

Evaluation

Scored on the 31 held-out test windows (65,804 cells), as the median over genes of the per-gene Pearson r. The masks are fixed (seed 2026), so other models can be compared on the same entries.

test condition local decoder global decoder
30 % of cells fully masked (the training task) 0.163 0.165
50 % of (cell, gene) entries masked 0.165 0.167
no masking (what get_model_output returns) 0.175 0.160

Citation

Drummer, F., Jiménez, S. et al. InterScale. bioRxiv (2026). Code: https://github.com/theislab/interscale