This page shows the chapter notebook with its saved results. Constructed examples do not measure competition gains.
Chapter 42: Image Augmentation
Try the decision first
When does adding transformed copies of the training images raise held-out accuracy, and when does it lower it?
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
When does adding transformed copies of the training images raise held-out accuracy, and when does it lower it?
A default augmentation stack can silently teach the model something false. The chapter asks for a label-preservation check per transform and for every policy to be compared with an unaugmented baseline on unchanged assessment images.
Real small images and a linear model. Shifts hurt here, which would likely not hold for larger images or convolutional networks; the mirrored variant is constructed so that the flip is valid, and the result says nothing about natural photographs. The size of each gain and loss moves noticeably between random draws; the signs did not.
The experiment
scikit-learn's bundled digits dataset (1,797 real 8 x 8 grayscale scans). The control is the number of training images (100, 300 or 900); 500 other images are the test set. A multinomial logistic regression is trained on the originals alone, or on the originals plus one transformed copy of each: an unchanged duplicate (control for doubling the rows), a random shift of up to one pixel, a left-right flip, or a half-turn. This is run on the digits as scanned, and on a constructed variant in which each image, in training and test alike, is mirrored with probability one half and keeps its label. Results are means over 12 random splits.
Calculation code
import warnings
import numpy as np
from sklearn.datasets import load_digits
from sklearn.linear_model import LogisticRegression
from kaggle_companion.activities._common import clean
warnings.filterwarnings("ignore") # lbfgs convergence notices on tiny training sets
SEED = 42
REPLICATES = 12 # independent train/test splits per training size; results are means over them
TEST_ROWS = 500
POLICIES = ("none", "duplicate", "shift", "hflip", "rot180")
def shifted(image, rng):
"""Move the 8 x 8 image by -1, 0 or +1 pixel in each direction, padding with zeros."""
dx, dy = rng.integers(-1, 2, 2)
out = np.zeros_like(image)
src = image[max(0, -dy):8 - max(0, dy), max(0, -dx):8 - max(0, dx)]
out[max(0, dy):max(0, dy) + src.shape[0], max(0, dx):max(0, dx) + src.shape[1]] = src
return out
TRANSFORMS = {"duplicate": lambda im, rng: im, # control: same rows twice, no change to the picture
"shift": shifted,
"hflip": lambda im, rng: im[:, ::-1], # mirror left to right
"rot180": lambda im, rng: im[::-1, ::-1]} # turn upside down (a 6 becomes a 9)
def fit_predict(images, labels, test_images, policy, rng):
"""Train on the originals plus one transformed copy of each (or on the originals alone) and predict the test images."""
if policy != "none":
copies = np.stack([TRANSFORMS[policy](im, rng) for im in images])
images, labels = np.concatenate([images, copies]), np.concatenate([labels, labels])
model = LogisticRegression(max_iter=300).fit(images.reshape(len(images), -1), labels)
return model.predict(test_images.reshape(len(test_images), -1))
def run(training_images):
digits = load_digits()
pictures, labels = digits.images / 16.0, digits.target # 1,797 real 8 x 8 grayscale scans, scaled to [0, 1]
accuracy = {v: {p: [] for p in POLICIES} for v in ("scanned", "mirrored")}
swapped = {p: [] for p in ("none", "rot180")} # share of true 6s and 9s predicted as the other one
for r in range(REPLICATES):
rng = np.random.default_rng(SEED * 100 + r)
order = rng.permutation(len(labels))
test, train = order[:TEST_ROWS], order[TEST_ROWS:TEST_ROWS + training_images]
mirror = rng.random(len(labels)) < 0.5
variants = {"scanned": pictures, # digits as scanned: orientation carries the label
"mirrored": np.where(mirror[:, None, None], pictures[:, :, ::-1], pictures)} # constructed: half the images mirrored, labels unchanged
for variant, images in variants.items():
for policy in POLICIES:
pred = fit_predict(images[train], labels[train], images[test], policy, np.random.default_rng(r))
accuracy[variant][policy].append(float((pred == labels[test]).mean()))
if variant == "scanned" and policy in swapped:
six_nine = np.isin(labels[test], (6, 9))
swapped[policy].append(float((pred[six_nine] == 15 - labels[test][six_nine]).mean()))
mean = {v: {p: float(np.mean(a)) for p, a in d.items()} for v, d in accuracy.items()}
return clean({"training_images": training_images, "accuracy": mean, "swapped_six_nine": {p: float(np.mean(a)) for p, a in swapped.items()},
"replicates": REPLICATES, "test_images": TEST_ROWS})
Measure it across the control
The control is training images (before augmentation). Each value below runs the whole experiment from the generator up.
Calculation code
import pandas as pd
from kaggle_companion.activities.ch42 import explain
VALUES = [100, 300, 900]
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())100 300 900 No augmentation, scanned 0.882 0.933 0.960 No augmentation, mirrored 0.749 0.862 0.906 Flip, scanned 0.840 0.893 0.922 Flip, mirrored 0.840 0.893 0.922 Half-turn, scanned 0.786 0.859 0.890 6/9 swapped by half-turn 20% 11% 10%
Look at it
The figure shows the default setting, training images (before augmentation) = 100.
Calculation code
import matplotlib.pyplot as plt
from kaggle_companion.activities.ch42 import draw, NCOLS, HEIGHT
DEFAULT = 100
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 100 training images, a left-right flip changes accuracy by 0.840 - 0.882 = -0.042 on digits as scanned and by 0.840 - 0.749 = +0.091 on digits in random mirror orientation. A one-pixel shift changes it by -0.032 and -0.043, and a half-turn by -0.096 and -0.111. The half-turn makes 20% of true 6s and 9s be predicted as the other digit, against 0% without augmentation. An unchanged duplicate of every image changes accuracy by +0.003.
- Flip on scanned digits: 0.840 - 0.882 = -0.042.
- Flip on mirrored digits: 0.840 - 0.749 = +0.091.
- Half-turn on scanned digits: 0.786 - 0.882 = -0.096.
- Unchanged duplicate on scanned digits: 0.885 - 0.882 = +0.003.
Apply this to your competition
- Write the invariance down (class, box, mask, orientation) and check each transform on a handful of images before training.
- Compare every augmentation with an unaugmented baseline and an unchanged-duplicate control on the same untouched assessment images.
- Look at per-class errors for confusion pairs a transform could create (6 and 9, left and right, mirrored text).
- Expect valid augmentation to matter most with little data; its gain shrinks as the training set grows, while an invalid transform keeps costing accuracy.
Book location: Chapter 42, Decide Which Changes Preserve the Target.
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.
Reject augmentations that alter relevant image semantics
Conditions
- image augmentation may violate the target distribution
Action
- Proposed conditional application: Audit augmentation-specific errors and reconsider intensity inversion after it causes test failures.
Check
- Proposed check: Remove inversion alone in matched runs; inspect polarity-specific failures and instance metric.
Limits
- Inversion may be valid in other acquisition settings; no isolated numeric harm supplied.
Match preprocessing to each pretrained ensemble member
Conditions
- a vision ensemble mixes backbones with different training normalization and input sizes
Action
- Proposed: bind each model checkpoint to its own normalization and input size rather than imposing one common transform.
Check
- Proposed: verify checkpoint training contracts and compare normalization against the intended model metadata; assert shared output class and row order.
Limits
- Twelve crop/flip views are built for each member; utils.predict_tta aggregation internals are outside this packet, so its averaging rule is not inferred.
Preserve borders in composite detection augmentation
Conditions
- mosaic cropping can remove important object-border information
Action
- Proposed conditional application: Build four-image mosaic augmentation that retains borders and transforms boxes consistently.
Check
- Proposed check: Visualize transformed boxes at all seams and compare border-object AP against ordinary mosaic on source holdouts.
Limits
- Geometry missing from text; stitching can create unrealistic border context.
Balance augmentation against class evidence
Conditions
- cropping or lighting can remove or change the visual cues defining image classes
Action
- Proposed: compare augmentation strength on a fixed split and inspect transformed examples for label preservation.
Check
- Proposed: inspect damaged regions under each transform and compare fixed-split validation across mild, standard and reduced augmentation.
Limits
- Winner-owned failed Experiment 3 was not submitted. Faster apparent overfit after strong augmentation reduction is qualitative; reduced augmentation is not shown to improve accuracy.
Budget image crop expansion against lost content
Conditions
- fixed-size image networks see variable-aspect inputs
Action
- Proposed adaptation: Compare aspect-preserving center crops with a bounded multicrop trial, inspecting lost content and correlated expansion.
Check
- Measure held-out accuracy, retained visual cues and training time per crop policy.
Limits
- Multicrop was not used in the final solution; center crop can discard style cues.
Test crop-based inference against resizing
Conditions
- source images exceed model resolution and inference runs without internet
Action
- Compare overlapping-patch probability averaging and center-crop resizing with plain resizing.
Check
- Measure crop coverage, held-out accuracy, inference time and memory.
Limits
- Crop aggregation adds cost and can remove important context; no isolated crop gain is supplied.
- Offline pretrained-asset caching is a separate reproducibility requirement.
Vet augmentation on small models before scaling training
Conditions
- fine-grained image classes depend on color and edge damage
Action
- Proposed conditional application: Compare safe flips/rotations with limited crops and lighting changes on small models before adopting them for larger ensembles.
Check
- Proposed check: Compare candidate augmentations on fixed splits using classwise confusion; rerun shortlist on final backbone.
Limits
- Small-model ranking may not transfer; clipping/lighting can erase target cues.
Randomize valid molecular strings for training and median TTA
Conditions
- a molecular text model is sensitive to equivalent string serialization
Action
- Proposed adaptation of source observation: Generate chemically equivalent randomized SMILES and compare training augmentation and median TTA separately.
Check
- Proposed verification: Verify molecular identity, including stereochemistry, and score/cost as view counts change.
Limits
- Training gain was not carefully ablated; altering stereochemistry can change molecule semantics and should not be copied blindly.
Assess test-time augmentation on labeled holdout data
Conditions
- TTA adds inference cost and may alter classification behavior
Action
- Proposed: measure ordinary and augmented prediction accuracy on the same validation loader before adopting TTA.
Check
- Proposed: compare per-class errors and inference runtime on a fixed independent holdout and ensure all ensemble outputs share row order.
Limits
- Different ensemble members use different split seeds, so their scores are not directly comparable across members. The reported 81.6% public accuracy cannot isolate TTA or augmentation gain.
Compare Mixup and CutMix instead of assuming either wins
Conditions
- both Mixup and CutMix are plausible image augmentations
Action
- Proposed recipe: compare them rather than treating the more elaborate method as automatically better.
Check
- Proposed check: Compare Mixup and CutMix on identical folds and training budgets, tuning each strength and inspecting class-wise errors.
Limits
- Source tested one recipe family; CutMix strength and image semantics can change the outcome.
Use deterministic prediction transforms for a pretrained grayscale ensemble
Conditions
- grayscale CT images feed three-channel pretrained backbones
Action
- Proposed conditional application: Replicate grayscale input to three channels, apply matched normalization, and reserve geometric and appearance augmentation for training.
Check
- Proposed check: Assert repeated validation transforms identical; inspect anatomy-preserving augmentation and compare pretrained input alternatives.
Limits
- Code establishes implementation only; three-channel replication adds no image information and medical invariances need validation.
Test biological augmentation invariances instead of copying image defaults
Conditions
- neural responses can change under flips or interpolation
Action
- Proposed conditional application: Restrict augmentation to tested saturation changes and separately assess flips and rotations.
Check
- Proposed check: Test each transform separately on repeated held-out images and inspect whether the biological response target should remain unchanged.
Limits
- Tiny evaluation does not establish biological invariance; rotation artifacts are the author's suggested explanation.
Evaluate landmark corruption and decoder-input augmentations separately
Conditions
- landmark-to-text models need task-specific regularization
Action
- Proposed adaptation of source observation: Test anatomical landmark dropout and decoder-input masking as separate augmentations, then compare with the unchanged model.
Check
- Proposed verification: Run paired ablations under the same split and include sequence length and decoding budget.
Limits
- The listed ablations are explicitly rough and not necessarily independent; transformation validity must be checked.