learn-ml-epistemology-with-phoebe / Practitioner session 3 of 10
Learn ML Epistemology with Phoebe · Practitioner session 3 of 10

Twenty seeds, one pipeline

Session 2 measured one model and found it leaning on the ward. Tonight the pipeline is run twenty times with nothing changed but the random seed, and both columns are read. On draw 1 the twenty held-out scores sit inside a band of 0.019 and the twenty shifted scores sprawl across 0.051. Across five data draws the shifted spread beat the held-out spread every time, by 2.7 to 11.3 times. A pipeline that reports one number is reporting one draw from a distribution it never shows you.

🔴 Hardest Anyone who retrains and ships whatever comes out Anyone who has fixed a seed to make results reproduce 45 min
0-3 · Welcome 3-16 · Underspecification 16-30 · Five draws 30-45 · Seed sweep and Q&A
Part 0

Where tonight sits

Session 2 left a printout with two columns: held-out accuracy flat across seeds, reliance on the ward moving from 0.70 to 1.00. Tonight adds the third column, the one from the deployment year, and turns the whole thing into a measurement with a name. The name is underspecification, the measurement is a pair of spreads, and the ratio between them is the number to carry into a review. Session 4 designs the world those shifted scores are computed in.

Live = written together in the 45 minutes Self-study = the full depth, after class 🔍 Every diagram zooms

★ What you walk out with tonight. A seed sweep you can run on your own model tonight, ten lines on top of whatever training code you already have. The two spreads it produces and the order to read them in. The Thornbury reference numbers, 0.019 against 0.051 on draw 1 and a ratio between 2.7 and 11.3 across five draws, so you know what a serious gap looks like. And the reason a fixed seed makes a result reproduce without making it true.

LiveUnderspecification, operationally5 min▶

D'Amour et al. (2020) define it in one sentence: "An ML pipeline is underspecified when it can return many predictors with equivalently strong held-out performance in the training domain." Read it as a property of the pipeline rather than of any model that came out of it. The pipeline is the data, the architecture, the loss, the optimiser and the schedule. Run it twice with different seeds and it hands you two different predictors. If those two score the same held out, the pipeline did not determine which one you got, and the held-out score cannot tell you which one you are holding.

The operational test is short. Vary something that should not matter, hold everything that should matter fixed, and score the results in more than one place. At Thornbury the thing that should not matter is the random seed, which sets the initial weights and the order the examples arrive in. Nothing else moves: same 4,000 training patients, same three inputs into twelve tanh hidden units into one logit, same schedule.

The same authors are blunt about the consequence: "Predictors returned by underspecified pipelines are often treated as equivalent based on their training domain performance, but we show here that such predictors can behave very differently in deployment domains."

Self-studyThe words that will keep coming back4 min▶
  • Underspecification. A pipeline that can return many predictors with equally strong held-out performance, which then behave differently in deployment. A property of the pipeline.
  • Seed sweep. Running the same pipeline n times with only the random seed changed, and keeping every score rather than the best one.
  • Spread. Highest minus lowest across the sweep. Blunt on purpose: it is the quantity a reviewer can check by eye against a printed list.
  • The ratio. Shifted spread divided by held-out spread. How much wider the models are where nobody measured them than where everybody did.
  • Data draw. A regenerated world: new training, held-out and shifted patients from the same recipe. Five of them exist, and a finding that appears in one is not yet a finding.
  • The standing pair. Mean held-out 0.949 and mean shifted 0.765 across the five draws.
Part 1 · covers one pipeline, twenty models

Identical where you looked

13 min live

Draw 1, twenty seeds. Every one of the twenty models is scored twice: on 2,000 held-out patients from the collection year and on 2,000 shifted patients from the deployment year. The two columns are drawn below on the same horizontal scale, which is the only fair way to compare them.

Draw 1. One pipeline, twenty runs, one difference between them. Same 4,000 patients collection year, ward at 90% Same architecture 3 inputs, 12 tanh, 1 logit Same schedule SGD, 30 epochs Seed 1 to 20 weights and example order Both bands below are drawn on the same horizontal scale. Held out, collection year 0.019 wide twenty models, mean 0.949 Shifted, deployment year 0.051 wide the same twenty models, mean 0.765 2.7 times wider on this draw, and wider on every draw that was run. Nothing in the held-out column separates these twenty models. Everything in the shifted column does. A review that sees only the first band is being shown a number the pipeline did not determine.
🔍 Click to zoom - the same twenty models, drawn to the same scale, in the two places they were scored.
LiveWhy a fixed seed makes this worse, not better4 min▶

Fixing the seed is good hygiene and it is the standard advice, because it makes a result reproduce. What it does not do is make the result representative. A fixed seed picks one draw from the distribution the pipeline can produce and then hides the fact that there was a distribution, because every rerun returns the same point and the printout looks stable.

The two habits are not in conflict, they answer different questions. Fix the seed when you want a build to be byte-identical tomorrow. Sweep the seed when you want to know what your pipeline is capable of returning. A team that only ever does the first has a reproducible number and no idea how much of it was luck.

LiveWhat the reliance column adds4 min▶

Session 2's measurement runs alongside the two accuracies for free, because it needs nothing but predictions. Across twenty seeds at Thornbury the reliance on the ward runs from 0.70 to 1.00: some models change their mind about 7 patients in 10 when only the ward moves, others about all of them.

That column is the mechanism underneath the spread. The models that lean hardest on the arrangement are the ones with the most to lose when it goes, and the held-out score is blind to the difference because the arrangement still holds on the held-out rows. Three columns, two of which move and one of which does not, is the whole finding in a printout you can put on one slide.

Self-studyWhat the seed actually controls, and why that is enough3 min▶

Two things only: the initial weights, and the order the training examples arrive in. Both are usually described as implementation details, and both are outside the specification of what the model is supposed to be. Nobody writes a model card that says which permutation of the training set was used.

That is exactly what makes the sweep convincing. If a quantity nobody considers part of the model produces a 0.051 spread in deployment accuracy, then the specification is not pinning down the thing that matters. A larger perturbation, a different architecture or a different feature set would produce a bigger spread and prove much less, because those are things the specification was never claiming to fix.

Part 2 · covers the five data draws

One draw is an anecdote

13 min live

Draw 1 is one world. Regenerate the training, held-out and shifted patients from the same recipe with a new seed and you get another. Five of them were run, twenty models each. One thing survived all five and one thing did not, and the difference between those two outcomes is the most useful part of the bench.

Five draws. Held-out spread on top, shifted spread below, one shared scale. Draw Spreads Ratio corr(held, shifted) 1 0.019 0.051 2.7x -0.89 2 0.008 0.038 4.8x +0.03 3 0.012 0.046 4.0x -0.87 4 0.003 0.034 11.3x +0.09 5 0.016 0.048 3.0x -0.75 Five out of five on the ratio. The correlation changes sign between draws, so it is not a finding.
🔍 Click to zoom - the column that repeats and the column that does not, side by side.
LiveThe part that repeated4 min▶

In five draws out of five the shifted spread was larger than the held-out spread, by 2.7, 4.8, 4.0, 11.3 and 3.0 times. The absolute numbers are worth holding too: the held-out spreads are thousandths, from 0.003 to 0.019, and the shifted spreads are hundredths, from 0.034 to 0.051. Twenty models that agree to within three thousandths of an accuracy point on draw 4 disagree by thirty-four thousandths once the ward arrangement changes.

Nothing here required an unusual world or an adversarial perturbation. The training set is 4,000 patients with two genuine signals in it, the model is small, and the shift is one arrangement in a hospital group changing. The spread is what the pipeline was always able to produce; the shifted set is only the place where it becomes visible.

LiveThe part that did not repeat, and why it is here4 min▶

The correlation between held-out and shifted accuracy reads -0.89 on draw 1, +0.03 on draw 2, -0.87 on draw 3, +0.09 on draw 4 and -0.75 on draw 5. A first run of this bench produced -0.89 and, with it, a headline: the best model on the held-out set is the worst under shift. One more data draw destroyed it.

Two readings of that column are both defensible from the numbers alone. One says the negative values in three draws out of five point at a real inverse relationship that the two positive draws are too noisy to show. The other says a quantity whose sign moves between draws is uninformative and the negatives are coincidence. Neither reading is settled by five draws, and the second is the one that survives contact with more of them so far. What is not defensible is quoting draw 1 on its own, which is how the first version of this bench nearly shipped. Session 9 takes the whole episode apart.

Self-studyOne number, and the distribution behind it4 min▶

A standard pipeline run prints one accuracy. That number is a sample of size one from the set of models the pipeline can return, and the sampling was done by whatever seed happened to be in the config file. Reporting it as the model's accuracy is the same move as reporting one patient's blood pressure as the ward's.

The fix is not to report the best of twenty, which is session 5's mistake in a different costume. It is to report the range. "0.949 held out, twenty seeds inside 0.019" is a stronger sentence than "0.949", and "0.765 shifted, twenty seeds inside 0.051" is a much weaker one than "0.765", which is the point.

Part 3 · build-along

Run the sweep, read it in order

15 min build-along

The sweep is a loop around training code you already have. Reading it takes discipline, because the ratio is the headline and the headline is the last thing to look at.

Read the sweep in this order. The ratio is third for a reason. 1 The absolute spreads Highest minus lowest, in each column, before any division. Thornbury held out: 0.003 to 0.019 Thornbury shifted: 0.034 to 0.051 Thousandths against hundredths. 2 The ratio Shifted spread divided by held-out spread. Thornbury: 2.7, 4.8, 4.0, 11.3, 3.0 across the five data draws. Above one in five out of five. 3 The reliance column Flip the suspect feature, count the predictions that change. Thornbury: 0.70 to 1.00 on the ward across the same twenty seeds. Says which models have most to lose. A ratio near one means two completely different things. Both spreads in thousandths: the shift you built cannot see the difference between these models. Both spreads in hundredths: the pipeline is unstable everywhere, including where you reported it.
🔍 Click to zoom - the ratio is uninterpretable until both spreads have been read on their own.

Build the three sets once. Training and held-out from the collection year, shifted from the deployment year. They are fixed for the whole sweep, so every model is scored on identical rows and any difference is the model.

Loop the seed, keep everything. Twenty runs, three numbers each: held-out accuracy, shifted accuracy, reliance on the suspect feature. Append every row. Nothing is discarded and nothing is ranked yet.

Take both spreads before the ratio. Highest minus lowest in each column. Write both down in full digits, because the ratio throws away the information that tells you which situation you are in.

Divide, and say how many draws it held for. One ratio from one world is a number, not a result. Regenerate the data and run it again before the ratio goes anywhere near a slide.

Point it at your own model. Any pipeline with a seed argument qualifies, including gradient boosting and anything with dropout or subsampling. Five seeds is enough to see whether the spread is thousandths or hundredths.

Do not pick the winner. The sweep is a measurement of the pipeline, not a tournament between models. Choosing the best of twenty on the shifted set is the subject of session 5, and it costs something.

★ Block 1 · the sweep, against the engine on this site // assets/ep-live.js exposes window.THORNBURY var T = window.THORNBURY; var DRAW = 101; // draw 1; the others are 555, 909, 4242, 7 var trainRows = T.makeData(4000, DRAW, 0.90); // collection year var heldRows = T.makeData(2000, DRAW + 1, 0.90); // collection year, not trained on var shiftRows = T.makeData(2000, DRAW + 2, 0.50); // deployment year, ward reorganised var rows = []; for (var s = 1; s <= 20; s++) { var m = T.train(trainRows, 1000 + s); // 3 inputs, 12 tanh units, 1 logit rows.push({ seed: s, held: T.acc(m, heldRows), shifted: T.acc(m, shiftRows), ward: T.relianceOnWard(m, heldRows) }); } // T.train's defaults are the whole specification: hidden 12, epochs 30, // lr 0.08, l2 2e-4. The second argument is the only thing moving in that loop.
★ Block 2 · both spreads, then the ratio function spread(xs) { return Math.max.apply(null, xs) - Math.min.apply(null, xs); } var held = rows.map(function (r) { return r.held; }); var shifted = rows.map(function (r) { return r.shifted; }); var ward = rows.map(function (r) { return r.ward; }); var hs = spread(held), ss = spread(shifted); console.log("held-out spread", hs.toFixed(3)); // 0.019 on draw 1 console.log("shifted spread ", ss.toFixed(3)); // 0.051 on draw 1 console.log("ratio ", (ss / hs).toFixed(1)); // 2.7 on draw 1 console.log("reliance range ", Math.min.apply(null, ward).toFixed(2), "to", Math.max.apply(null, ward).toFixed(2)); // 0.70 to 1.00 across seeds // Then change DRAW to 555, 909, 4242 and 7 and run the whole thing again. // The ratio came out 2.7, 4.8, 4.0, 11.3 and 3.0. Five worlds, one direction.
★ Block 3 · the same sweep around your own training code import numpy as np # fit_model(seed) is whatever you already have: it must accept a seed and # return something with a .predict. X_held / X_shift are fixed for the sweep. records = [] for seed in range(20): model = fit_model(seed) records.append({ "seed": seed, "held": float((model.predict(X_held) == y_held).mean()), "shifted": float((model.predict(X_shift) == y_shift).mean()), }) held = np.array([r["held"] for r in records]) shifted = np.array([r["shifted"] for r in records]) print("held-out spread", round(float(np.ptp(held)), 4)) print("shifted spread ", round(float(np.ptp(shifted)), 4)) print("ratio ", round(float(np.ptp(shifted) / np.ptp(held)), 1)) # No shifted set yet? Then you have one column and no ratio, which is an # honest state to be in. Session 4 is about building the second column.

The habit to keep. Whenever a model is about to be approved on a single accuracy figure, ask how many seeds produced it. If the answer is one, the figure is a sample of size one from a distribution nobody has looked at, and twenty minutes of compute converts it into a range. Report the range next to the number: "0.949 held out, twenty seeds inside 0.019, 0.765 shifted, twenty seeds inside 0.051" is a claim somebody can check.

Check yourself

Three questions

Twenty Thornbury models differ only by the random seed. On draw 1 the held-out spread is 0.019 and the shifted spread is 0.051. What does that license you to say?

The held-out estimate is fine and precise: twenty models land inside nineteen thousandths of it. The problem is that the number the review sees is identical across models that behave differently once the ward arrangement changes. Tuning the seed on the held-out set would select on a quantity that carries almost no information about the shifted column, which is session 5's territory.

Draw 1 gives a correlation of -0.89 between held-out and shifted accuracy. Across the five draws the values are -0.89, +0.03, -0.87, +0.09 and -0.75. What goes in the write-up?

A quantity that reads -0.89 in one world and +0.09 in the next has not established a direction. More seeds per draw would tighten each estimate without addressing the thing that moved, which was the data draw. The first version of this bench nearly shipped the majority reading, and session 9 is about how close that came.

A colleague runs the sweep on their own model and reports a ratio of 1.1. What do you need before you can interpret it?

Both spreads in thousandths means the stress set cannot distinguish these models, which may say more about the stress set than about the pipeline. Both spreads in hundredths means the pipeline is unstable in both places, including the one that was reported. The division hides exactly the digits that separate those two situations.

Homework

Before session 4

30 min

Run block 3 on a model your team owns, with five seeds rather than twenty, and record the held-out spread in full digits. Most pipelines have a seed somewhere even if nobody set it deliberately. Then write one sentence naming a shift you could score those same five models on: something about the world that is true now and might not be in a year. Bring the sentence rather than the spread. Session 4 is about whether that shift is one you can defend, and the first draft of it is usually wrong in an instructive way.

Sources covered

What tonight maps to

✓ Underspecification, operationally D'Amour et al. (2020): a pipeline that can return many predictors with equally strong held-out performance, which behave differently in deployment. A property of the pipeline, tested by varying something that should not matter.
✓ Bench A, draw 1 Twenty models inside 0.019 held out and 0.051 shifted, a ratio of 2.7 times, with mean accuracies of 0.949 and 0.765.
✓ All five data draws Ratios of 2.7, 4.8, 4.0, 11.3 and 3.0. The shifted spread was wider in five draws out of five.
✓ How to run a seed sweep Fixed sets, one loop, three columns kept, both spreads read before the ratio, and the same loop around any pipeline that takes a seed.
✓ How to read the ratio Absolute spreads first, ratio second, reliance third, and the two different meanings of a ratio near one.
◐ Designing the shifted set Session 4. What a stress test can and cannot establish, and D'Amour et al.'s five application domains.
◐ The correlation that changed sign Session 9 owns the full account of the finding that one more data draw destroyed.
◐ What picking the best of twenty costs Session 5 measures it rather than asserting it.
· Memorization, random labels and double descent Not covered by design. learn-deep-learning-with-phoebe session 05 owns how a network can fit noise and what the interpolation threshold means.
· Metric definitions and drift detection Not covered by design. learn-model-evaluation-with-phoebe defines every metric and owns monitoring.

Session 3 cheat sheet

Underspecified pipelineIt can return many predictors with equally strong held-out performance. The score does not identify which one you have.
Vary what should not matterThe seed sets initial weights and example order. Nobody claims those are part of the model.
0.019 against 0.051Draw 1, twenty models. Thousandths where you looked, hundredths where you did not.
2.7 to 11.3 timesThe ratio across five data draws. Wider off-test in five out of five.
Spreads before the ratioA ratio of one means different things at thousandths and at hundredths. Read both columns raw.
Reliance third0.70 to 1.00 on the ward. It says which of the twenty have the most to lose.
A fixed seed hides the rangeIt buys reproducibility, not representativeness. Sweep to see what the pipeline can return.
The sign that moved-0.89 to +0.09 across draws. One draw is not a finding, and that near-miss is session 9.