skip to content
Brendan Desjardins

Backend / ML

UFC Fight Prediction & Analytics Platform

A live UFC prediction platform with automated data collection, model retraining, low-latency inference, and a history of predictions across real events.

The idea

This project started as a Jupyter Notebook experiment to see if I could use machine learning to predict UFC fights accurately. I’ve followed the UFC for years, so it was fun a fun problem for me to work on and build my skillset with. Once the first model showed some promise in predicting fights, I kept iterating on this project and finding things I wanted to add.

Eventually, I became more interested in everything around the model rather than just improving an accuracy number. I wanted to turn the notebook into something that could collect new data, retrain itself, serve predictions, and keep running across real UFC events without me manually holding everything together.

What I’ve built

The project has grown into a multi-service platform in Go and Python. A data pipeline scrapes upcoming fights and builds 56 features into PostgreSQL, while a neural network + XGBoost ensemble is exported to ONNX and served behind a Go inference service.

I also built an MLflow retraining pipeline with experiment tracking, a model registry, and accuracy-gated promotion. Training runs as a scheduled Cloud Run job and checks training/serving parity before a model is released. The platform has now been making and tracking predictions across live UFC events for months, which has made things like monitoring real-world accuracy and keeping old predictions around much more interesting than a normal train/test split.

Why I keep working on it

This is probably the project I’ve had the most fun building because there’s always another direction I can take it. Sometimes that’s trying a different model or feature, and other times it’s improving the backend, deployment pipeline, monitoring, or site itself.

More than anything, it’s been a good way to learn what happens in ML systems after model.fit(). I’ve found that model that works in a notebook is one thing, but keeping the data, model, API, and predictions working together over time has been a much more interesting problem.