Skip to main content
Install or upgrade with pip install -U bioptimus-sdk.
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_embedding returns a spatial gene-expression prediction and its tile embedding from a single forward pass, with whole-slide persistence of both outputs. Available on the local, aws, and huggingface backends, 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.
  • huggingface optional-dependency extra for the in-process Hugging Face backbone loader. Install with pip install bioptimus-sdk[huggingface] to pull timm, huggingface_hub, and the PyTorch stack. Missing timm/ huggingface_hub now raise an ImportError pointing at the extra.
  • Slide-level aggregation utilities in bioptimus.inference: slide_embedding (pools a slide’s tile embeddings into one vector) and pseudobulk (pools predicted spatial gene expression into a bulk RNA-seq–like Pseudobulk profile with gene names when available). Both build on the pure slide_reduce helper (with a slide_mean shorthand), operate on written predict/embed output (Zarr/HDF5/NPZ), and can optionally save the vector next to the input as <name>.slide.npy when save=True. A pool selector ("mean" default, "max", "sum", "median") chooses the reduction; also on SlideInference.embed_slide / predict_pseudobulk.
  • Endpoint verification: bioptimus.observability.healthcheck.verify_endpoint sends 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 an ErrorCode and a remediation hint. Returns a HealthReport (JSON-serializable) and is fail-safe by default, or raises with raise_on_failure=True for CI gating. Exposed as bioptimus verify --model h1 --backend remote --base-url ... (--json for machine-readable output, non-zero exit on failure) and as build_support_bundle(verify={...}), which adds a healthcheck.json artifact to the diagnostic bundle. New ErrorCode.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_bundle collects environment, configuration and probe results, the server exposes /diagnostics, and both are reachable from the bioptimus CLI.
  • 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 InferenceMode enum, 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-sdk package; 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_FILE error 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 NaN into tile geometry.
  • A single failing tile no longer aborts the slide: per-tile failures are isolated in TorchModel.forward and reported individually.
  • Bulk RNA file extensions resolve deterministically, and a non-mapping workspace configuration or an unrecognized create_transform keyword argument raises a typed error rather than a bare KeyError.
  • AWSClient rejects a non-object JSON payload, and the async client creates a one-shot aiohttp session 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 .pt2 output, 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 (or Inference) 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, an nn.Module adapter that turns tiles into endpoint requests and returns stacked tensors, plus a demo notebook comparing Hugging Face H1 embeddings against endpoint embeddings.

Changed

  • Rename MultiModelData to MultiModalData and move the module to bioptimus/data/multi_modal/. See the breaking-change note above.
  • Clarify the WSIReader.mpp_downsample error 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-side log1p bulk RNA preprocess. Previously log1p(-1) produced -inf, yielding NaN embeddings that failed ModelResponse validation with one error per output dimension.
  • Strip oversized ICC color profiles before PNG-encoding tiles, fixing ValueError: Decompressed Data Too Large on 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 IndexError instead 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 ValueError on a header-only bulk RNA file instead of failing later with an opaque error, and validate SubsetColumns indices.
  • 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.

Prior releases

Release notes for versions published before this changelog was introduced are not reconstructed here. See the release history on PyPI.