Project 09
A two-tower retrieval model feeding a LightGBM ranking stage on MovieLens, built to keep retrieval and ranking as genuinely separate stages in the code, the way a production system would split them into independently-scaled services, even though both run in one process here.
Retrieval and ranking stay architecturally separate on purpose, even inside one process, so the eventual split into independently-scaled services is a deployment change, not a rewrite.
A real overfitting problem, val loss bottoming out at epoch 9 then climbing back by epoch 20, was fixed with dropout and weight decay rather than papered over with best-val-loss checkpointing, and that fix made the retrieval baseline itself stronger first: Recall@10 1.4% to 3.5%, val loss now decreasing monotonically through all 20 epochs. Ranking then lifts Recall@10 further to 8.2%, a +167% relative NDCG@10 uplift from the ranking stage, on top of a retrieval baseline that had itself roughly doubled.
A ranking-invariant test asserts the ranker can only reorder retrieval's candidates, never invent a new item_id, a contract test on a non-LLM ML component in the same spirit as this portfolio's mocked-model tests elsewhere. Cold-start users, no training history, fall back to popularity-ranked items instead of crashing, verified at both the function level and through the real FastAPI endpoint. A genre-consistency sanity check, a user with 26% Sci-Fi interactions gets 6 of their top-10 recommendations tagged Sci-Fi, confirms the model learned real preference signal, not just popularity.
serving_bundle.pkl freezes features at training time, a named training-serving-skew tradeoff documented as a real production concern, not just a caveat, since a real system would refresh it on a schedule rather than once. CI trains the model fresh from scratch on every push instead of committing binary weights to git, making it a genuine regression check on the training pipeline itself, not just the serving code around it.
What I Learned
Tech Stack