From Model to Data Product: FastAPI & Docker
DSC3103 · Lab

FastAPI Model Serving & Training-Serving Skew Lab

Reproduce the Step 8 bug from Lab 9.2 — a feature threshold that differs between training and serving — and measure what loading the model per request really costs.

  1. 1 · Predict0/1
  2. 2 · Experiment0/2
  3. 3 · Explain0/1
  4. 4 · Code it0/2
  5. 5 · Challenge
  6. 0/4 tasks done

Predict first

Commit to a guess before you touch anything. Being wrong here is how it sticks.

Load = 150 ms, predict = 5 ms, 200 requests. Seconds saved by loading once at startup?

Experiment

Move the controls and watch the outputs. Goals tick off automatically when you reach them.

Training-serving skew

Training used is_rainy = rainfall_mm > 5.0. A copy-pasted API used > 10.0.

Shared features.py
2889.58 UGX
Skewed API (> 10 mm)
2889.58 UGX
Silent error
0.00 UGX

Both thresholds agree here, which is exactly why this bug hides until rainfall lands between 5 and 10 mm.

Load once at startup vs per request

Total serving time
1.15 s vs 31.00 s
load once: T = load + N·infer per request: T = N·(load + infer) → 27.0× faster

Explain it

Put what you saw into words. This is what the exam will ask you to do.

What is training-serving skew, how did Step 8 show it, and what architecture prevents it?

Code it

Write real code against real data. Python and SQL run right here in your browser and hidden tests check your work; the AI reviews it like an examiner.

Pythoncore

One make_features() for training and serving

Write the shared feature module that both train.py and the API import:

  • FEATURE_COLUMNS = ["rainfall_mm", "is_rainy", "month", "is_beans", "is_maize", "is_matooke"]
  • make_features(df) → a DataFrame with exactly those columns, in that order:
    • is_rainy = 1 if rainfall_mm > 5.0 else 0 (strictly greater)
    • month = month number of date
    • is_beans, is_maize, is_matooke = one-hot of commodity (0/1)

It must work on a single-row request too — that's where naive pd.get_dummies breaks, because a one-row frame only produces one dummy column.

Ctrl/⌘ + Enter to run

Challenge

Fixed variations, a new problem every day, and unlimited AI challenges built from your current settings.

Startup Model Load vs Per-Request Load Latency

Loading model.joblib from disk takes 150 ms and model.predict() takes 5 ms. For 200 requests, how many seconds are saved by loading the model once at FastAPI startup instead of inside /predict?