learn-web3-with-phoebe / Practitioner session 8 of 10
Learn Web3 with Phoebe · Practitioner session 8 of 10

ML on public adversarial data

Three things are true about Larkfield's rows that are not true about the datasets modelling practice was built on. The features are readable by everyone, including the people who produce the inputs. The population is not a sample of anything, because 240 of about 1,000 address rows were created on purpose by 4 parties. And 5.75 percent of a naive load describes history the chain no longer has, so a training set frozen without a finality lag contains events that did not happen. Each of those is measured on the benches, and none of them is fixed by choosing a different model.

🔧 Practitioner track Anyone training a model on ledger rows Anyone signing off a model's evaluation 45 min
0-3 · Welcome 3-18 · Three properties 18-30 · The unit of analysis 30-45 · Build-along and Q&A
Part 0

The model is the last decision, and the smallest one

A modelling brief on this data looks ordinary right up to the point where somebody asks where the rows came from. Larkfield has a table, it has a grain, it has a target worth predicting, and every library on the shelf will fit something to it without complaining. What has changed is underneath the table. Three properties of the source decide most of the outcome before a single hyperparameter is chosen, and all three of them are measurable tonight rather than arguable.

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

★ What you walk out with tonight. The three properties named and priced: 195 addresses your only feature is blind on and a blind spot anyone can enumerate, 240 of about 1,000 rows belonging to 4 parties, and 511 rows in a naive load describing history that is gone. The measurement most people do not expect, which is that clustering the addresses raises the operator share of the training population from 24.4 percent to 34.3 percent against a truth of 1.3. And the habit that follows: settle the unit of analysis, the label source and the load discipline before anyone opens a modelling library, because the model choice cannot reach any of them.

LiveWhat is actually different here4 min▶

Plenty of datasets are noisy, imbalanced or drifting, and the craft for all three is well developed. None of that craft is what is being tested tonight. Noise is a property of measurement. What Larkfield has is a property of authorship: some of these rows exist because a party decided they should exist, and that party knows what Larkfield can compute from them, because the columns are public.

That is a narrow difference and it has wide consequences. It means the training distribution is not a sample from a population, it is a population that was partly assembled. It means an evaluation set drawn the same way inherits the same composition. And it means a feature's usefulness is not a stable fact about the world, because the thing the feature reads is produced by somebody who can also read the feature.

Real world

Larkfield's first model scored well and shipped. The evaluation was an average over address rows, which is the default in every tutorial and the default in their notebook. Nobody had written down that a quarter of those rows belonged to four parties, because nobody had computed it. The model was good at the traffic those four parties produce and that is most of what the score was measuring.

Self-studyThe words used tonight3 min▶
  • Unit of analysis. What one row of the training table represents. Tonight it is an address, a clustered entity, or a real party, and the three give different answers to the same question.
  • Grain. The same idea said in a warehouse accent. Worth keeping both words, because the modelling side and the pipeline side rarely notice they are talking about one decision.
  • Population composition. Who is in the table and in what proportion. On ordinary data this is an accident of collection. Here part of it is a choice somebody else made.
  • One-sided error. An error that can only run in one direction. Bench A's clustering never fuses two parties, on any seed, so the count it produces can be too high and can never be too low.
  • Observable features. Features computed from columns that anyone can read. Not a security property, a modelling one: the inputs and the blind spots are both public.
  • Finality lag. How far behind the tip a loader stays before writing a block's rows. Session 7 priced it. Tonight it is a property of the training set rather than of the report.
  • Operator. A party running many addresses deliberately. Bench A has 4 of them holding 60 addresses each, and the generator knows which is which so the truth can be checked.
Part 1 · covers the three properties

Public features, authored labels, vanishing rows

15 min live

Take the three one at a time, each with the number the benches put on it. They are independent of each other, they are all present at once, and each one lands on a different part of the modelling workflow: the feature step, the population step, and the step where somebody freezes a snapshot and calls it a training set.

Three properties of the source, each measured, each landing on a different step of the workflow. 1 · YOUR FEATURES ARE PUBLIC THE ONLY EVIDENCE THERE IS you anyone The same columns, the same rows. Internal telemetry is private by default. These columns never were. 195 addresses your one feature says nothing at all about 787 of 982 addresses ever appear as a spend input. The rest carry no evidence, and that list is public. 2 · YOUR LABELS MAY BE MANUFACTURED ONE ROW PER ADDRESS, SEED 11 240 742 ordinary addresses 24.4%, and 4 parties chose it WHAT THE ROWS SAY ABOUT PARTIES truth clustered naive 304 676 to 707 982 a ceiling, never a correction 240 of about 1,000 rows belong to 4 parties, not to 240 The composition of the training population is not an accident of collection. Part of it is authored. 3 · YOUR TRAINING SET CAN BE WITHDRAWN A NAIVE LOAD, 200 BLOCKS 8,883 rows a report would see 511 rows, 5.75%, and nothing errored TRAINING SET, frozen at the tip carries every one of those rows 5.75% of a naive load describes history the chain dropped A training set assembled with no finality lag contains events that did not happen. None of the three is fixed by a better model, because none of them is a property of the model. They are properties of who can read the columns, who chose the population, and whether the rows you trained on still exist. The model choice is made after all three are settled, and here all three are settled by somebody other than you.
🔍 Click to zoom - the three panels are independent of each other and all three are true at once, which is why no single mitigation covers the set.
LiveYour features are public, and so are their blind spots4 min▶

Feature engineering on internal telemetry is a private act. You decide what to log, you decide what to derive, and the people who produce the events cannot see either decision. Here the derivation is the only part that is private, and even that is not much of a secret, because the co-spend signal is the standard one and anyone working this data reaches for it.

The sharper point is the blind spot rather than the feature. On seed 11, 787 of 982 addresses ever appear as a spend input at all. The remaining 195 are seen only as recipients, so the one feature available says nothing whatsoever about them. That is an ordinary coverage gap with one unusual property: anybody can compute exactly which 195 they are, from the same rows, with no access to Larkfield's warehouse.

A coverage gap you can enumerate from the outside is a different object from a coverage gap that lives in your logs. It is not a reason to stop using the feature. It is a reason to write down what the feature cannot see, in the model card, in the same place you write down what it can, because somebody else already has that list.

LiveThe population was partly written by four parties4 min▶

A table of one row per address looks like a sample. It is not. Across all five seeds of Bench A, exactly 240 addresses out of roughly a thousand belong to 4 operators running 60 each on purpose. That is about 24 percent of the training rows, and the 24 was not a fact about the world, it was a decision made by four parties who could have chosen 20 or 600.

This is why the word manufactured is worth keeping instead of softening it to imbalanced. Class imbalance is something you correct for, because the imbalance in the sample is an artefact of collection and the population underneath is fixed. Here the population underneath is not fixed. Reweighting to the observed composition reweights to a number somebody else set.

And the standard remedy does not remove it. Clustering by co-spend brings the count from 982 down to 696 on seed 11, which is an improvement, and the improvement is a ceiling rather than a correction. The truth is 304 and the clustered figure is still 2.3 times it. Session 4 measured that; tonight the consequence is that the training table is still mostly made of rows that do not correspond one to one with parties.

LiveA snapshot frozen at the tip is not a snapshot3 min▶

Session 7 priced the finality lag as a reporting decision. It is also a training decision, and it is a worse one, because a report is republished and a frozen training set is not. Bench B's naive loader ends the run with 511 rows, 5.75 percent of the warehouse, describing blocks that were replaced. A training set cut from that warehouse has those rows in it.

What makes this different from ordinary label noise is that the rows are not wrong in a random direction. They are all the tail of the table, the most recent blocks, which is precisely the region a time-based split puts in the validation fold. So the defect concentrates in the part of the data that is being used to decide whether the model works.

The fix is not a modelling fix and it costs nothing clever: apply a lag before you cut the snapshot, record the lag you used alongside the snapshot, and treat a training set with no recorded lag as a training set of unknown composition. That is a line in a manifest, and almost nobody writes it.

Self-studyWhere serious people disagree5 min▶

One camp says that a model should be trained at the grain the data actually has, which is the address, and that any attempt to model entities is importing an inference error into the features. Their case is concrete: the clustering is a heuristic with a known one-sided error, so training on clustered rows means training on a population whose composition depends on how well the heuristic happened to work in that month. Address grain is at least a stable definition. Whatever it fails to capture, it fails to capture the same way every time, and a stable wrong unit is easier to reason about than a unit that moves.

The other camp says that a model whose rows are not parties cannot answer a question about parties, and most of the questions worth asking are about parties. Training at address grain produces a model that is well calibrated on a population nobody cares about, and every downstream user will quietly read its output as being about people, because the output will be labelled with something that sounds like a person. On this view the inference error in the clustering is real and it is the smaller error, and the right move is to model at entity grain and carry the bound through to the output.

Both camps are staffed by people who have shipped models on identity-ambiguous data. Notice that Bench A does not settle the argument and cannot: it shows the clustering is a ceiling with zero wrong merges, which supports the second camp, and it also shows the ceiling is 2.3 times the truth and moves between 676 and 707 across months, which supports the first. What the bench does settle is that nobody may hold either position without stating which grain they are on, because the two produce different numbers on the same rows.

Part 2 · covers the unit of analysis

The unit of analysis outweighs the model choice

12 min live

Here is the measurement that changes how this session is usually taught. Clustering the addresses is the step everyone reaches for to make the population more honest. On Bench A it makes the operator share of the training population larger, not smaller, and by a wide margin. The step is still worth taking. It is just not doing what people assume it is doing.

Same rows, three units of analysis. The operator share moves, and once it moves the wrong way. SEED 11 · TEAL IS ORDINARY PARTIES, AMBER IS THE FOUR OPERATORS one row per address 982 rows 240 742 24.4% operator one row per clustered entity 696 rows 239 457 34.3% operator one row per true entity 304 rows, the generator knows 300 people 1.3% operator 4 operators Clustering raised the operator share of the training population from 24.4 percent to 34.3 percent. Ordinary addresses merge because they co-spend. Operator addresses mostly do not, so they come through the step almost intact. The truth is 4 operators among 304 parties, which is 1.3 percent of the parties that exist. An average over address rows gives those 4 parties about 19 times the weight they hold among real parties. Over clustered rows, about 26 times.
🔍 Click to zoom - the third bar is the one you do not have. It is drawn to the same scale so the size of the first two can be read against it rather than against each other.
Live Bench A running in this page. Change the month and watch the operator share of the training population move under a fixed method.

...

...
LiveEvaluation inherits the composition, and the direction4 min▶

An evaluation set drawn from the same rows has the same composition as the training set, which is the whole point of drawing it that way and is usually correct. It stops being correct when the composition is not a property of the world. A score averaged over address rows on seed 11 is a weighted average in which the four operators carry 24.4 percent of the weight, and on clustered rows they carry 34.3 percent. Among real parties they are 1.3 percent.

So a model that handles operator traffic well and ordinary traffic poorly gets a good score, and the score is not lying about anything it claims to measure. It is an honest average over the rows it was given. The rows were the decision.

The second half is the direction. Bench A reports zero wrongly merged clusters on all five seeds, which means the clustering error only ever fails to join addresses that belong together. A count taken from these rows can come out too high and cannot come out too low. Any metric built on top of that population inherits the same one-sidedness, so an evaluation that looks well calibrated is calibrated against a ceiling.

One axis, three positions, and an error that has only one direction available to it. PARTIES BEHIND ONE MONTH OF LARKFIELD ROWS TRUTH CLUSTERED NAIVE 304 676 to 707 982 to 1,025 every error points this way, and none of them points back 0 clusters wrongly merged, on all five seeds 392 addresses still split from their owner, seed 11 2.3x the clustered count against the truth of 304 A one-sided error is not a small error. It is a different kind of error. Every metric computed on this population inherits the direction. A count taken from these rows cannot come out too low, so a model that looks calibrated against them is calibrated against a ceiling rather than against the truth.
🔍 Click to zoom - the gap between the teal marker and the two bands is the error, and there is no band anywhere to the left of the marker.
LiveAnything that triggers a payment gets optimised against3 min▶

The last consequence is the plainest and the one with no technical remedy. Larkfield's product issues a reward for activity. If a model's output decides who receives a reward, then the model's output is worth something, and something worth money on a public dataset will be optimised against by whoever it pays. Bench A already contains the shape of that: four parties running 240 addresses, and the generator does not need to know why they did it for the count to be wrong.

What is worth stating precisely is the boundary of what the bench shows. It shows that a population can be substantially composed by a small number of parties, that the standard remedy leaves most of that composition in place, and that the composition is invisible in any metric computed at address grain. It does not show any particular method anybody used, and nothing here is a description of how to do it.

The operational consequence is a governance one rather than a modelling one. A model whose output moves money needs the question "who benefits if this score is wrong in this specific direction" answered in writing before it ships, and the answer belongs next to the evaluation rather than in a risk register somebody reads annually. If nobody can name the beneficiary, that is not reassurance, it is the same gap that made the address count look like a user count.

Self-studyWhat a model card has to say on this data4 min▶

Most model documentation templates have a field for the training data and it is usually filled in with a table name and a date range. On this data, three fields decide whether the document is worth anything, and none of them is standard.

The first is the unit of analysis, stated as a noun and not as a table name. "One row per address" and "one row per clustered entity" are different models with different meanings and the same schema, and the widget above shows they have different populations. A reader who cannot tell which one they are holding will read the output as being about people, because that is what the surrounding sentences will be about.

The second is the load discipline of the snapshot: the finality lag applied before the rows were frozen, as a number, with the reorganisation depth it was chosen against. A snapshot with no recorded lag is a snapshot of unknown composition, and Bench B says how unknown: 5.75 percent of a naive load at depth 3, concentrated in the most recent blocks.

The third is the direction of the known error. Not its magnitude, which moves between months, but its sign, which does not. Recording that the entity count is a ceiling with zero observed wrong merges tells a reader something they can act on immediately, which is that any downstream figure derived from it may be revised downwards and will never be revised upwards. That single sentence prevents more misuse than a page of metrics.

Part 3 · build-along

Take the three properties to a model you already have

15 min hands on

Six steps, on a model in your own estate, whether or not it touches a ledger. Bring the training set you wrote down for homework. Most of these take ten minutes and have never been asked.

Say your unit of analysis out loud

Not the table name. What one row is, as a noun. Then ask the person who reads the output what they think one row is. If the two nouns differ, stop the exercise here, because that is the finding and it outranks the other five.

Find the largest single contributor of rows

One party, one source, one integration. What share of your training rows do they account for? Bench A's answer is 24.4 percent for four parties combined. If you cannot compute yours in an afternoon, that is also an answer.

Ask who else can see your features

For each feature, mark whether its input is produced by somebody who can also observe it. On internal telemetry most will be no. Count the yes column and keep the number, because it is the part of your feature set that is not a stable fact about the world.

Write down what your features are blind on

The rows where the feature has no evidence at all, as a count and as a rule. Seed 11 has 195 of 982. Then ask whether somebody outside your team could derive that same list from data they already have.

Check the lag on your snapshot

How far behind the source was the cut? If the answer is "the latest data we had", your validation fold is made of the least settled rows in the table. Write the lag into the snapshot manifest today, even if today's value is zero.

Name the sign of your largest known error

Not the size, the direction. Can your headline number be too high, too low, or both? If both, say which is more likely and why. A number that can only be wrong one way is a different object from a number with noise on it.

The habit to keep. Before agreeing to a modelling brief on data you did not generate, ask three questions in this order. What is one row. Who chose how many of these rows exist. And can the rows I trained on be withdrawn. Nothing in the modelling toolkit answers any of the three, and the answers decide more of the outcome than every choice that comes after them.

Check yourself

Three questions

A team clusters Larkfield's addresses by co-spend before training, reasoning that it will make the population closer to a population of real parties. What does Bench A measure?

The step is still worth taking, because 696 is closer to 304 than 982 is. It just does the opposite of what is assumed to the composition: it compresses the part of the population that leaves evidence and leaves the part that does not almost intact.

Why is "your labels may be manufactured" a different problem from ordinary class imbalance?

Imbalance is an artefact of collection over a population that exists independently of you. Reweighting to the observed composition is reasonable there. Here the observed composition is partly an authored quantity, so reweighting to it reweights to somebody else's decision.

A training set is cut from a naive append-only load with no finality lag. Beyond the 5.75 percent of rows that are wrong, what makes this worse for a model than for a report?

The defect is not spread evenly. It sits at the tail, which is the part a temporal split uses to decide whether the model works, and the snapshot that carries it is frozen and shipped rather than recomputed next week.

Before session 9

Homework

Twenty five minutes. One written line about a model, and one result you find suspicious.

Write the three missing model card fields

For one model you own: the unit of analysis as a noun, the load discipline of the snapshot with a number, and the sign of the largest known error. Three lines. Bring them, and bring the field you could not fill in.

Bring a result that looked too good

Any measurement from your own work where a control, a filter or a safeguard appeared to give complete protection. It does not have to have been wrong. Session 9 is a bench that reported exactly that and was, and the way it was caught is the transferable part.

Covered tonight

What this session covers

✓Features that anyone can read787 of 982 addresses carry co-spend evidence, 195 carry none, and the list of which is public.
✓A population partly authored240 of about 1,000 address rows belong to 4 parties, on every seed, by their choice and not by collection.
✓A training set that can be withdrawn511 rows, 5.75 percent of a naive load, describing blocks that were replaced, concentrated at the tail.
✓The unit of analysis, measured24.4 percent operator at address grain, 34.3 at clustered grain, 1.3 in truth. Same rows, one decision.
✓Evaluation inherits the compositionAn honest average over rows somebody else composed, weighting 4 parties about 19 times their real share.
✓The one-sided error, carried throughZero wrong merges on all five seeds, so every derived figure is a ceiling and can never be revised upwards.
✓Three model card fields nobody fills inUnit of analysis as a noun, the lag on the snapshot as a number, and the sign of the largest known error.
◐The finality lag as a reporting decisionPriced in session 7. Tonight it returns as a property of a frozen snapshot instead.
◐Trusting a bench that reports a defence workingRaised tonight through the load discipline. Session 9 is the bench here that got it wrong and how it was caught.
○Probabilistic record linkageFuzzy matching, blocking and scoring live in learn-entity-resolution-with-phoebe.
○Chain mechanics and why branches get replacedThe prerequisite is learn-blockchain-with-phoebe and it is assumed rather than repeated.
○Any method for manipulating a real systemNot described anywhere here. Only what the generator produced and what the benches measured on it.
○Anything to do with price, markets or holdingsOut of scope by design, and nothing here is advice of any kind.
Take this with you

Cheat sheet

The one sentence. The features are public, the population is partly authored, and the rows can be withdrawn. No model choice reaches any of the three.
Public blind spots. 195 of 982 addresses have no co-spend evidence, and anyone can compute which 195 without touching your warehouse.
240 of about 1,000. Four parties, 60 addresses each, on every seed. A quarter of the training rows, chosen rather than collected.
The grain is the decision. Operator share is 24.4 percent per address, 34.3 percent per clustered entity, 1.3 percent in truth.
Clustering compresses the wrong half. It merges the addresses that co-spend. Operators mostly do not, so they come through nearly intact.
Evaluation is an honest average. Over rows somebody else composed. A score per address gives 4 parties about 19 times their real weight.
The sign, not the size. Zero wrong merges on five seeds means every derived count is a ceiling and can only ever be revised downwards.
The snapshot manifest. Record the finality lag on the cut. 5.75 percent of a naive load is wrong, and it sits in your validation fold.