Model Zoo¶
Choose a tile, slide, or patient encoder below. List installed presets without loading weights:
from slide2vec import list_models
list_models() # all presets
list_models("tile") # tile-level only
list_models("slide") # slide-level only
list_models("patient") # patient-level only
Tile-level encoders¶
Spacing values are supported scales, in microns per pixel. If a preset
supports several scales and has no registered default, pass
PreprocessingConfig(requested_spacing_um=...) explicitly for slide
extraction.
Registry input_size is the default final model input size. Slide
extraction reads tiles at requested_tile_size_px (default: input_size),
applies only the encoder’s photometric preprocessing (dtype, scaling,
normalization), and encodes exactly that size. No encoder-side resize or
center crop follows the read. Lunit, mSTAR, GigaPath and GPFM default to
224px; DINOv2 to 518px. Slide and patient presets inherit the default of their
tile encoder.
This is slide2vec’s declared extraction policy, not a reproduction of each
model’s published sampling protocol. Earlier releases read Lunit and mSTAR at
248px and GigaPath at 256px, then center-cropped to 224px, leaving unencoded margins
between non-overlapping tiles. A 224px grid changes the tile count and
coverage; embeddings from the two policies are not equivalent. resume
refuses to reuse tile, hierarchical or slide embeddings whose metadata records
a different requested_tile_size_px.
An off-default size requires allow_non_recommended_settings=True, an
encoder that supports variable input, and a multiple of the patch size. The
permission only allows the size; preprocessing stays geometry-preserving. For
DINOv2 matched-resolution experiments:
model = Model.from_preset("dinov2-vitb14", allow_non_recommended_settings=True)
model.embed_slides(
slides,
preprocessing=PreprocessingConfig(
requested_spacing_um=0.5, requested_tile_size_px=224,
),
)
This forwards exactly 224×224 pixels. Without the flag, an off-default request raises; 225px raises even with the flag (not a multiple of 14).
Pre-cropped images (embed_images, embed_tiles) keep each encoder’s
shipped get_transform recipe: Lunit/mSTAR Resize 248 → CenterCrop 224,
GigaPath Resize 256 → CenterCrop 224, DINOv2 Resize 518 → CenterCrop 518, GPFM
direct 224 resize. Dense extraction is unchanged.
Preset |
Model |
Output dim |
Spacing (µm/px) |
|---|---|---|---|
|
384 |
|
|
|
384 |
|
|
|
512 |
|
|
|
768 |
any ( |
|
|
768 |
|
|
|
768 |
|
|
|
768 |
|
|
|
768 / 1536 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 |
|
|
|
1024 / 2048 |
|
|
|
1280 / 2560 |
|
|
|
1280 / 2560 |
|
|
|
1536 |
|
|
|
1536 |
|
|
|
1536 |
|
|
|
1536 |
|
|
|
1536 / 3072 |
|
|
|
768 / 1536 |
|
|
|
384 / 768 |
|
|
|
1536 |
|
|
|
3072 |
|
|
|
4608 |
|
Slash-separated dimensions denote output variants. For example, Virchow2
uses cls_patch_mean (2560 dimensions) by default; select its 1280-dimensional
CLS vector with:
from slide2vec import Model
model = Model.from_preset("virchow2", output_variant="cls")
Slide-level encoders¶
Patient-level encoders¶
Patient-level encoders aggregate multiple slide embeddings for the same patient
into a single patient-level embedding. They require a patient_id column in
the input manifest (or patient_id keys in each slide dict
when using the Python API).
Preset |
Model |
Tile encoder |
Spacing (µm/px) |
Output dim |
|---|---|---|---|---|
|
|
|
768 |
Installation extras¶
Install slide2vec[fm] for the shared foundation-model dependencies, or use
the model-specific extras declared in pyproject.toml. Extras with
conflicting dependency pins need separate environments:
slide2vec[prism2]pins a different Transformers version fromfm,prism, andtitanand requires FlashAttention.slide2vec[waiv]supplies the Transformers 5 runtime forphaetandmascaret; it conflicts with thefm,prism,prism2, andtitanextras.
For example, install PRISM2 in its own environment with:
pip install "slide2vec[prism2]"
The musk, conch, and gigapath-slide presets also require upstream
packages that are not included in the PyPI extras. The tile-only gigapath
preset uses timm and does not need the GigaPath package. Install the relevant
package below:
pip install git+https://github.com/lilab-stanford/MUSK.git
pip install git+https://github.com/Mahmoodlab/CONCH.git
pip install git+https://github.com/prov-gigapath/prov-gigapath.git
Gated models require access approval on their linked Hugging Face page, plus
hf auth login or an HF_TOKEN environment variable. The base install
also includes hs2p’s sam2 dependencies for AtlasPatch tissue segmentation;
see Preprocessing to enable it.
Dense grids and attention maps¶
Tile encoders can also return a spatial patch-token grid (B, d, h, w)
instead of the pooled (B, D) vector, and most can return per-head
CLS-attention grids (B, K, h, w). See API Guide for the dense and
attention APIs.
Support varies by preset. Check it without loading weights:
from slide2vec.encoders import resolve_encoder_capabilities
capabilities = resolve_encoder_capabilities("uni2")
print(capabilities.level) # "tile"
print(capabilities.pooled) # True
print(capabilities.dense) # True
print(capabilities.attention) # True
print(capabilities.patch_size) # (14, 14)
Resolution reads the registry only: it does not instantiate the encoder,
download files, or access the network. Slide and patient reports include
tile_encoder and tile_encoder_output_variant so you can preflight the
fixed tile dependency the same way.
Custom encoder plugin package¶
An encoder owned outside this repository can behave exactly like a built-in
preset. Package it as a Python distribution with a zero-argument provider in
the slide2vec.encoders entry-point group. Installing the distribution is
enough: the Python API and CLI discover it lazily, without a manual import.
Minimal package layout¶
Create these two files in a separate repository:
my-slide2vec-encoders/
├── pyproject.toml
└── src/
└── my_slide2vec_encoders/
└── __init__.py
pyproject.toml declares the installed provider:
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
[project]
name = "my-slide2vec-encoders"
version = "0.1.0"
dependencies = ["slide2vec>=5.7", "torch", "torchvision"]
[project.entry-points."slide2vec.encoders"]
my_org = "my_slide2vec_encoders:register_encoders"
[tool.setuptools.packages.find]
where = ["src"]
src/my_slide2vec_encoders/__init__.py implements the public Encoder
contract and registers its static preset metadata:
from pathlib import Path
import torch
from torch import Tensor
from torchvision.transforms import v2
from slide2vec.encoders import (
TileEncoder,
register_encoder,
resolve_requested_output_variant,
)
CHECKPOINT = Path("/models/my-tile-model.ts")
class MyTileModel(TileEncoder):
def __init__(self, *, output_variant: str | None = None):
self._output_variant = resolve_requested_output_variant(output_variant)
self._device = torch.device("cpu")
# Loading belongs in construction, never in register_encoders().
self._model = torch.jit.load(CHECKPOINT, map_location="cpu").eval()
def get_transform(self):
# Shipped recipe, applied to given (pre-cropped) images only.
return v2.Compose([
v2.ToImage(),
v2.Resize((224, 224)),
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
])
def get_normalization_transform(self):
# Required. Photometrics only (dtype, scaling, normalization): declared
# slide runs read the requested tile size and encode exactly that size.
return v2.Compose([
v2.ToImage(),
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
])
def encode_tiles(self, batch: Tensor) -> Tensor:
return self._model(batch)
@property
def encode_dim(self) -> int:
return 768
@property
def device(self) -> torch.device:
return self._device
def to(self, device: torch.device | str):
self._device = torch.device(device)
self._model = self._model.to(self._device)
return self
def register_encoders() -> None:
register_encoder(
"my-tile-model",
level="tile",
output_variants={"default": {"encode_dim": 768}},
default_output_variant="default",
input_size=224,
supports_variable_input_size=False,
supported_spacing_um=0.5,
precision="fp16",
source="/models/my-tile-model.ts",
)(MyTileModel)
The provider must stay metadata-only: register_encoders() must not
construct an encoder, read a checkpoint, or access the network. That work
belongs to the encoder constructor.
Install and use it¶
pip install ./my-slide2vec-encoders
from slide2vec import Model, list_models
assert "my-tile-model" in list_models()
model = Model.from_preset("my-tile-model")
The same preset name works as model.name in YAML and in the CLI. For
distributed extraction, install the plugin distribution — and make its weights
and credentials reachable — in the same way on every worker and node.
Provider diagnostics¶
A provider that fails to load is skipped as a whole; built-ins and healthy
providers stay available, and list_models() emits a RuntimeWarning.
For structured access to those failures:
from slide2vec import list_encoder_provider_diagnostics
for diagnostic in list_encoder_provider_diagnostics():
print(
diagnostic.provider_key,
diagnostic.provider,
diagnostic.exception_type,
diagnostic.message,
)