Assignment Overview
In this capstone-level assignment, you will build a complete production-ready ML system. This project bridges the gap between building models in notebooks and deploying them in real-world production environments. You'll implement model interpretability, create REST APIs, containerize with Docker, and set up monitoring - the full MLOps lifecycle!
Interpretability
SHAP values, LIME explanations, feature importance, partial dependence
REST API
Flask/FastAPI endpoints, request validation, error handling
Docker
Containerization, Dockerfile, docker-compose, portability
Monitoring
Logging, metrics tracking, health checks, A/B testing concepts
The Scenario
HealthPredict Inc. - Patient Risk Assessment
You have been hired as a Machine Learning Engineer at HealthPredict Inc., a healthcare technology company. The data science team has built a diabetes prediction model, but it's stuck in a Jupyter notebook. The CTO has given you this challenge:
"We have a great model with 85% accuracy, but doctors don't trust black-box predictions. We need to explain WHY the model makes each prediction, deploy it as an API that our hospital partners can integrate, containerize it for easy deployment, and monitor it in production. Can you take this notebook and turn it into a production system?"
Your Task
Build a complete deployment pipeline for a diabetes prediction model. Your system must provide interpretable predictions, expose a REST API, run in Docker, and include production monitoring capabilities.
The Dataset
Use the Pima Indians Diabetes dataset or create a similar synthetic dataset with the following structure:
File: diabetes.csv (Diabetes Prediction Data)
pregnancies,glucose,blood_pressure,skin_thickness,insulin,bmi,diabetes_pedigree,age,outcome
6,148,72,35,0,33.6,0.627,50,1
1,85,66,29,0,26.6,0.351,31,0
8,183,64,0,0,23.3,0.672,32,1
1,89,66,23,94,28.1,0.167,21,0
0,137,40,35,168,43.1,2.288,33,1
...
Columns Explained
pregnancies- Number of pregnancies (integer)glucose- Plasma glucose concentration (integer)blood_pressure- Diastolic blood pressure mm Hg (integer)skin_thickness- Triceps skin fold thickness mm (integer)
insulin- 2-Hour serum insulin mu U/ml (integer)bmi- Body mass index (float)diabetes_pedigree- Diabetes pedigree function (float)age- Age in years (integer)outcome- Target: 0 = No diabetes, 1 = Diabetes (binary)
Requirements
Your project must include ALL of the following components. Each component is mandatory and will be tested individually.
Model Training Notebook
Create model_training.ipynb that:
- Loads and preprocesses the diabetes dataset
- Trains a classification model (Random Forest, XGBoost, or similar)
- Evaluates with accuracy, precision, recall, F1, and ROC-AUC
- Saves the trained model using
joblib
# model_training.ipynb
import joblib
from sklearn.ensemble import RandomForestClassifier
# Train model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# Save model
joblib.dump(model, 'models/diabetes_model.joblib')
joblib.dump(scaler, 'models/scaler.joblib')
Model Interpretability Notebook
Create interpretability.ipynb that:
- Computes feature importance from tree-based models
- Generates SHAP summary plots (global and local)
- Creates LIME explanations for individual predictions
- Plots partial dependence (PDP) and ICE curves
- Saves all visualizations as PNG files
# interpretability.ipynb
import shap
import lime
from lime.lime_tabular import LimeTabularExplainer
# SHAP
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)
shap.summary_plot(shap_values, X_test, show=False)
plt.savefig('visualizations/shap_summary.png')
# LIME
lime_explainer = LimeTabularExplainer(X_train, feature_names=feature_names)
exp = lime_explainer.explain_instance(X_test[0], model.predict_proba)
exp.save_to_file('visualizations/lime_explanation.html')
Flask/FastAPI REST API
Create app.py that implements:
GET /health- Health check endpointPOST /predict- Single prediction with probabilityPOST /predict/batch- Batch predictionsPOST /explain- Prediction with SHAP explanation- Input validation using Pydantic (FastAPI) or marshmallow (Flask)
- Proper error handling with meaningful messages
# app.py (FastAPI example)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import joblib
app = FastAPI(title="Diabetes Prediction API")
class PatientData(BaseModel):
pregnancies: int
glucose: float
blood_pressure: float
skin_thickness: float
insulin: float
bmi: float
diabetes_pedigree: float
age: int
@app.get("/health")
def health_check():
return {"status": "healthy", "model_loaded": True}
@app.post("/predict")
def predict(patient: PatientData):
# Load model, make prediction, return result
pass
@app.post("/explain")
def explain(patient: PatientData):
# Return prediction with SHAP values
pass
Docker Containerization
Create Dockerfile and docker-compose.yml that:
- Uses Python 3.9+ slim base image
- Installs all dependencies from
requirements.txt - Copies model files and application code
- Exposes port 8000 for the API
- Runs the API server on container start
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
# docker-compose.yml
version: '3.8'
services:
diabetes-api:
build: .
ports:
- "8000:8000"
volumes:
- ./logs:/app/logs
environment:
- LOG_LEVEL=INFO
Logging & Monitoring
Create monitoring.py that:
- Implements structured logging with timestamps
- Logs all API requests with input features
- Logs predictions and response times
- Tracks prediction distribution over time
- Saves logs to file and optionally to console
# monitoring.py
import logging
import time
from functools import wraps
logging.basicConfig(
filename='logs/predictions.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def log_prediction(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
duration = time.time() - start_time
logging.info(f"Prediction: {result}, Duration: {duration:.4f}s")
return result
return wrapper
API Testing Script
Create test_api.py that:
- Tests all API endpoints
- Validates response formats and status codes
- Tests error handling with invalid inputs
- Includes at least 10 test cases
# test_api.py
import requests
import pytest
BASE_URL = "http://localhost:8000"
def test_health_endpoint():
response = requests.get(f"{BASE_URL}/health")
assert response.status_code == 200
assert response.json()["status"] == "healthy"
def test_predict_valid_input():
patient_data = {
"pregnancies": 6, "glucose": 148, "blood_pressure": 72,
"skin_thickness": 35, "insulin": 0, "bmi": 33.6,
"diabetes_pedigree": 0.627, "age": 50
}
response = requests.post(f"{BASE_URL}/predict", json=patient_data)
assert response.status_code == 200
assert "prediction" in response.json()
assert "probability" in response.json()
Documentation
Create comprehensive README.md that includes:
- Project overview and architecture diagram
- Installation instructions (local and Docker)
- API documentation with example requests/responses
- Model performance metrics
- Interpretability explanation for non-technical stakeholders
- Future improvements and scaling considerations
Submission
Create a public GitHub repository with the exact name shown below:
Required Repository Name
diabetes-prediction-deployment
Required Files
diabetes-prediction-deployment/
├── app.py # Flask/FastAPI REST API
├── model_training.ipynb # Model training notebook
├── interpretability.ipynb # SHAP, LIME, PDP analysis
├── monitoring.py # Logging and monitoring utilities
├── test_api.py # API test cases
├── requirements.txt # Python dependencies
├── Dockerfile # Docker configuration
├── docker-compose.yml # Docker Compose configuration
├── diabetes.csv # Dataset
├── models/
│ ├── diabetes_model.joblib # Trained model
│ └── scaler.joblib # Fitted scaler
├── visualizations/
│ ├── shap_summary.png # SHAP summary plot
│ ├── shap_waterfall.png # SHAP waterfall (local)
│ ├── lime_explanation.html # LIME explanation
│ ├── feature_importance.png # Feature importance bar chart
│ └── pdp_plots.png # Partial dependence plots
├── logs/
│ └── predictions.log # Sample prediction logs
└── README.md # REQUIRED - comprehensive docs
README.md Must Include:
- Your full name and submission date
- Architecture diagram showing system components
- API documentation with curl/Python examples
- Model performance metrics (accuracy, F1, ROC-AUC)
- Docker run instructions
- Interpretability insights for stakeholders
Do Include
- All API endpoints working and tested
- Docker container runs without errors
- SHAP and LIME visualizations
- Comprehensive logging implementation
- At least 10 API test cases passing
- Clear, professional README
Do Not Include
- Hardcoded absolute paths
- API keys or credentials in code
- Large model files (use joblib compression)
- Virtual environment folders
- __pycache__ or .pyc files
- Incomplete or broken Docker setup
Enter your GitHub username - we'll verify your repository automatically
Grading Rubric
Your assignment will be graded on the following criteria:
| Criteria | Points | Description |
|---|---|---|
| Model Training & Performance | 30 | Model achieves ≥80% accuracy, proper preprocessing, saved correctly |
| Interpretability (SHAP/LIME) | 50 | SHAP summary & waterfall, LIME explanations, PDP/ICE plots |
| REST API Implementation | 50 | All endpoints working, input validation, error handling, /explain endpoint |
| Docker Containerization | 40 | Dockerfile correct, container runs, docker-compose works |
| Logging & Monitoring | 30 | Structured logging, request/response tracking, log files generated |
| Testing | 25 | At least 10 test cases, all passing, covers edge cases |
| Documentation & Code Quality | 25 | Comprehensive README, clean code, proper structure |
| Total | 250 |
Ready to Submit?
Make sure you have completed all requirements and reviewed the grading rubric above.
Submit Your AssignmentWhat You Will Practice
Model Interpretability
SHAP values for global/local explanations, LIME for instance-level interpretability, PDP/ICE plots
API Development
Building REST APIs with Flask/FastAPI, input validation, error handling, documentation
Docker & Containers
Containerizing ML applications, Dockerfile best practices, docker-compose orchestration
Production MLOps
Logging, monitoring, testing, and deploying ML models in production environments
Pro Tips
SHAP Best Practices
- Use TreeExplainer for tree-based models (faster)
- Limit background data for KernelExplainer
- Save SHAP values for later use
- Create force plots for individual explanations
API Security
- Validate all input data strictly
- Don't expose internal error details
- Rate limit in production
- Use environment variables for config
Docker Optimization
- Use multi-stage builds for smaller images
- Cache pip install layer efficiently
- Don't copy unnecessary files (.dockerignore)
- Use slim/alpine base images when possible
Common Pitfalls
- Forgetting to include model files in Docker
- Not handling missing values in API input
- SHAP explainer not matching model type
- Logs not persisted outside container