Section 1 · Lesson 8

Lessons learned and recap

The score climbed from 0.30 to 0.6486 because of decisions about the metric and the data, more than because of a fancier network.

You'll learn

The path to 0.6486

Bar chart of holdout scores: all-empty 0.30, starter U-Net 0.5677, ResNet-34 at tau 0.5 0.6305, tau 0.3 with TTA 0.6420, with post-processing 0.6486.
Holdout score as each step is added. All values come from the project's evaluation files. The starter value is its score at tau 0.9.
StepScoreSource
Predict nothing0.3000milestone1/answers.json, question 9
Milestone 1 starter model, tau 0.90.5677threshold_sweep.csv
ResNet-34 U-Net with TTA, tau 0.50.6305runs/r34_baseline/eval.json
Same, tau 0.30.6420eval.json
Same, per-class post-processing (2-fold CV)0.6486eval.json

What worked

  1. Read the metric before modelling. The all-empty baseline scores 0.30, and naive Dice rewards silence. Knowing that a missed defect costs about 37 times more than a false alarm pointed the project toward low thresholds from the start.
  2. Split on label combinations. Stratifying on the 15-way combination string kept rare classes in the holdout (63 defect_b images).
  3. Keep the native 128 × 800 shape. No resizing means no aspect distortion, and both dimensions divide by 32 for the encoder.
  4. Average predictions. Flip TTA added 0.0136 to the score at tau 0.3 (0.6284 to 0.6420).
  5. Tune per class, and validate the tuning. Per-class rules added another 0.0066. Cross-validating the tuning gave 0.6486 against 0.6491 in-sample, so the gain isn't an artefact of tuning on the same images.

What the project can't claim

Where to go next

These ideas follow from the evidence above. The files don't test them:

Recap quiz

1. In this project's RLE, runs are written as:

  1. row, column, length triples
  2. start and length pairs, 1-based and column-major
  3. start and end pairs, 0-based and row-major

Lesson 1: rle_decode subtracts 1 from each start and reshapes with order="F".

2. About what share of image-class pairs have no defect?

  1. 16%
  2. 50%
  3. 84%

Lesson 2: 38,371 of 45,572 pairs are empty, which is 84.2%.

3. Which weights make up the competition score?

  1. 0.70 foreground Dice, 0.20 false-positive score, 0.10 empty accuracy
  2. 0.50 Dice, 0.50 accuracy
  3. 1.00 naive mean Dice

Lesson 3. An all-empty prediction therefore scores 0.2 + 0.1 = 0.30.

4. Why does the network end in four sigmoid outputs?

  1. It saves memory.
  2. Several defect types can appear in one image, so each class is its own yes-or-no mask.
  3. Sigmoids are faster than softmax.

Lesson 4: 1,198 images have two or more classes.

5. Which loss does train.py use by default?

  1. Cross-entropy only
  2. Dice only
  3. BCE plus multilabel Dice

Lesson 5: loss = bce(logits, msk) + args.dice_w * dice(logits, msk).

6. The per-class thresholds are 0.05 to 0.2. What does that tell you?

  1. The metric rewards finding defects more than avoiding false alarms.
  2. The model is badly calibrated and unusable.
  3. The metric ignores empty images.

Lesson 6: a missed defect costs far more than a false alarm, so the best cut-offs are low.

7. What does cross-validating the post-processing tune protect against?

  1. Slow training
  2. Reporting a score on the same images the parameters were tuned on
  3. Flipped masks

Lesson 6: tuning on half the holdout and scoring on the other half gives 0.6486, close to the in-sample 0.6491.

8. Which claim can the project files support?

  1. The two-model ensemble beats the single model.
  2. The positive-pairs loss improves the score.
  3. A single ResNet-34 U-Net with TTA and tuned rules scores 0.6486 under 2-fold CV on the holdout.

Lesson 7 and this lesson: only r34_baseline has saved holdout outputs and an evaluation.

Review the section. Watch the training progress video, or flip through the slide deck that summarises all eight lessons.