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

Stress tests, and what they license

Session 3 read a spread off a shifted column without ever asking where that column came from. Tonight builds it. The shifted set at Thornbury is one argument away from the held-out set, and the discipline in that one argument is the whole session: the shift has to be one you can name and justify from how the hospital group actually changes, it has to land on the inputs rather than the labels, and passing it buys you a claim about that shift and no others. D'Amour et al. ran stress tests across five application domains and found the same thing in all of them.

🔴 Hardest Anyone asked to prove a model is robust Anyone who has been handed a robustness section to review 45 min
0-3 · Welcome 3-16 · What it licenses 16-29 · Three design rules 29-45 · Build-along and Q&A
Part 0

Where tonight sits

The two numbers quoted across the whole track, 0.949 held out and 0.765 shifted, are not symmetrical. The first comes from a split, which is a procedure. The second comes from a design decision somebody made about how the world changes, and a different decision would have produced a different number. Tonight is about making that decision defensible, because the shifted column is only as good as the argument behind it. Session 5 asks what happens once people start choosing models against it.

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

★ What you walk out with tonight. Three rules for designing a shift, each with the failure it prevents. The exact construction of the Thornbury shifted set, one argument different from the held-out set, so you can see where a stress test lives in code. The sentence a passed stress test licenses, and the three sentences it does not. And D'Amour et al.'s five application domains as the answer to anyone who says this is a hospital problem.

LiveA stress test is a scored set, not a technique4 min▶

There is nothing clever in the machinery. A stress test is a second evaluation set, built so that one named thing about the world is different, and scored with the same metric on the same trained model. No retraining, no new features, no change to the model at all. At Thornbury the named thing is the ward arrangement, and the difference between the held-out set and the shifted set is a single argument in the generator moving from 0.90 to 0.50.

What makes it hard is not the code, it is the argument for why that shift and not another. Anyone can perturb a column and produce a drop. A drop only means something if the perturbation corresponds to a change the world can actually make, which is why the design rules in Part 2 are about justification rather than about method.

Self-studyThe words that will keep coming back4 min▶
  • Stress test. Scoring a trained model on data built so one named aspect of the world differs from the collection conditions.
  • Named shift. A change you can describe in a sentence about the world, with a mechanism, before you write the code that produces it.
  • Input shift. The relationship between the features and the outcome changes. The outcome itself is still generated the same way.
  • Label shift. The outcome changes. A drop measured after moving labels is not a fact about the model.
  • The licensed claim. The one sentence a passed stress test supports, which always names the shift it was run under.
  • The unenumerable remainder. Every shift you did not think of. It does not shrink when you pass the ones you did.
Part 1 · covers what a stress test licenses

A narrow claim, held firmly

13 min live

The Thornbury shifted set answers one question well. Twenty models that were indistinguishable held out separate on it, and the separation is measurable: reliance on the ward from 0.70 to 1.00, shifted accuracy spread across 0.051 on draw 1. That is a strong result about one shift, and it is silent about everything else.

One shift, tested. Two very different lists follow from it. Establishes This model relies on the ward. That one does not. Measured, not argued. The pipeline returns predictors that differ under this shift, by 0.051 on draw 1. The size of the drop under this shift: 0.949 held out against 0.765 shifted. The same model, scored twice. Does not establish That the model holds under a shift nobody thought of. Nothing tests that. That 0.765 is the worst case. A ward that reversed would cost more. That a model which passed is robust. It passed one test, under one shift, on one named feature. Passing a stress test removes one way of being wrong from a list nobody can finish writing.
🔍 Click to zoom - the left column is evidence, the right column is the part that gets dropped in the summary.
LiveThe sentence you may write, and the one you may not4 min▶

Licensed: "scored on patients from a year in which the ward no longer agrees with the outcome, this model falls from 0.949 to 0.765, and its measured reliance on the ward is the figure printed beside it." Every clause names something that was done. A reader can disagree with the design of the shift, and that disagreement is productive because the design is on the page.

Not licensed: "the model is robust to distribution shift." That sentence is about a category, and the test was about one member of it. It is also the sentence that gets written, because it is shorter and because the robustness section of a document is usually read as a verdict rather than as a list of what was tried.

Real world

Ask for the list, not the verdict. "Which shifts did you score it on" produces a short honest answer, usually one or two, and everybody in the room can then see the remainder. "Is it robust" produces a yes.

LiveFive domains, one result4 min▶

D'Amour et al. (2020) is a forty-author paper, and the author list is doing work. Their stress tests span computer vision, medical imaging, natural language processing, clinical risk prediction from electronic health records, and medical genomics. Different data types, different teams, different pipelines, and the same finding: many predictors with equally strong held-out performance, behaving differently once they were scored somewhere else.

That breadth is the answer to the most common deflection, which is that the effect is an artefact of one field's data or one team's habits. Thornbury is a small simulation built to make the mechanism visible and checkable. The evidence that the mechanism is general is theirs, not this bench's.

Where D'Amour et al. ran their stress tests. Computer vision Medical imaging Natural language processing Clinical risk prediction from health records Medical genomics Forty authors, five domains, one result. Many predictors with equally strong held-out performance, behaving differently once they were scored elsewhere.
🔍 Click to zoom - the breadth is the argument that this is not one field's local difficulty.
Part 2 · covers the design discipline

Three rules for a shift worth scoring

13 min live

Each rule exists because a specific bad stress test is easy to write and looks exactly like a good one in the write-up. The rules are about the design, not the code, and the third one is the one teams break after the run rather than during it.

Each rule is here because the test that breaks it reads like a good one. 1 Name it first A shift you can describe as a sentence about the world, with a mechanism, before any code. Holds The group reorganises its wards. Hospital groups do that. Fails Gaussian noise on every column. Nothing in the world does that. 2 Move the inputs The outcome is generated the same way on both sides. Only the inputs behave differently. Holds The ward stops agreeing with who deteriorates. Fails Flip one outcome in five. The drop measures the labels. 3 Claim only what you ran The licensed sentence names the shift. Every time, including in the one-line summary. Holds Falls to 0.765 when the ward stops agreeing with the outcome. Fails Robust to distribution shift. One member, whole category.
🔍 Click to zoom - name it, move the inputs, claim only the shift you ran.
LiveWhy the labels must stay where they are4 min▶

Corrupting labels in the stress set produces a drop reliably, which is what makes it tempting. It measures nothing about the model. Flip one outcome in five and a perfect model is now scored wrong on one row in five, because the thing predictions are compared against has been made wrong. Every model in the pool loses ground together, and the number that comes out is a property of the corruption.

The Thornbury shift keeps the outcome mechanism untouched and moves an input's relationship to it. A patient with a given vitals drift and lab trend deteriorates with exactly the same probability in the deployment year as in the collection year. What changed is which ward that patient is in, which is a fact about hospital administration and not about physiology. A model that never used the ward scores the same in both worlds, and that is the property the test is built to expose.

LiveAn open disagreement: named shifts, or a broad battery5 min▶

The rules above take one side of a live argument, and the other side is not foolish. The named-shift position says a perturbation with no mechanism behind it produces a number nobody can act on: if you cannot say what in the world would do that to your data, a drop tells you nothing about deployment and an absence of a drop tells you less.

The battery position says that the shifts which break models are, almost by definition, the ones nobody anticipated, so restricting yourself to shifts you can justify guarantees you only ever test the failures you already feared. On this view a wide sweep of arbitrary perturbations is a detector for underspecification rather than a forecast of deployment, and a pipeline whose outputs scatter under nonsense perturbations is telling you something real even though the perturbations are not.

Both positions are held by people who have shipped models that failed. They disagree about what the number is for: evidence about a deployment, or evidence about a pipeline. The practical reconciliation, which neither camp fully accepts, is that they are different measurements and should be reported under different headings rather than averaged into a robustness score.

Self-studyWhere the shift comes from when you cannot simulate it4 min▶

Thornbury can regenerate its deployment year because the world is a function. Real projects usually cannot, and the substitutes are ordinary: hold out a later time period rather than a random slice, hold out one site or region entirely, score on the subgroup whose intake process changed last year, or use data collected before and after a known policy change as two worlds.

Each of those is a named shift with a mechanism, which is the only property that matters. A held-out year is a stress test if you say what you expect to have changed in it, and it is just another random split if you do not. Generalisation of an experiment to a new population is a different subject and belongs to learn-experimentation-with-phoebe; the question here is a fitted model scored somewhere else.

Part 3 · build-along

Build the Thornbury shifted set

16 min build-along

The whole stress test is one argument. Below is the generator that produces both worlds, the three lines that call it, and the mistake that looks identical in a diff.

One generator, one argument, two worlds. The outcome mechanism, identical in both worlds y drawn from sig(-0.35 + 1.25*vitals + 1.05*lab). Two honest signals, and no ward term anywhere in it. A patient with the same vitals and labs deteriorates with the same probability on both sides. Collection year makeData(n, seed, 0.90) The ward agrees with the outcome 90 percent of the time. Training and held-out rows. one argument Deployment year makeData(n, seed, 0.50) The ward agrees with the outcome 50 percent of the time. The shifted rows. Nothing else moved. An input's relationship to the outcome moved. The outcome did not. So the fall from 0.949 to 0.765 belongs to the model, and a model that ignored the ward would not fall at all.
🔍 Click to zoom - the shift is a single argument, and its discipline is that the label line is untouched.

Write the sentence before the code. "The group reorganises its wards, so the ward stops agreeing with who deteriorates." If the sentence needs the code to make sense, the shift has no mechanism behind it yet.

Find the one parameter that carries it. At Thornbury it is the agreement rate between the ward and the outcome. One argument, one value in each world, and a diff a reviewer can read in a second.

Check the label line is untouched. Read the generator and confirm the outcome is drawn the same way on both sides. This is the step that gets skipped, and skipping it is how a stress test comes to measure its own corruption.

Score without retraining. The same trained model, the same metric, the new rows. Any retraining turns a stress test into a different experiment about whether the pipeline can learn the new world.

Report both numbers and the shift. Held out, shifted, and the sentence from step one. Two numbers with no sentence between them is the shape most robustness sections already have.

Write down what you did not test. A ward that reverses rather than decays, a new intake process, a different patient mix. The list is short to write and it is the part a reader cannot reconstruct.

★ Block 1 · the generator, from assets/ep-live.js /* Both worlds come out of this one function. shortcutStrength is the shift. */ function makeData(n, seed, shortcutStrength){ var r=rng(seed), rows=[]; for(var i=0;i<n;i++){ var vit=normal(r), lab=normal(r); var z=-0.35+1.25*vit+1.05*lab; // the outcome mechanism: no ward in it var y = r() < sig(z) ? 1 : 0; // this line is the same in both worlds /* ward agrees with the outcome shortcutStrength of the time */ var ward = (r() < shortcutStrength) ? y : (r()<0.5?1:0); rows.push({x:[vit,lab,ward], y:y}); } return rows; }
★ Block 2 · three sets, one trained model, two scores var T = window.THORNBURY; var trainRows = T.makeData(4000, 101, 0.90); // collection year var heldRows = T.makeData(2000, 102, 0.90); // collection year, never trained on var shiftRows = T.makeData(2000, 103, 0.50); // the stress test var m = T.train(trainRows, 1001); // trained once, on the collection year only console.log("held out", T.acc(m, heldRows).toFixed(3)); // around 0.949 console.log("shifted ", T.acc(m, shiftRows).toFixed(3)); // around 0.765 console.log("reliance", T.relianceOnWard(m, heldRows).toFixed(2)); // 0.70 to 1.00 by seed // No retraining between the two scores. The model does not know the wards moved, // which is the entire point: deployment does not retrain you either.
✗ The stress test that measures nothing // WRONG: this moves the labels, not the inputs. shiftRows.forEach(function (row) { if (Math.random() < 0.2) row.y = 1 - row.y; }); // Every model in the pool now loses ground together, including one that // never looked at the ward, and including a perfect one: one row in five // is scored against the wrong answer. Nothing about the model was measured.

The habit to keep. Every robustness claim gets a shift named in the same sentence as the number. "0.765 once the ward stops agreeing with the outcome" survives a reader asking what was tested; "robust to shift" does not. And keep the list of untested shifts next to the tested one, because the person reading your summary in six months will otherwise assume the list is empty.

Check yourself

Three questions

A model passes the Thornbury stress test: it scores 0.949 held out and barely moves on the shifted set. What may go in the summary?

One shift was scored, so one claim is licensed and it names that shift. Other shortcuts may exist and would only appear under stresses nobody built, and the category word "robust" turns a result about one member into a claim about all of them.

A colleague builds a stress set by flipping one outcome in five, and reports that accuracy fell sharply. What did they measure?

Moving the labels changes what the predictions are being compared against, so the drop is a property of the manipulation rather than of the model. A stress test has to leave the outcome mechanism alone and move an input's relationship to it, which is what the single argument in the Thornbury generator does.

Why does the D'Amour et al. paper span computer vision, medical imaging, natural language processing, clinical risk prediction from electronic health records and medical genomics?

Forty authors across five application areas found many predictors with equally strong held-out performance behaving differently under stress. A single-domain result invites the reply that the domain is unusual, which is exactly the reply the breadth removes.

Homework

Before session 5

30 min

Take the shift sentence you wrote after session 3 and put it through the three rules. Does it name a mechanism the world actually has? Does it move an input rather than the outcome? Then write the claim that passing it would license, in one sentence that mentions the shift. Most first drafts fail rule two without noticing, usually by resampling the outcome to change the base rate. Bring the sentence and the claim. Session 5 asks what happens once a set like this starts being used to choose between models rather than to describe one.

Sources covered

What tonight maps to

✓ What a stress test can establish That this model relies on the ward and that one does not, that the pipeline returns predictors which differ under this shift, and the size of the drop: 0.949 against 0.765.
✓ What it cannot establish That the model holds under a shift nobody designed, that the measured drop is the worst case, or that a model which passed is robust in general.
✓ D'Amour et al.'s five application domains Computer vision, medical imaging, natural language processing, clinical risk prediction from electronic health records, and medical genomics. Forty authors, one result.
✓ The three design rules Name the shift and justify it from how the world changes, apply it to the inputs and not the labels, and claim only the shift you ran.
✓ How the Thornbury shifted set is built One generator, one argument. The outcome line is identical in both worlds and the ward agreement moves from 0.90 to 0.50.
◐ What selecting on this set would cost Session 5 measures what happens once a set is used to choose a model rather than to describe one.
◐ Both benches, run live Session 10. The shifted set built here is what pane A scores against.
· External validity for experiments Not covered by design. learn-experimentation-with-phoebe owns generalising an experiment to a new population; the question here is a fitted model scored elsewhere.
· Fairness auditing Not covered by design. The stress tests here are about credibility rather than group harm, and the fairness literature is a separate subject.
· Drift detection and monitoring Not covered by design. learn-model-evaluation-with-phoebe owns detecting a shift after deployment; tonight is about scoring one before.

Session 4 cheat sheet

A stress test is a scored setSame model, same metric, one named thing about the world different. No retraining.
Name it before you code itIf you cannot say what in the world would do that to your data, the drop is uninterpretable.
Move inputs, never labelsFlip one outcome in five and even a perfect model is scored wrong on one row in five.
One argumentThornbury's two worlds differ by 0.90 against 0.50. The outcome line is identical on both sides.
Claim the shift, not the categoryFalls to 0.765 when the ward stops agreeing, rather than robust to distribution shift.
Five domainsVision, medical imaging, NLP, clinical risk from health records, genomics. Forty authors, same result.
The remainder does not shrinkPassing removes one way of being wrong from a list nobody can finish writing.
List what you did not testA reversed ward, a new intake process, a different patient mix. Readers assume the list is empty.