This page shows the chapter notebook with its saved results. Constructed examples do not measure competition gains.
Chapter 46: Segmentation Architectures
Try the decision first
Which threshold and post-processing rule is best depends on how Dice is averaged: how large is that effect, and when does it appear?
Write your expectation before opening the worked results. Use the chapter activity to compare supported inputs. To change the calculation itself, run the notebook on GitHub.
Your answers stay on this page until you download them. They are not sent to a server.
Worked notebook and saved results
Which threshold and post-processing rule is best depends on how Dice is averaged: how large is that effect, and when does it appear?
The chapter asks to specify the Dice reduction and the empty-target behaviour before reporting a score. In a competition with many empty images that choice decides which threshold wins, so a model compared under the wrong reduction is ranked under the wrong rule.
Constructed data and a generated probability map; the sizes of these effects are properties of this generator, not a competition result.
The experiment
Constructed 32 x 32 images with one disc each (radius 2 to 8 pixels), where the control sets the share of images with no disc. A stand-in for a trained network supplies the probability map: the blurred mask plus spatially smooth noise, so small objects are weak and empty images carry speckle. Three rules are chosen on 150 development images: the threshold that maximises pooled Dice, the threshold that maximises mean per-image Dice (an empty prediction on an empty image scores 1), and a threshold plus a minimum object size (0, 5, 10 or 20 pixels, via connected components) for per-image Dice. Each is scored on 300 held-out images with both reductions, averaged over 10 draws.
Calculation code
import numpy as np
from scipy import ndimage
from kaggle_companion.activities._common import clean
SEED = 46
DRAWS = 10 # independent image sets; every estimate is a mean over draws
SIZE = 32 # images are 32 x 32 pixels
N_DEV, N_HELD = 150, 300 # development images (choose the rule) and held-out images (score it)
THRESHOLDS = np.linspace(0.2, 0.9, 15)
AREAS = (0, 5, 10, 20) # minimum object sizes in pixels tried by the post-processing rule
def generate(n, empty_share, rng):
"""Masks with one disc each (radius 2 to 8 px; a share of the images is empty) and a stand-in model's probability map.
The map is the blurred mask plus spatially smooth noise, so it misses small objects and speckles over empty images."""
yy, xx = np.mgrid[:SIZE, :SIZE]
masks = np.zeros((n, SIZE, SIZE), bool)
for i in np.where(rng.random(n) >= empty_share)[0]:
radius = rng.choice([2, 3, 4, 6, 8], p=[0.25, 0.25, 0.2, 0.15, 0.15])
cy, cx = rng.integers(radius + 1, SIZE - radius - 1, 2)
masks[i] = (yy - cy) ** 2 + (xx - cx) ** 2 <= radius ** 2
blur = ndimage.gaussian_filter(masks.astype(float), (0, 1.2, 1.2))
field = ndimage.gaussian_filter(rng.normal(size=masks.shape), (0, 1.5, 1.5))
field /= field.std()
return masks, 1 / (1 + np.exp(-(9 * (blur - 0.35) + 1.44 * field - 1.0)))
def pooled_dice(pred, target):
"""Intersection and support summed over the whole set, then one ratio."""
return (2 * (pred & target).sum() + 1e-6) / (pred.sum() + target.sum() + 1e-6)
def image_dice(pred, target):
"""One ratio per image, averaged later. An empty target with an empty prediction scores 1 (the rule stated in the text)."""
inter = (pred & target).sum((1, 2))
total = pred.sum((1, 2)) + target.sum((1, 2))
return np.where(total == 0, 1.0, 2 * inter / np.maximum(total, 1))
def remove_small(pred, area):
"""Delete connected components smaller than `area` pixels."""
if area == 0:
return pred
out = pred.copy()
for i in np.where(pred.any((1, 2)))[0]:
labels, count = ndimage.label(pred[i])
for k, size in enumerate(ndimage.sum(pred[i], labels, range(1, count + 1)), 1):
if size < area:
out[i][labels == k] = False
return out
def run(empty_share):
rng = np.random.default_rng(SEED)
keys = ("pooled_rule", "image_rule", "area_rule")
rows = {k: {"pooled": [], "image": []} for k in keys}
chosen = {"pooled_rule": [], "image_rule": [], "area_rule": [], "area": []}
curve_pooled, curve_image = [], []
for _ in range(DRAWS):
dev_mask, dev_prob = generate(N_DEV, empty_share, rng)
held_mask, held_prob = generate(N_HELD, empty_share, rng)
# Rule 1: the threshold that maximises pooled Dice on the development images.
t_pooled = THRESHOLDS[np.argmax([pooled_dice(dev_prob > t, dev_mask) for t in THRESHOLDS])]
# Rule 2: the threshold that maximises mean per-image Dice (empty rule included).
t_image = THRESHOLDS[np.argmax([image_dice(dev_prob > t, dev_mask).mean() for t in THRESHOLDS])]
# Rule 3: threshold and minimum object size that maximise mean per-image Dice.
best = max(((image_dice(remove_small(dev_prob > t, a), dev_mask).mean(), t, a) for a in AREAS for t in THRESHOLDS[::2]),
key=lambda s: s[0])
preds = {"pooled_rule": held_prob > t_pooled, "image_rule": held_prob > t_image,
"area_rule": remove_small(held_prob > best[1], best[2])}
for k, pred in preds.items():
rows[k]["pooled"].append(pooled_dice(pred, held_mask))
rows[k]["image"].append(image_dice(pred, held_mask).mean())
chosen["pooled_rule"].append(t_pooled)
chosen["image_rule"].append(t_image)
chosen["area_rule"].append(best[1])
chosen["area"].append(best[2])
curve_pooled.append([pooled_dice(held_prob > t, held_mask) for t in THRESHOLDS])
curve_image.append([image_dice(held_prob > t, held_mask).mean() for t in THRESHOLDS])
gain = np.array(rows["area_rule"]["image"]) - np.array(rows["pooled_rule"]["image"])
return clean({
"empty_share": empty_share,
"rules": {k: {"pooled": np.mean(v["pooled"]), "image": np.mean(v["image"])} for k, v in rows.items()},
"threshold": {k: np.mean(chosen[k]) for k in keys}, "min_area": np.mean(chosen["area"]),
"gain_image": gain.mean(), "gain_se": gain.std(ddof=1) / np.sqrt(DRAWS), "win_rate": float((gain > 0).mean()),
"thresholds": THRESHOLDS, "curve_pooled": np.mean(curve_pooled, 0), "curve_image": np.mean(curve_image, 0),
"draws": DRAWS, "dev_images": N_DEV, "held_images": N_HELD,
})
Measure it across the control
The control is share of images with an empty mask. Each value below runs the whole experiment from the generator up.
Calculation code
import pandas as pd
from kaggle_companion.activities.ch46 import explain
VALUES = [0, 0.25, 0.5, 0.75]
results = {value: run(value) for value in VALUES}
table = pd.DataFrame({str(v): explain(results[v], v)['metrics'] for v in VALUES})
print(table.to_string())0 0.25 0.5 0.75 Pooled rule, per-image Dice 0.817 0.744 0.723 0.728 Pooled rule, pooled Dice 0.905 0.901 0.894 0.876 Per-image rule, per-image Dice 0.822 0.765 0.801 0.866 Minimum-size rule, per-image Dice 0.831 0.833 0.872 0.922 Minimum-size rule, pooled Dice 0.909 0.908 0.903 0.899 Gain over pooled rule (SE) +0.013 (0.002) +0.090 (0.006) +0.149 (0.009) +0.194 (0.018)
Look at it
The figure shows the default setting, share of images with an empty mask = 0.5.
Calculation code
import matplotlib.pyplot as plt
from kaggle_companion.activities.ch46 import draw, NCOLS, HEIGHT
DEFAULT = 0.5
fig, axes = plt.subplots(1, NCOLS, figsize=(6.6 if NCOLS == 1 else 10.4, HEIGHT), layout='constrained')
draw(axes, results[DEFAULT], DEFAULT)
plt.show()What the result says
With 50% of images empty, the threshold tuned for pooled Dice (0.630) scores pooled Dice 0.894 but mean per-image Dice 0.723. Tuning for per-image Dice moves the threshold to 0.825 and gives 0.801 per image and 0.855 pooled. Adding a minimum object size (mean 7.0 pixels) reaches 0.872 per image: 0.872 - 0.723 = 0.149 over the pooled-Dice rule (standard error 0.009, better in 100% of draws).
- Pooled-Dice rule, per-image minus pooled: 0.723 - 0.894 = -0.171.
- Per-image rule, pooled Dice: 0.855 - 0.894 = -0.039 against the pooled rule.
- Minimum-size rule over the pooled-Dice rule, per image: 0.872 - 0.723 = +0.149.
- Thresholds chosen: pooled 0.630, per-image 0.825, with minimum size 0.590.
Apply this to your competition
- Write the official Dice reduction and the empty-mask rule into the validation code before comparing any model.
- Choose the threshold, and a minimum object size if the host scores per image, on development images, then freeze both.
- Report the share of empty images and the score on empty and non-empty images separately.
- Check the minimum-size rule against false positives that are large, not only speckle.
Book location: Chapter 46, Segmentation Losses.
Apply a lesson from this chapter
Select a lesson whose conditions match your project. State how you would test it and what would make you reject it.
Track pseudo-label sources separately in segmentation
Conditions
- Segmentation training uses multiple pseudo-label sources.
Action
- Track teacher/source identity for each pseudo-labeled slide and compare source-specific training variants.
Check
- Evaluate on clean patient-held-out labels and audit teacher training provenance.
Limits
- The proposed ensemble-diversity explanation is speculative; source does not establish hand-labeling superiority.
- Nonempty deep-supervision loss is a separate training choice.
Separate face localization from identity classification
Conditions
- an image contains multiple faces requiring separate identity predictions
Action
- Proposed adaptation of source observation: Detect individual face regions and classify each detected region with a separate recognition model.
Check
- Proposed verification: Measure end-to-end recall as well as classification accuracy on correctly localized regions.
Limits
- The first-place claim is for classifier Part1; timing of the winner-owned full detector/classifier continuation is unspecified and it is not established as the competition submission. Detector failures propagate; no measured latency or isolated pipeline gain is supplied.
Handle 180-degree yaw ambiguity before box averaging
Conditions
- 3D box orientations are equivalent modulo180degrees
Action
- Proposed recipe: compare circular averaging of doubled yaw angles with naive angle averaging.
Check
- Proposed check: Test circular doubled-angle averaging at175/5degrees and near wraparound, halve the final angle, and compare box IoUwith naive averaging.
Limits
- Applicable to orientation modulo180degrees only; directed headings require360degree treatment.
Iterate detector pseudo-label refinement
Conditions
- a detector ensemble can supply labels for extra unlabeled images
Action
- Proposed conditional application: Fine-tune from the base checkpoint on teacher-ensemble labels, then repeat using the first pseudo-label model outputs.
Check
- Proposed check: Generate leakage-safe teacher boxes, compare one versus two rounds at equal training budget, and measure quality on untouched source-held-out images.
Limits
- Hidden-test pseudo-labeling is competition transduction; deployment reuse requires eligible unlabeled images and an untouched labeled holdout.
Undo every 3D test-time transform before fusing boxes
Conditions
- point clouds are transformed for test-time augmentation
Action
- Proposed recipe: map predicted box centers and yaw back to the original coordinates before fusion.
Check
- Proposed check: Round-trip synthetic boxes through each transform and inverse, including flips, scaling and wraparound, before comparing fused predictions.
Limits
- Box conventions and yaw direction differ across libraries; inverse correctness must be tested independently of quality gains.
Tune the balance between classification and box-regression losses
Conditions
- classification and localization are trained jointly
Action
- Proposed recipe: compare loss weights instead of assuming equal task weighting.
Check
- Proposed check: Sweep loss weights on inner validation, report accuracy/IoUtradeoffs on an untouched holdout, and monitor relative loss/gradient scales.
Limits
- Alpha0.7depends on loss scales and task priorities; no controlled weight sweep is reported.
Keep bounding-box targets consistent with image resizing
Conditions
- image resizing changes the coordinate system used for localization
Action
- Proposed recipe: verify normalized box targets and all resize and augmentation transformations.
Check
- Proposed check: Overlay transformed boxes on resize/crop/flip fixtures and round-trip coordinates to the original image, checking edges and degenerate boxes.
Limits
- Normalization conventions must match resize and augmentation; published description does not prove transform implementation correctness.
Learn proposal separation quality from morphology
Conditions
- segmentation candidates have uncertain watershed thresholds
Action
- Proposed conditional application: Predict candidate IoU using morphological features with LightGBM and choose separation thresholds per candidate.
Check
- Proposed check: Fit IoU regressor on OOF candidates; compare adaptive/fixed thresholds on untouched image types.
Limits
- Candidate labels can leak from fitted base masks; distribution shift affects learned quality.
Predict touching borders to separate adjacent instances
Conditions
- binary masks merge neighboring nuclei
Action
- Proposed conditional application: Predict cell-interior and touching-border channels and use watershed; combine full-mask predictions when border removal hurts IoU.
Check
- Proposed check: Compare border/full-mask targets with watershed on image-source-held-out instance precision and IoU thresholds.
Limits
- Border removal improves separation but removes area; multiple networks increase cost.
Share a backbone while separating classification and localization heads
Conditions
- each image requires both a class and bounding box
Action
- Proposed recipe: compare a shared feature extractor with task-specific prediction heads.
Check
- Proposed check: Compare shared and separate backbones under the same split and budget, report both accuracy and IoU, and inspect negative task transfer.
Limits
- Joint learning can harm either task; source's win explanation does not establish component causality.
Use crops for training when full-image detection exceeds memory
Conditions
- high-resolution document detection with limited GPU memory
Action
- Proposed: train on bounded image crops and evaluate multiscale full images under an explicit size cap.
Check
- Proposed: ensure boundary-crossing boxes are handled consistently and compare crop training/full-image inference across scale settings while recording peak memory.
Limits
- The author reports two 1080 Ti GPUs and leaderboard scores of 0.935 and 0.946 for different training/testing scale packages, plus 0.950 for an ensemble. The metric definition and leaderboard partition are unspecified; crop and scale effects are not isolated.
Budget 3D TTA by measured incremental benefit
Conditions
- additional point-cloud transformations increase inference work
Action
- Proposed recipe: compare the limited flip-only TTA with more rotations and transformations under the runtime constraint.
Check
- Proposed check: Profile each added transform's validation gain and end-to-end inference time after inverse mapping and fusion, stopping when budget or marginal utility is exhausted.
Limits
- TTA benefits depend on fusion and transform validity; source supplies no quantified extra-copy speed tradeoff.
Discard tile borders while budgeting overlap inference cost
Conditions
- large-image segmentation has edge artifacts in tiled predictions
Action
- Proposed adaptation of source observation: Use overlapping context tiles and retain central predictions, optionally gating empty tiles with a classifier.
Check
- Proposed verification: Check complete coverage, border quality and missed-positive gating errors plus total inference time.
Limits
- The source reports fourfold inference cost; aggressive gating can miss small masks and validation used the old dataset.
Fuse boxes across detector scales
Conditions
- multiple detectors produce competing boxes for the same objects
Action
- Proposed conditional application: Use weighted box fusion to combine multi-scale detector predictions and compare it with the existing suppression/ensemble baseline.
Check
- Proposed check: Compare WBF and NMS with identical detectors on source-held-out AP; check class mapping and coordinate rescaling.
Limits
- Correlated detectors can reinforce errors; nine-model inference is expensive.
Test gradient accumulation rather than assuming equivalence
Conditions
- large detection models motivate smaller micro-batches
Action
- Proposed conditional application: Verify accumulation behavior against actual-batch training before adopting it.
Check
- Proposed check: Match effective batch, optimizer steps and LR; compare actual/accumulated batches with normalization behavior controlled.
Limits
- Microbatch statistics, loss scaling or implementation may differ; failure is local.