Production-style customer churn prediction system with reproducible training, experiment tracking, model registration, and a FastAPI inference service.
Most ML portfolio projects stop at a notebook and a model score. This repository demonstrates the engineering work needed to operationalize a model:
- configuration-driven data ingestion and validation
- reusable preprocessing and training pipelines
- candidate model comparison with explicit champion selection
- MLflow experiment tracking and model registry integration
- artifact persistence for downstream serving
- FastAPI inference layer with typed contracts
- Docker packaging for local deployment
- automated tests and GitHub Actions CI
The use case is intentionally simple so the focus stays on production-minded ML engineering instead of model novelty.
flowchart LR
A["CSV Dataset"] --> B["Data Ingestion<br/>schema validation"]
B --> C["Preprocessing<br/>imputation + scaling + encoding"]
C --> D["Model Selection<br/>logistic regression vs random forest"]
D --> E["Evaluation<br/>classification metrics"]
D --> F["MLflow Tracking<br/>params, metrics, artifacts"]
F --> G["Model Registry<br/>champion version"]
D --> H["Local Artifact Store<br/>joblib + metadata"]
H --> I["FastAPI Service<br/>/health, /predict"]
I --> J["Docker Container"]
K["GitHub Actions"] --> L["pytest"]
- Configurable dataset path, feature schema, artifact locations, and MLflow settings
- Basic raw-data validation before any training begins
- Reusable
ColumnTransformerpipeline for numeric and categorical features - Candidate model evaluation using consistent metrics and holdout data
- Champion model selection based on
roc_aucwith explicit local artifact persistence - MLflow tracking for runs, metrics, feature schema, and serialized model artifacts
- Model registration flow that tags the selected model version and attempts to assign a
championalias - FastAPI service with Pydantic request and response models
- CI workflow that installs dependencies and runs the test suite on pushes and pull requests
MLFlowOps Pipeline/
├── .github/
│ └── workflows/
│ └── ci.yml
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── schemas.py
│ └── service.py
├── artifacts/
│ ├── .gitkeep
│ ├── models/
│ │ └── .gitkeep
│ └── reports/
│ └── .gitkeep
├── configs/
│ └── training_config.json
├── data/
│ └── customer_churn_sample.csv
├── src/
│ ├── __init__.py
│ ├── config.py
│ ├── exceptions.py
│ ├── logger.py
│ ├── train.py
│ ├── utils.py
│ └── pipeline/
│ ├── __init__.py
│ ├── data_ingestion.py
│ ├── evaluation.py
│ ├── model_registry.py
│ ├── preprocessing.py
│ └── training.py
├── tests/
│ ├── helpers.py
│ ├── test_api.py
│ ├── test_data_ingestion.py
│ ├── test_preprocessing.py
│ └── test_training.py
├── .gitignore
├── Dockerfile
├── README.md
└── requirements.txt
python -m venv .venv
source .venv/bin/activateOn Windows PowerShell:
.venv\Scripts\Activate.ps1pip install --upgrade pip
pip install -r requirements.txtThe repository includes a lightweight sample dataset so the full workflow is runnable without external downloads.
python -m src.train --config configs/training_config.jsonTraining will:
- validate the input dataset
- split the data into train and test sets
- evaluate logistic regression and random forest baselines
- log each candidate run to MLflow
- persist the champion model to
artifacts/models/ - save a local metrics summary to
artifacts/reports/metrics.json - register the best model in MLflow using the configured model name
The training configuration points to a local MLflow file store under artifacts/mlflow_tracking. To inspect runs and the model registry in the UI, start MLflow against the same backend store:
mlflow ui \
--backend-store-uri file:./artifacts/mlflow_tracking \
--host 0.0.0.0 \
--port 5000Then open http://127.0.0.1:5000.
Train the model first so the API has a local artifact to load:
python -m src.train --config configs/training_config.json
uvicorn app.main:app --reloadAvailable endpoints:
GET /healthPOST /predict
curl -X POST "http://127.0.0.1:8000/predict" \
-H "Content-Type: application/json" \
-d '{
"age": 34,
"tenure_months": 8,
"monthly_charges": 92.5,
"contract_type": "Month-to-month",
"payment_method": "Electronic check",
"internet_service": "Fiber optic",
"support_tickets": 4,
"paperless_billing": "Yes"
}'Expected response shape:
{
"churn_probability": 0.84,
"predicted_label": "churn",
"model_name": "random_forest",
"model_version": "3"
}Build the API image:
docker build -t mlflowops-pipeline .Run the container:
docker run --rm -p 8000:8000 \
-v $(pwd)/artifacts:/app/artifacts \
mlflowops-pipelineIf you have not trained the model yet, run the training command locally first so the mounted artifacts/ directory contains the model artifact and metadata.
The GitHub Actions workflow is intentionally simple and realistic:
- checks out the repository
- installs Python dependencies
- runs the test suite with
pytest
This is a practical baseline for an ML project portfolio repo and leaves room for future extensions such as container image publishing or deployment promotion.
- Why a preprocessing pipeline is serialized together with the estimator
- Why experiment tracking matters even for baseline models
- How the champion model is selected and persisted for serving
- Why the API depends on artifact metadata in addition to the model binary
- How CI enforces repeatability and prevents regressions in utility code
- Add data and concept drift monitoring with scheduled batch evaluation against recent production samples.
- Introduce a feature store or offline feature contract to support both training and batch scoring from the same schema source.
- Extend CI/CD to build and publish the Docker image, then promote registered models to deployment environments based on approval gates.