2026-09-18
Adds the combined
predict_with_embedding mode across every backend, an
in-process Hugging Face backbone loader, slide-level aggregation, and the
observability surface (support bundles, diagnostic probes, endpoint
verification, PII anonymization). Also clamps whole-slide reads at slide edges
and moves the SDK runtime onto zarr 3.Added
- Combined inference:
EndpointModel.predict_with_embeddingreturns a spatial gene-expression prediction and its tile embedding from a single forward pass, with whole-slide persistence of both outputs. Available on thelocal,aws, andhuggingfacebackends, exposed over HTTP by the inference server, and served by one M-Optimus forward rather than two. Requesting it on an embedding-only model raises rather than silently degrading. - In-process Hugging Face backend for embedding backbones, selected with
Backbone(..., backend="huggingface"). Configuration-driven, with backend-aware model discovery. huggingfaceoptional-dependency extra for the in-process Hugging Face backbone loader. Install withpip install bioptimus-sdk[huggingface]to pulltimm,huggingface_hub, and the PyTorch stack. Missingtimm/huggingface_hubnow raise anImportErrorpointing at the extra.- Slide-level aggregation utilities in
bioptimus.inference:slide_embedding(pools a slide’s tile embeddings into one vector) andpseudobulk(pools predicted spatial gene expression into a bulk RNA-seq–likePseudobulkprofile with gene names when available). Both build on the pureslide_reducehelper (with aslide_meanshorthand), operate on writtenpredict/embedoutput (Zarr/HDF5/NPZ), and can optionally save the vector next to the input as<name>.slide.npywhensave=True. Apoolselector ("mean"default,"max","sum","median") chooses the reduction; also onSlideInference.embed_slide/predict_pseudobulk. - Endpoint verification:
bioptimus.observability.healthcheck.verify_endpointsends one synthetic tile through a deployed endpoint on any backend (remote,aws,local,huggingface) and validates that the request succeeds, that the response matches the model’s declared output contract (length, finiteness, tile echo), and that failures carry anErrorCodeand a remediation hint. Returns aHealthReport(JSON-serializable) and is fail-safe by default, or raises withraise_on_failure=Truefor CI gating. Exposed asbioptimus verify --model h1 --backend remote --base-url ...(--jsonfor machine-readable output, non-zero exit on failure) and asbuild_support_bundle(verify={...}), which adds ahealthcheck.jsonartifact to the diagnostic bundle. NewErrorCode.ENDPOINT_CONTRACT_MISMATCH(BIO-NET-003) covers a reachable endpoint whose response does not match the requested model. - Anonymized support bundles and diagnostic probes for reporting a failure
without shipping slide data:
build_support_bundlecollects environment, configuration and probe results, the server exposes/diagnostics, and both are reachable from thebioptimusCLI. - Configurable PII anonymization primitives, applied to log fields and support bundles so file paths and identifiers can be redacted at the boundary.
- Coordinate-driven tile extraction: an explicit tile-coordinate list can drive a whole-slide run instead of the tissue mask, for spatial gene-expression benchmarking against a fixed grid.
- Warning when a precomputed tissue mask’s aspect ratio does not match the slide’s, which previously produced silently misaligned tiles.
- One-time per-slide warning when a non-pyramidal slide forces a Level 0 downsample fallback, so the resulting read cost is visible.
Changed
- Whole-slide inference modes are unified behind an
InferenceModeenum, with a coercion shim that still accepts the legacy mode strings. An unknown mode now raises instead of being silently ignored. - The SDK runtime supports zarr 3, and Zarr writes are buffered by chunk rather than issued per tile.
- Slide pooling accumulates in float64 without an upcast copy of the tile matrix, so aggregating a large slide no longer doubles peak memory.
- CUDA version detection recognizes Blackwell devices.
- The published changelog is scoped to the
bioptimus-sdkpackage; repo-wide changes stay in the internal root changelog and are not shipped.
Fixed
- Whole-slide reads at slide edges are clamped to the slide bounds, both at Level 0 and in read-level space, and the cuCIM and OpenSlide backends now share one read path instead of clamping differently.
- Display helpers no longer append MPP and objective units to a value that already carries them.
- The single-WSI coordinate guard is enforced on every entry point, and tiles are anchored on tile size rather than on the requested stride.
- An empty bulk-RNA input raises a typed
RNA_EMPTY_FILEerror instead of failing later with an opaque message. - The server reports a terminal unhealthy state when every model fails to load, rather than staying up with no usable model.
- Non-finite MPP and magnification values in slide metadata are rejected
instead of propagating
NaNinto tile geometry. - A single failing tile no longer aborts the slide: per-tile failures are
isolated in
TorchModel.forwardand reported individually. - Bulk RNA file extensions resolve deterministically, and a non-mapping
workspace configuration or an unrecognized
create_transformkeyword argument raises a typed error rather than a bareKeyError. AWSClientrejects a non-object JSON payload, and the async client creates a one-shotaiohttpsession when none is supplied instead of reusing a closed one.- In-process checkpoint load failures are classified with an
ErrorCode, embedding width is selected by named.pt2output, and a failed support-bundle health check keeps its typed error code.
2026-07-28
The first release on the 1.2 line, shipping the in-process
local backend
alongside SDK observability, omics-preprocessing fixes, and a PyTorch adapter
for endpoint-backed models.Breaking change. The
MultiModelData dataset was renamed to
MultiModalData and moved from
bioptimus.data.multi_model.multi_model_dataset to
bioptimus.data.multi_modal.multi_modal_dataset. No compatibility alias is
provided: code importing the old name or module path must be updated. The
class joins a single WSI with optional bulk RNA data across modalities
(histology + transcriptomics), so multi-modal is the accurate term; the old
name also collided conceptually with the unrelated multi-model inference
server.Added
- Notify SDK users when a newer release is available: on first
Backbone(orInference) creation the installed version is compared against the latest stable release on PyPI and a one-time warning is logged if it is behind. - Structured JSON logging, typed error propagation, and boundary logging across the SDK.
bioptimus.utils.pytorch.TorchModel, annn.Moduleadapter that turns tiles into endpoint requests and returns stacked tensors, plus a demo notebook comparing Hugging Face H1 embeddings against endpoint embeddings.
Changed
- Rename
MultiModelDatatoMultiModalDataand move the module tobioptimus/data/multi_modal/. See the breaking-change note above. - Clarify the
WSIReader.mpp_downsampleerror when a requested target MPP is finer than the slide’s native resolution: the message now reports the slide’s actual native MPP instead of an internal epsilon-adjusted threshold, and states that downsampling can only raise MPP. The non-positive-MPP case gets its own message.
Fixed
- Preserve the missing-gene sentinel (
-1) through the server-sidelog1pbulk RNA preprocess. Previouslylog1p(-1)produced-inf, yieldingNaNembeddings that failedModelResponsevalidation with one error per output dimension. - Strip oversized ICC color profiles before PNG-encoding tiles, fixing
ValueError: Decompressed Data Too Largeon Focus slides and any slide whose embedded ICC profile exceeds Pillow’s 1 MB text-chunk limit. - Validate prediction-writer patch indices against the allocated tile count so
an out-of-range index raises
IndexErrorinstead of writing to an unexpected row or silently wrapping to the tail. - Preserve the missing-gene sentinel through
TPMNormaliser, excluding sentinels from the row total so the scale is not skewed by a meaningless negative sum. - Raise a clear
ValueErroron a header-only bulk RNA file instead of failing later with an opaque error, and validateSubsetColumnsindices. - Skip a malformed model config entry instead of aborting the whole model load.
- Keep batch runs resilient to a single failing slide rather than aborting the remaining slides.
- Handle zero-pixel and zero-tile slides without raising.

