API Guide¶
Use Model for in-memory slide and patient embeddings, image artifacts,
or dense grids. Use Pipeline for manifest-driven slide processing. See
Getting Started for installation and a first slide.
Input and outcome |
Entry point |
|---|---|
Slides → in-memory tile or slide embeddings |
|
Manifest → saved slide artifacts |
|
A patient’s slides → patient embedding |
|
Image files → saved vectors |
|
Slide coordinates or image files → saved dense grids |
|
Augmented tensors → live dense grids |
EmbeddedSlide¶
embed_slide returns one EmbeddedSlide when the run
produces a single annotation bag. A string annotation selects one bag;
a list selects several and returns them in the requested order.
embed_slides returns {sample_id: {annotation: EmbeddedSlide}}.
See Annotation-Aware Sampling for examples.
- class slide2vec.EmbeddedSlide(*, sample_id, tile_embeddings, slide_embedding, x, y, tile_size_lv0, image_path, mask_path=None, annotation=None, num_tiles=None, mask_preview_path=None, tiling_preview_path=None, latents=None, encoder_input_size_px=None)¶
Bases:
objectIn-memory result of embedding a single slide.
- tile_embeddings: Any¶
Tile embeddings —
torch.Tensorof shape(N, D).
- slide_embedding: Any | None¶
Slide-level embedding —
torch.Tensorof shape(D,)for slide-level encoders;Nonefor tile-only encoders.
- annotation: str | None = None¶
Annotation class this bag of tiles was sampled for.
"tissue"for the default tissue-only path,"merged"for the union output mode, or the class name (e.g."tumor") when annotation-aware sampling fans a slide out into one bag per class. See the annotation-aware sampling documentation.
PreprocessingConfig¶
See Preprocessing for the PreprocessingConfig
field reference, readers, segmentation, annotation sampling, and previews.
ExecutionOptions¶
- class slide2vec.ExecutionOptions(*, output_dir=None, output_format='pt', batch_size=32, num_workers_per_gpu=None, num_preprocessing_workers=None, num_gpus=None, precision=None, output_dtype=None, prefetch_factor=4, save_tile_embeddings=False, save_slide_embeddings=False, save_latents=False)¶
Bases:
objectRuntime execution and output settings.
- num_workers_per_gpu: int | None = None¶
DataLoader worker count per GPU rank.
Nonemeans auto (capped by CPU / SLURM limit, then split across the resolved GPU count). Image-only routes safely use zero when auto selection happens after model loading.
- num_preprocessing_workers: int | None = None¶
Tiling worker count.
Nonemeans auto (capped by CPU / SLURM limit).
- precision: str | None = None¶
Forward-pass dtype —
"fp16","bf16","fp32", orNone(auto-determined from the model preset).
- output_dtype: str | None = None¶
Feature output dtype —
"fp16","fp32", orNoneto followprecision(fp16 → fp16, else fp32). Applies to live dense grids and to tile, slide, hierarchical, and patient artifacts;"bf16"is rejected because persisted features cross a numpy boundary.
- save_tile_embeddings: bool = False¶
Persist tile embeddings to disk when running a slide-level model.
Pipeline¶
Use Pipeline for manifest-driven batch processing and disk
outputs:
from slide2vec import ExecutionOptions, Model, Pipeline, PreprocessingConfig
model = Model.from_preset("virchow2")
pipeline = Pipeline(
model=model,
preprocessing=PreprocessingConfig(
requested_spacing_um=0.5,
requested_tile_size_px=224,
masks={"min_coverage": {"tissue": 0.1}},
),
execution=ExecutionOptions(output_dir="outputs/demo", num_gpus=2),
)
result = pipeline.run(manifest_path="/path/to/slides.csv")
See Input Manifest for the full manifest schema.
Pipeline.run(...) returns a RunResult:
- class slide2vec.RunResult(*, tile_artifacts, hierarchical_artifacts, slide_artifacts, patient_artifacts=<factory>, process_list_path=None)¶
Bases:
objectReturn value of
Pipeline.run().- tile_artifacts: list[TileEmbeddingArtifact]¶
Tile embedding artifacts written to disk.
- hierarchical_artifacts: list[HierarchicalEmbeddingArtifact]¶
Hierarchical embedding artifacts; empty when hierarchical mode is disabled.
- slide_artifacts: list[SlideEmbeddingArtifact]¶
Slide embedding artifacts written to disk.
See Output Layout for the full on-disk directory structure and file schemas.
Per-slide completion callback¶
Pipeline.run_with_coordinates(coordinates_dir, *, slides=None,
on_slide_persisted=None) and Model.embed_tiles(slides, tiling_results, *,
preprocessing=None, execution=None, on_slide_persisted=None) accept an
optional on_slide_persisted callable. slide2vec calls it in the calling
process, synchronously, once per persisted (sample_id, annotation) work
unit with that unit’s TileEmbeddingArtifact (or
HierarchicalEmbeddingArtifact under hierarchical
preprocessing), after the artifact file is complete on disk and before the
entry point returns. With num_gpus > 1 it fires as each rank reports a
finished slide, not after the whole stage returns.
def commit(artifact):
print(artifact.sample_id, artifact.path)
result = pipeline.run_with_coordinates("outputs/demo", on_slide_persisted=commit)
Zero-tile slides, slides skipped by resume, and slides that fail do not
fire the callback. An exception raised inside it propagates out of the entry
point. The return value is unchanged and still lists every artifact.
Hierarchical Feature Extraction¶
Enable hierarchical mode by setting region_tile_multiple in
PreprocessingConfig:
from slide2vec import PreprocessingConfig
preprocessing = PreprocessingConfig(
requested_spacing_um=0.5,
requested_tile_size_px=224,
region_tile_multiple=6, # 6×6 = 36 tiles per region
)
The tile embeddings tensor will have shape (R, T, D) instead of (N, D).
See Hierarchical Features for the full explanation.
Patient-level embedding¶
For patient-level models, use embed_patient() for a single patient
or embed_patients() for a batch.
Single patient¶
from slide2vec import Model
model = Model.from_preset("moozy")
result = model.embed_patient(
["/data/slide_1a.svs", "/data/slide_1b.svs"],
patient_id="patient_1",
)
print(result.patient_id) # "patient_1"
print(result.patient_embedding.shape) # torch.Size([768])
print(result.slide_embeddings) # {"slide_1a": tensor, "slide_1b": tensor}
Multiple patients¶
results = model.embed_patients(
[
{"sample_id": "slide_1a", "image_path": "/data/slide_1a.svs", "patient_id": "patient_1"},
{"sample_id": "slide_1b", "image_path": "/data/slide_1b.svs", "patient_id": "patient_1"},
{"sample_id": "slide_2a", "image_path": "/data/slide_2a.svs", "patient_id": "patient_2"},
]
)
for r in results:
print(r.patient_id, r.patient_embedding.shape)
embed_patients(...) returns one EmbeddedPatient per unique patient,
ordered by first appearance.
- class slide2vec.EmbeddedPatient(*, patient_id, patient_embedding, slide_embeddings)¶
Bases:
objectIn-memory result of embedding a single patient.
- patient_embedding: Any¶
Aggregated patient embedding —
torch.Tensorof shape(D,).
- slide_embeddings: dict[str, Any]¶
Slide-level embeddings keyed by
sample_id— each atorch.Tensorof shape(D,).
Images to Embeddings¶
When your images already exist as files — a patch benchmark (BACH, CRC,
PCam, …) or an exported ROI set — there is no slide to tile.
embed_images() encodes those images directly and writes one
embedding artifact per image:
from slide2vec import ExecutionOptions, ImageSpec, Model
model = Model.from_preset("virchow2")
artifacts = model.embed_images(
[
ImageSpec(sample_id="bach-001", image_path="/data/bach/001.tif"),
ImageSpec(sample_id="bach-002", image_path="/data/bach/002.tif"),
],
execution=ExecutionOptions(output_dir="outputs/bach", num_gpus=2),
)
print(artifacts[0].path) # outputs/bach/image_embeddings/bach-001.pt
print(artifacts[0].feature_dim) # 2560
The run uses the GPUs selected by ExecutionOptions.num_gpus and resumes
automatically when repeated with the same output directory. sample_id is the
artifact’s identity and must be unique within a run; slide2vec never derives
it from the filename. Mixed-size inputs are supported: each image goes through
the encoder’s shipped transform before batching. spacing_at_level_0 is
not accepted by this pooled image API; use dense extraction when physical
spacing is part of the request.
- class slide2vec.ImageSpec(*, sample_id, image_path, spacing_at_level_0=None)¶
Bases:
objectOne named image source:
(sample_id, image_path, spacing_at_level_0).The input unit of
Model.embed_images()— the Given-geometry counterpart ofSlideRegions.spacing_at_level_0is the optional finite positive caller declaration used by hs2p to resolve source level-0 spacing. Flat PNG/JPEG sources have no embedded spacing and therefore require it for dense extraction.sample_idis the artifact’s whole identity, so it must be unique within a run and a valid filename component.
- class slide2vec.ImageEmbeddingArtifact(*, sample_id, path, metadata_path, format, feature_dim)¶
Bases:
objectOne persisted given-geometry image embedding: the
(D,)payload + its sidecar.The unit of
slide2vec.api.Model.embed_images(): a caller holding pre-cropped tile images (a public patch benchmark) gets one artifact per image, named by thesample_idit supplied. Unlike a tile artifact this holds a single vector, not a bag — the image is the sample.
Live Dense Encoding after Augmentation¶
Use prepare_dense_encoder() when your training or inference loop
already owns image/mask reading and joint augmentation. You hand slide2vec one
CPU RGB uint8 tensor in (3, H, W) layout; slide2vec owns normalization,
padding, device transfer, and the frozen no-grad encode.
import torch
from slide2vec import DenseImageOptions, ExecutionOptions, Model
model = Model.from_preset("virchow2", device="cuda")
kit = model.prepare_dense_encoder(
dense=DenseImageOptions(
target_size=(1024, 768),
window_size=224,
overlap=0.5,
feature_kind="patch_features",
),
execution=ExecutionOptions(precision="fp16", output_dtype="fp32"),
)
preprocess = kit.preprocessor() # lightweight and safe to pickle into workers
items = [preprocess(augmented_rgb_uint8_chw) for augmented_rgb_uint8_chw in images]
cpu_batch = torch.stack(items) # batching starts after item preprocessing
grids = kit.encode(cpu_batch)
print(cpu_batch.shape) # (B, 3, Henc, Wenc), on CPU
print(grids.shape) # (B, D, Gh, Gw), on the model device
preprocessor() accepts one unbatched CPU uint8 RGB tensor whose
(H, W) equals kit.geometry.target_size — it never resizes or crops. It
applies the encoder’s normalization and bottom/right padding and returns a CPU
floating-point tensor ready for normal DataLoader collation.
encode(batch) moves the collated batch to the model device and returns an
on-device grid with no gradient history, in ExecutionOptions.output_dtype
(or the same precision-derived default as persisted dense extraction). D is
the patch-feature dimension for feature_kind="patch_features"; for
"cls_attention" it is the selected block/head/prefix-query channel count.
The immutable kit.geometry is authoritative:
target_size— required augmented input(H, W);patch_size— encoder patch(Ph, Pw);encoded_size— padded encoder input(Henc, Wenc);grid_shape— output(Gh, Gw);pad—(bottom, right)padding;crop_box—(left, top, right, bottom)box for mapping the padded extent back to the target.
The kit uses only the encoding fields of DenseImageOptions /
DenseOptions (target_size, padding, window/overlap, feature kind,
attention selection); source-reading fields are ignored, and this path never
reads files or writes artifacts. Reuse one prepared kit across loops or folds
with the same geometry.
- class slide2vec.DenseEncodeKit(loaded, plan)¶
Bases:
objectA shareable live dense encoder for already-augmented RGB tensors.
This is deliberately a plain object rather than
torch.nn.Module; the foundation encoder is private and cannot be registered accidentally by assigning the kit to a trainable decoder.- property geometry: DenseEncodeGeometry¶
The authoritative immutable input, padding, and output-grid geometry.
- preprocessor()¶
Return the serializable itemwise CPU preprocessor.
- class slide2vec.DenseEncodeGeometry(target_size, patch_size, encoded_size, grid_shape, pad, crop_box)¶
Bases:
objectImmutable geometry of a live dense encoding run.
All sizes are
(height, width)exceptcrop_box, which follows the common(left, top, right, bottom)convention. Padding is bottom/right only.
Persisted Region Grids¶
embed_regions_dense() accepts level-0 point coordinates and the
same optional source-spacing declaration as dense images:
from slide2vec import DenseOptions, ExecutionOptions, Model, SlideRegions
model = Model.from_preset("virchow2")
artifacts = model.embed_regions_dense(
[SlideRegions(
sample_id="slide-1",
image_path="/data/slide-1.svs",
coordinates=[[1024, 2048], [4096, 2048]],
spacing_at_level_0=0.252,
)],
dense=DenseOptions(spacing_um=0.5, target_size=224),
execution=ExecutionOptions(output_dir="outputs"),
)
Coordinates stay in the source level-0 pixel frame. Encoder inputs that differ from the encoder’s registered size require an encoder that supports variable input; slide2vec derives the necessary model settings from the declared geometry, and fixed-input encoders fail before any region is read.
Dense Grids from Images¶
When the supervision arrives as image/mask pairs rather than slides —
segmentation and detection datasets, exported ROI sets —
embed_images_dense() is the image-sourced counterpart of
embed_regions_dense: the image is the region, so there is no ROI
coordinate plan.
from slide2vec import DenseImageOptions, ExecutionOptions, ImageSpec, Model
model = Model.from_preset("virchow2")
artifacts = model.embed_images_dense(
[
ImageSpec(sample_id="ocelot-001", image_path="/data/ocelot/001.jpg",
spacing_at_level_0=0.25),
ImageSpec(sample_id="ocelot-002", image_path="/data/ocelot/002.jpg",
spacing_at_level_0=0.25),
],
dense=DenseImageOptions(
target_size=1024,
spacing_um=0.5,
window_size=224,
),
execution=ExecutionOptions(output_dir="outputs/ocelot", num_gpus=2),
)
print(artifacts[0].path) # outputs/ocelot/dense_image_embeddings/ocelot-001.pt
print(artifacts[0].grid_shape) # (74, 74) after padding 1024 to 1036 pixels
The image and region APIs share padding, whole-image or sliding-window
encoding, and the feature_kind choice. The run uses the GPUs selected by
ExecutionOptions.num_gpus and automatically reuses compatible artifacts
when repeated with the same output directory.
PNG/JPEG inputs require ImageSpec.spacing_at_level_0, because they carry
no embedded physical spacing. target_size is a declaration, not a resize:
every image must arrive at exactly target_size after reading, so a dataset
whose images differ in size is several runs, one per geometry.
- class slide2vec.DenseImageOptions(*, target_size, spacing_um=None, tolerance=0.05, backend='auto', pad_mode='reflect', image_pad_value=None, window_size=None, overlap=0.0, feature_kind='patch_features', attention_blocks=(-1,), attention_include_registers=False)¶
Bases:
objectDense
(d, gh, gw)extraction over pre-cropped images.Every supported source uses hs2p’s spacing-aware reader contract.
.png,.jpg, and.jpeginputs use hs2p’s one-level PIL reader and therefore requireImageSpec.spacing_at_level_0; WSI readers may resolve native metadata instead. hs2p resolves source spacing, backend, pyramid level, tolerance, complete-extent read, and permitted area downsampling at the requested run-levelspacing_um. Omitted spacing resolves the encoder’s single registry default.ImageSpec.spacing_at_level_0is the optional caller declaration used by hs2p when resolving level-0 spacing.target_sizeis always a strict post-read declaration, never a fit-to-size request: each final pixel array must already be exactly this size. Declaring it up front lets the effective encoder input be validated (and variable-input constructor settings resolved) before model loading or pixel decoding. Differing final geometries therefore require separate runs.- target_size: int | tuple[int, int]¶
a square side length, or an explicit
(height, width)for non-square images.- Type:
Supervision geometry in pixels the dense grid registers to
- spacing_um: float | None = None¶
Positive, finite requested run spacing in µm/px.
Noneresolves the encoder’s single registry default.
- tolerance: float = 0.05¶
Relative spacing tolerance used by hs2p for spacing-readable level selection; raster reads have no tolerance result.
- backend: str = 'auto'¶
Requested hs2p backend for spacing-readable inputs.
"auto"is resolved in the parent; raster images always resolve to Pillow.
- pad_mode: str = 'reflect'¶
Padding mode used to pad the image up to the encoder’s patch multiple. One of
"reflect"/"replicate"/"constant"/"zero".
- image_pad_value: float | None = None¶
Constant fill value for
pad_mode in {"constant", "zero"}(ignored otherwise).
- window_size: int | None = None¶
Encoder field-of-view chunk fed through the backbone per forward.
None(default) is one whole-image forward; a smaller value slides the encoder and blends token grids.
- overlap: float = 0.0¶
Fractional window overlap in
[0, 1)for the sliding path (ignored whenwindow_size is None).
- feature_kind: str = 'patch_features'¶
"patch_features"(the patch-token grid) or"cls_attention"(CLS/register self-attention grid).
- class slide2vec.DenseImageArtifact(*, sample_id, path, metadata_path, feature_dim, grid_shape)¶
Bases:
objectOne persisted dense grid over a pre-cropped image: payload + geometry sidecar.
The unit of
slide2vec.api.Model.embed_images_dense(). Same payload as aDenseRegionArtifact— a(d, gh, gw)grid plus the geometry that produced it — but named the way a given-geometry input can be named: by the caller’ssample_idalone, since there is no slide, no level-0 coordinate and no sampled class.
Dense Attention Map Extraction¶
Most ViT tile encoders can also return their per-head prefix-token
self-attention as a dense spatial grid. This is the attention analog of
encode_tiles_dense and uses the same get_normalization_transform().
encode_tiles_attention(batch, *, blocks=(-1,), include_registers=False)accepts a normalized(B, C, H, W)tensor and returns(B, K, h, w).K = len(blocks) * (1 + M·include_registers) * nh, wherenhis the head count andMthe model’s register-token count. Heads are never reduced.Channels are stacked in the deterministic order
[block][cls, reg…][head]. The CLS channels do not depend oninclude_registers— registers only append channels.blocksselects transformer blocks (negative indices count from the end);include_registersadds the register-token query rows for models that carry them (e.g. Hibou).
Example:
import torch
from PIL import Image
from slide2vec.encoders import encoder_registry
encoder = encoder_registry.require("lunit")().to("cuda")
transform = encoder.get_normalization_transform()
tile = Image.open("/data/tile.png").convert("RGB")
batch = transform(tile).unsqueeze(0).to(encoder.device)
with torch.no_grad():
attn = encoder.encode_tiles_attention(batch) # last block, CLS only
print(attn.shape) # (1, nh, 28, 28) for a 224 px Lunit tile
Each value is a softmax weight: one query row’s attention over the patch keys,
so values are non-negative and a channel’s spatial sum is <= 1 (the
prefix-token key columns carry the remaining mass). The input must be divisible
by the encoder patch size.
Method and artifact reference¶
- class slide2vec.Model(*, name, device='auto', output_variant=None, allow_non_recommended_settings=False)¶
Bases:
object- classmethod from_preset(name, *, output_variant=None, allow_non_recommended_settings=False, device='auto')¶
- Return type:
- prepare_dense_encoder(*, dense, execution=None)¶
Prepare live dense encoding for one augmented RGB tensor at a time.
Only the encoding fields shared by
DenseImageOptionsandDenseOptionsapply after the augmented-pixel handoff. Source-reading fields (spacing, tolerance, and backend) are intentionally ignored.
- embed_tiles(slides, tiling_results, *, preprocessing=None, execution=None, on_slide_persisted=None)¶
- Return type:
list[TileEmbeddingArtifact] |list[HierarchicalEmbeddingArtifact]
- aggregate_tiles(tile_artifacts, *, preprocessing=None, execution=None)¶
- Return type:
- embed_slide(slide, *, annotation=None, preprocessing=None, execution=None, sample_id=None, mask_path=None, spacing_at_level_0=None)¶
- Return type:
- embed_slides(slides, *, annotations=None, preprocessing=None, execution=None)¶
- Return type:
dict[str,dict[str,EmbeddedSlide]]
- embed_patient(slides, patient_id=None, *, preprocessing=None, execution=None)¶
Embed a single patient’s slides and return one
EmbeddedPatient.Convenience wrapper around
embed_patients()for the common case where all slides belong to the same patient.- Parameters:
slides (
Sequence[str|Path|Mapping[str,object] |SlideLike|SlideSpec]) – All slides for this patient.patient_id (
str|None) – Optional patient identifier applied to every slide. When omitted,patient_idis read from slide dict keys or object attributes; slides that carry nopatient_idfall back tosample_id.
- Return type:
- embed_patients(slides, patient_id_map=None, *, preprocessing=None, execution=None)¶
Embed slides and aggregate them into patient-level embeddings.
Requires a patient-level model (e.g.
moozy). For each patient all contributing slide embeddings are aggregated by the model’sencode_patientmethod.- Parameters:
slides (
Sequence[str|Path|Mapping[str,object] |SlideLike|SlideSpec]) – Slides to process. Each entry may be a path, aSlideSpec, or a dict withsample_id/image_pathkeys. When patient_id_map isNoneapatient_idkey in each dict is used to group slides.patient_id_map (
dict|None) – Optional explicit{sample_id: patient_id}mapping. When provided it takes precedence over anypatient_idkey embedded in the slide dicts. When omitted and the slide dicts carry nopatient_id, each slide is treated as its own patient.
- Return type:
- embed_regions_dense(regions, *, dense, execution=None)¶
Extract + persist a dense
(d, gh, gw)grid per caller-supplied ROI.The dense counterpart of the pooled coordinate path: each
SlideRegionsnames a slide + a set of level-0 ROI coordinates, and every ROI is read, encoded through the dense transform, and written todense_embeddings/[<class>/]<sample_id>/<x>_<y>.ptplus a geometry sidecar. The run splits its ROIs across all visible GPUs (execution.num_gpus);num_gpus=1encodes fully in-process. Resume is automatic — only ROIs whose sidecar has the same source-spacing declaration and resolved hs2p read plan are skipped. Returns oneDenseRegionArtifactper input ROI.The effective encoder input — the padded ROI for a whole-tile run, one patch-aligned window for a sliding one — is declared before any region is read, so a geometry the encoder cannot accept raises here rather than at the first forward pass. Variable-input capable encoders get their registry-declared constructor settings applied automatically; there is nothing for the caller to pass.
- Return type:
- embed_images_dense(images, *, dense, execution=None)¶
Extract + persist a dense
(d, gh, gw)grid per caller-supplied image.The image-sourced counterpart of
embed_regions_dense(), for consumers whose supervision arrives as image/mask pairs rather than as slides (segmentation, detection): eachImageSpecis decoded, run through the encoder’s normalization-only transform, padded up to the encoder’s patch multiple, encoded — whole-image, or by sliding the encoder’s native field and blending the token grids — and written todense_image_embeddings/<sample_id>.ptplus a geometry sidecar. The run splits its images across all visible GPUs (execution.num_gpus);num_gpus=1encodes fully in-process. Resume is automatic: an image is skipped only when its payload exists and its sidecar records the same normalized source identity and complete extraction recipe. Returns oneDenseImageArtifactper input image, in input order.Every source is opened through hs2p. PNG/JPEG inputs use hs2p’s one-level PIL reader and require
ImageSpec.spacing_at_level_0because they have no embedded spacing.dense.spacing_umrequests one physical read scale, orNoneresolves the encoder’s single registry default. The parent resolves each source’s metadata, concrete backend, native level, tolerance result, and final geometry before resume; hs2p reads that complete level and area-downsamples when required, but never upsamples.ImageSpec.spacing_at_level_0is preserved separately from the resolved source spacing and is passed to every hs2p backend.Everything after reading is shared with the slide path, including the effective encoder input — the padded image for a whole-image run, one patch-aligned window for a sliding one — which is declared before any image is decoded, so a geometry the encoder cannot accept raises here rather than on a torchrun rank’s first forward pass.
dense.target_sizeis a strict post-read declaration, not a fit-to-size request: every final image must already be that size (a non-square(h, w)is fine). Spacing-driven area downsampling establishes physical scale; it never repairs a mismatch with the declared geometry.- Return type:
- embed_images(images, *, execution=None)¶
Embed + persist one embedding per caller-supplied image.
The Given-geometry entry point: the caller already holds pre-cropped images — a public patch benchmark (BACH, CRC, Gleason, BreakHis, MHIST, PCam), an exported ROI set — and slide2vec neither tiles nor reads a slide. Each
ImageSpecis decoded, preprocessed with the encoder’s shipped transform, encoded, and written toimage_embeddings/<sample_id>.ptplus a provenance sidecar. The run splits its images across all visible GPUs (execution.num_gpus);num_gpus=1encodes fully in-process. Resume is automatic — images whose sidecar already exists are skipped. Returns oneImageEmbeddingArtifactper input image, in input order.Unlike the pooled and dense paths there is no geometry to declare: the images are heterogeneously sized (2048x1536 beside 96x96) and were never requested, so the encoder’s shipped transform is the contract and slide2vec records the resulting encoder input size as run provenance rather than validating it. That also means preprocessing runs itemwise before stacking — in-process by default, or in spawned loader workers when
num_workers_per_gpuis explicit — because differently sized images cannot be stacked before they are resized.ImageSpec.spacing_at_level_0is rejected here rather than ignored because this path has no slide level-0 read plan.- Return type:
- class slide2vec.DenseOptions(*, spacing_um, target_size, tolerance=0.05, backend='auto', pad_mode='reflect', image_pad_value=None, window_size=None, overlap=0.0, feature_kind='patch_features', attention_blocks=(-1,), attention_include_registers=False)¶
Bases:
objectDense
(d, gh, gw)grid extraction settings (issue #217).The dense counterpart of the pooled
PreprocessingConfig: it names the extraction geometry (spacing → level, supervisiontarget_size, padding) and the dense encode knobs (whole-tile vs sliding-window, patch grid vs CLS-attention). Unlike the pooled path there is no tiling — the caller supplies ROI coordinates directly (seeSlideRegions) — so aDenseOptionscarries only what slide2vec needs to read and encode each ROI.ExecutionOptionsis reused unchanged for output/precision/GPUs.- spacing_um: float¶
Target spacing in µm/px the ROI is read at (resolved to a pyramid level per slide).
- target_size: int¶
Supervision tile side length in pixels at spacing_um (the dense grid registers to it).
- backend: str = 'auto'¶
Slide reading backend.
"auto"resolves per slide (cucim → vips → openslide → asap).
- pad_mode: str = 'reflect'¶
Padding mode used to pad the tile up to the encoder’s patch multiple. One of
"reflect"/"replicate"/"constant"/"zero".
- image_pad_value: float | None = None¶
Constant fill value for
pad_mode in {"constant", "zero"}(ignored otherwise).
- window_size: int | None = None¶
Encoder field-of-view chunk fed through the backbone per forward.
None(default) is one whole-tile forward; a smaller value slides the encoder and blends token grids. Together withtarget_sizethis fixes the effective encoder input — the geometry handed toencode_tiles_dense— from which the encoder’s variable-input constructor settings are derived; hence nodynamic_img_sizeknob here.
- overlap: float = 0.0¶
Fractional window overlap in
[0, 1)for the sliding path (ignored whenwindow_size is None).
- feature_kind: str = 'patch_features'¶
"patch_features"(the patch-token grid) or"cls_attention"(CLS/register self-attention grid).
- class slide2vec.SlideRegions(*, sample_id, image_path, coordinates, annotation=None, spacing_at_level_0=None)¶
Bases:
objectOne slide’s ROIs for dense extraction:
(sample_id, image_path, coordinates, annotation).The dense input unit soma’s slide-manifest path hands to
Model.embed_regions_dense().coordinatesis an(N, 2)array of level-0 top-left(x, y)pixel coordinates; each ROI is read + encoded into one persisted(d, gh, gw)grid named<x>_<y>.pt.spacing_at_level_0optionally declares the source image’s level-0 spacing when metadata is missing or must be overridden.annotationnamespaces the output under a per-class subdirectory (reusing the pooled convention);Noneis the flat layout.
- class slide2vec.TileEmbeddingArtifact(*, sample_id, path, metadata_path, format, feature_dim, num_tiles, annotation=None)¶
Bases:
object
- class slide2vec.HierarchicalEmbeddingArtifact(*, sample_id, path, metadata_path, format, feature_dim, num_regions, tiles_per_region, annotation=None)¶
Bases:
object
- class slide2vec.SlideEmbeddingArtifact(*, sample_id, path, metadata_path, format, feature_dim, latent_path=None, annotation=None)¶
Bases:
object
- class slide2vec.DenseRegionArtifact(*, sample_id, x, y, path, metadata_path, feature_dim, grid_shape, annotation=None)¶
Bases:
objectOne persisted dense ROI grid: the
(d, gh, gw)payload + its geometry sidecar.Dense emits one directory per slide (
dense_embeddings/[<class>/]<sample_id>/) and one<x>_<y>.pt/<x>_<y>.meta.jsonpair per ROI — the counterpart of the pooled one-file-per-slide artifacts. Named from what slide2vec knows (slide + level-0 top-left coordinate); soma maps its ROIsample_idback onto(x, y).
Encoder provider diagnostics¶
- class slide2vec.EncoderProviderDiagnostic(provider_key, provider, exception_type, message)¶
Bases:
objectPublic, immutable description of one skipped installed provider.
- slide2vec.list_encoder_provider_diagnostics()¶
List deterministic diagnostics for installed providers skipped at discovery.
- Return type:
See Model Zoo for provider packaging and discovery behavior.