Cheat sheets

ML System Design, Drift and Feature Stores

Frame the task, price serving, beat baselines, roll out safely, catch drift and training-serving skew.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

One definition, two readers#

backfillmaterializeRaw eventsRegistryfeature definitionsOffline storehistory withtimestampsPoint-in-timejoinlabels to trainingsetOnline storelatest value perentityServing requesta few millisecondsLogged featuresserving timeSkew checkmismatch rate perfeaturebackfillmaterializeRaweventsRegistryfeaturedefinitionsOfflinestorehistorywithtimestampsPoint-in-timejoinlabels totrainingsetOnlinestorelatestvalue perentityServingrequesta fewmillisecondsLoggedfeaturesservingtimeSkewcheckmismatchrate perfeature

From Lesson 02.21

From goal to safe launch#

1Taskname the prediction, the entity, the horizon andthe decision that uses it.2Metricspick offline, online, business and guardrailmetrics before the model.3Baselinestrivial, heuristic and current system. Set aminimum lift first.4Datacheck label source, label delay and that everyfeature exists at prediction time.5Budgetsset p99 latency, peak QPS, cost per day andstaleness.6Shadowthe new model scores a copy of live traffic.Nobody uses its output.7Canaryreal decisions for 1 to 5 percent of traffic.Roll back on a guardrail break.8A/B testrandom user split. Measure the business metricwith a statistical test.

From Lesson 02.19

Toolkit calls#

TaskCode
Cheapest plan in budgetchoose_serving(workload, costs)
Lift over the best baselinecompare_to_baselines(..., min_lift=0.02)
Score a design docreview_design_doc(doc, ready_score=0.85)
Numeric drift, decile binspsi(reference, current, bins=10)
Largest CDF gapks_statistic(sample_a, sample_b)
Categorical driftchi_square_test(reference_counts, current_counts)
As-of join with TTLpoint_in_time_join(labels, rows, ttl_days)
Compare logged featuresdetect_skew(training, serving, features)

From 02.19 code/main.py, 02.20 code/main.py, 02.21 code/main.py

Price batch and online serving#

refresh_hours = workload.max_staleness_hours - costs.batch_job_hours
if refresh_hours <= 0:job longer than the limit
return ServingPlan("batch", False, ...)
runs_per_day = 24.0 / refresh_hours
predictions = workload.entities * runs_per_day
dollars = (predictions / 1e6 * costs.batch_dollars_per_million
+ workload.requests_per_day / 1e6 * costs.lookup_dollars_per_million)
replicas = max(costs.min_replicas, math.ceil(workload.peak_qps / costs.replica_qps))
dollars = replicas * costs.replica_dollars_per_hour * 24.0online pays for idle
feasible = costs.online_latency_ms <= workload.latency_budget_ms

From 02.19 code/main.py

Drift and skew formulas#

Covariate drift
P(x) changes. Input monitors see it.
Prior drift
P(y) changes. Prediction and outcome monitors see it.
Concept drift
P(y | x) changes. Only outcome monitors see it.
PSI
\sum (\text{current} - \text{reference}) \cdot \ln(\text{current} / \text{reference}) over bins.
KS D
largest gap between two empirical CDFs. 0 for identical, 1 for no overlap.
Cramér's V
square root of chi2 / grand_total for a two-row table.
Little's law
in progress = throughput times latency. 400 rps at 50 ms is 20.
Lift
model score minus the strongest baseline score.

From Lesson 02.20, Lesson 02.19

Commands#

CommandWhat it does
python3 code/main.pyRuns each lesson demo with the standard library
python3 code/main.py my_design_doc.jsonReviews your own design document
stats.ks_2samp(reference_amounts, current_amounts)KS statistic and p-value in scipy
stats.chi2_contingency(table)Chi-square statistic, p-value and dof
DummyClassifier(strategy="most_frequent")Majority-class baseline
feast applyRegisters feature definitions in Feast
feast materialize-incremental <end time>Copies latest values to the online store
store.get_historical_features(entity_df=...)Point-in-time training features

From Lesson 02.19, Lesson 02.20, Lesson 02.21

Defaults and numbers#

SettingDefaultNote
family_alpha0.01Bonferroni, 0.005 for each of two tests
psi_warn0.10PSI below 0.1 is stable
psi_drift0.25Above 0.25 is a significant shift
ks_drift0.10D must pass and p below alpha
min_cramers_v0.10Effect size for categories
patience2Consecutive drift windows before an alert
window_size500step=250, label_delay=500
PSI share clip0.0001Stops an infinite log

From 02.20 code/main.py, Lesson 02.20

Failures and fixes#

SymptomCauseFix
Model service times outNo plan for the failureUse the heuristic baseline
Nightly batch job failsScores go missingServe last good scores, then the rule
Score distribution jumpsWrong decisions at scalePause actions and alert a person
Inputs drift, accuracy stableCovariate driftOften none. Watch the outcome
Accuracy drops, inputs quietConcept driftCollect new labels, then retrain
Offline 0.948, live worseNaive join reads future rowsPoint-in-time join
Serving default -1, training 365Two code pathsOne registry definition
60 false alarms per day50 features hourly at 0.05Bonferroni, effect size, persistence

From Lesson 02.19, Lesson 02.20, Lesson 02.21

Abbreviations#

PSI
Population Stability Index. From credit scoring.
KS
Kolmogorov-Smirnov. Two-sample test on CDFs. Needs no bins.
TTL
time to live. An older value counts as missing.
QPS
queries per second. Size for the peak, not the average.
p99
the latency that 99 of 100 requests stay under.
CBPE
Confidence-based Performance Estimation. Fails on concept drift.

From Lesson 02.19, Lesson 02.20, Lesson 02.21

Questions#

When not to use ML?
A short rule works, no labels, nobody acts, or one error is unacceptable.
Why not AUC?
It averages over thresholds you never use. Match the decision instead.
How to split data?
Train 60-80%, validation 10-20%, test 10-20%. Hold out the newest period.
How to break a feedback loop?
Keep a random holdout that never gets the intervention.
How to find the skew cause?
Compare online read, fresh compute and second code path.
After retraining?
Test on recent labels, shadow and canary, then reset the reference window.

From Lesson 02.01, Lesson 02.19, Lesson 02.21, Lesson 02.20