Segmentation¶
A dense semantic-segmentation path: predict a per-pixel class map for each
tile. Segmentation is the canonical dense contract — the shared front half and
output machinery that the Detection path and the decoder-free
pixel-classifier method all build on. A frozen
foundation-model encoder produces a dense (d, grid_h, grid_w) token grid (cached as
feature_type="dense_grid"); a decoder turns that grid into a per-pixel class map;
and a SegmentationHead owns the geometry, loss, metric,
and prediction artifacts. Only the trainable component and the output representation differ
across the dense paths.
See also
The dense-prediction walkthrough runs the neural-decoder segmentation path end to end on a tiny synthetic dataset, then runs detection right after, so you can see exactly what changes between the two.
The dense contract¶
Every dense path shares the same front half and output machinery; this is the contract a new dense task plugs into.
Manifest —
dataset_type: segmentationusessoma.dataset.SegmentationManifest. The supervision is a per-sample mask raster (mask_path), not a scalarlabel.Spacing-aware mask reader — masks are read at the run’s spacing and registered against the token grids extracted at the same spacing (
soma.dense.reader). The annotation vocabulary (pixel_mapping, per-classmin_coverage, the background-present vs background-absent label remap) is a preprocessing concern — see Preprocessing.Frozen dense extraction — a frozen encoder emits a dense
(d, grid)grid, cached asfeature_type="dense_grid". No gradients flow through the backbone; only the trainable component on the grid is fit.Window-as-knob extraction — the encoder is read at its native spacing and a native-size window slides across the tile, stitching the token grids so every window stays in-distribution on both pixel size and mpp.
dense_window_sizeis the knob (null= whole-patch single forward;=native input = native-window sliding). The full mode table and the scale/context trade-off live on the pixel-classifier page (cls_attentionshares the identical extraction).Dense metrics — evaluation streams compact per-image confusion counts (full
(N, C, H, W)logits would OOM across a cohort); the head accumulatesdense_statsrows and finalizesmean_dice/mean_iou(soma.tasks.dense_metrics).Prediction artifacts — each fold writes
metrics.jsonplus the prediction-raster / overlay / CSV artifacts per split.
The neural-decoder default path¶
The decoder is the default trainable component on the dense grid (the dense-grid analogue of an aggregator). For each tile:
Run the frozen ViT → dense patch-feature grid
(d, grid_h, grid_w).A decoder (
lightweight_convby default) regresses a(C, grid)map; the head interpolates it to the supervisiontarget_sizeand crops viacrop_box.The head applies the per-pixel class activation and trains with cross-entropy + soft-Dice (the overlap term is a Tversky generalization —
beta > alphais recall-oriented for small structures,gamma > 1is focal-Tversky on hard classes).At evaluation, predictions are argmaxed per pixel and scored with
mean_dice/mean_iou.
The decoder is input-agnostic: it consumes whatever dense (d, grid) grid the
encoder emits, set by preprocessing.feature_kind (see Decoders). Multi-encoder
composite runs are supported on the decoder path and
auto-concatenate at token-grid resolution (concat_resolution: grid).
data:
dataset_type: segmentation
preprocessing:
requested_tile_size_px: 512 # supervision (mask) size
requested_spacing_um: 0.5 # read + native encoder spacing
encoder: { name: uni }
decoder: # the dense trainable component
name: lightweight_conv
task:
name: segmentation
params: { num_classes: 5 }
evaluation:
metrics: [mean_dice, mean_iou]
Methods¶
The dense grid admits two feature substrates (what the encoder emits) and two trainable components on it; the neural decoder above is the default. The Segmentation tutorial lists the substrate and component alternatives with the runnable walkthrough for each.
Task head¶
- class soma.tasks.segmentation.SegmentationHead(*, num_classes, geometry, ignore_index=255, dice_weight=1.0, class_weights=None, ce_gamma=0.0, tversky_alpha=0.5, tversky_beta=0.5, tversky_gamma=1.0, metrics=None, spacing_um=None, backend='auto', tolerance=0.05, label_remap=None)¶
Bases:
TaskHeadDense per-pixel classification head (parameter-free; the decoder learns).
- Parameters:
num_classes (
int) – Number of segmentation classesC.geometry (
DenseGridGeometry) – The run’sDenseGridGeometry— suppliesencoded_sizeandcrop_boxsoforwardmaps decoder logits to the mask’starget_size. The same geometry the extractor used (single source).ignore_index (
int) – Mask value excluded from loss and metrics.dice_weight (
float) – Weight on the overlap (soft-Dice / Tversky) term added to the region (cross-entropy) term.class_weights (
list[float] |None) – Optional per-class(num_classes,)weights for the cross-entropy term (e.g. inverse frequency) up-weighting rare classes.None= unweighted.ce_gamma (
float) – Focal exponent on cross-entropy.0.0= plain (optionally class-weighted) CE;> 0down-weights easy, well-classified pixels.tversky_gamma (tversky_alpha / tversky_beta /) – Overlap-term shape. The default
(0.5, 0.5, 1.0)is soft-Dice;beta > alphapenalizes false negatives more (recall-oriented for small structures),gamma > 1focuses on hard, low-overlap classes (focal-Tversky).metrics (
list[str] |None) – Metric names (validated against thesegmentationfamily); empty uses the default[mean_dice, mean_iou].
References¶
The shared decoder trainable component (see Decoders) and the decoder-free pixel-classifier alternative.
The detection path, which reuses this dense contract front half and differs only in output representation (see Detection).