pneumoops / README.md
Prakhar54-byte's picture
Deploy build-b06abeb
c966ef1 verified
|
Raw
History Blame Contribute Delete
7.12 kB
---
title: PneumoOps
emoji: 🫁
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: true
license: mit
short_description: MLOps A/B testing & drift monitoring
---
# 🫁 PneumoOps
**Continuous MLOps Pipeline with A/B Testing & Data Drift Monitoring for 14-Class Thoracic Disease Detection**
[![CI](https://github.com/Prakhar54-byte/PneumoOps/actions/workflows/deploy.yml/badge.svg)](https://github.com/Prakhar54-byte/PneumoOps/actions)
[![Python 3.11](https://img.shields.io/badge/python-3.11-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](#)
---
## What This Is
PneumoOps is a production-style MLOps system for **multi-label chest X-ray classification**. It demonstrates real-world deployment challenges:
- **A/B Testing** β€” every inference request is randomly routed to either *Model A (PyTorch)* or *Model B (ONNX)*, letting you measure real-world latency differences between serving backends.
- **Data Drift Monitoring** β€” statistical pixel-distribution comparison (KS-test) against the training baseline. When distribution shifts, the system flags `DRIFT_DETECTED` β€” the trigger for automated retraining in production.
- **Prometheus Observability** β€” request counters, latency histograms, per-disease prediction rates, and drift alert counters are all scraped at `/metrics`.
- **Dockerized Deployment** β€” the entire stack runs in containers, deployable to Hugging Face Spaces via a single `git push`.
---
## Architecture
```
Train (ChestMNIST + MobileNetV3-small)
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
Model A (.pth) Model B (.onnx)
PyTorch serving ONNX Runtime serving
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ FastAPI Backend β”‚
β”‚ β”œβ”€ A/B Router (60/40) β”‚
β”‚ β”œβ”€ Drift Monitor (KS) β”‚
β”‚ β”œβ”€ Prometheus /metricsβ”‚
β”‚ └─ /health /history β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Gradio UI β”‚
β”‚ Top-3 predictions β”‚
β”‚ Model arm used β”‚
β”‚ Latency (ms) β”‚
β”‚ Drift alert badge β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## Dataset & Model
| Property | Value |
|---|---|
| Dataset | [ChestMNIST](https://medmnist.com/) β€” 14-class multi-label chest X-ray |
| Classes | Atelectasis, Cardiomegaly, Effusion, Infiltration, Mass, Nodule, Pneumonia, Pneumothorax, Consolidation, Edema, Emphysema, Fibrosis, Pleural Thickening, Hernia |
| Model A | MobileNetV3-small (PyTorch `.pth`) |
| Model B | MobileNetV3-small (ONNX Runtime `.onnx`) |
| Training | 5 epochs, AdamW, BCEWithLogitsLoss, per-class threshold tuning |
| Macro AUROC | 0.686 (5-epoch, 5k samples β€” improves with full dataset) |
---
## Project Structure
```
pneumo_ops/
β”œβ”€β”€ backend/
β”‚ └── main.py # FastAPI: A/B routing, drift monitor, Prometheus
β”œβ”€β”€ frontend/
β”‚ └── app.py # Gradio UI: top-3 chart, drift badge, latency
β”œβ”€β”€ scripts/
β”‚ └── train_chestmnist.py # Training: ChestMNIST β†’ MobileNetV3 β†’ ONNX export
β”œβ”€β”€ models/
β”‚ └── chestmnist_mobilenetv3/
β”‚ β”œβ”€β”€ mobilenetv3_chestmnist.pth # Model A (PyTorch)
β”‚ β”œβ”€β”€ mobilenetv3_chestmnist.onnx # Model B (ONNX)
β”‚ β”œβ”€β”€ training_metrics.json
β”‚ └── baseline_stats.json # Pixel stats for drift reference
β”œβ”€β”€ model_utils.py # CalibratedModel + temperature scaling util
β”œβ”€β”€ Dockerfile # Single-container build
β”œβ”€β”€ docker-compose.yml # backend + frontend services
β”œβ”€β”€ requirements.txt
└── .github/workflows/
└── deploy.yml # CI (lint/import check) + HF Spaces deploy
```
---
## Quick Start
### 1. Install
```bash
git clone https://github.com/Prakhar54-byte/PneumoOps
cd pneumo_ops
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
```
### 2. Train the model
```bash
# Quick run (5k samples, ~1 min on GPU)
python3 scripts/train_chestmnist.py --epochs 5 --batch-size 32 --max-train-samples 5000
# Full dataset
python3 scripts/train_chestmnist.py --epochs 15 --batch-size 64
```
Outputs saved to `models/chestmnist_mobilenetv3/`:
- `mobilenetv3_chestmnist.pth` β€” PyTorch checkpoint
- `mobilenetv3_chestmnist.onnx` β€” ONNX export
- `training_metrics.json` β€” AUROC, AUPRC, F1, thresholds
- `baseline_stats.json` β€” pixel reference for drift detection
### 3. Run the backend
```bash
PNEUMOOPS_PROFILE=chestmnist python3 -m uvicorn backend.main:app --port 7860
```
Key endpoints:
| Endpoint | Description |
|---|---|
| `POST /predict` | Run inference (A/B routed) |
| `GET /health` | System status + model metadata |
| `GET /metrics` | Prometheus scrape endpoint |
| `GET /history` | Last 20 requests |
| `GET /metrics/class-rates` | Per-class prediction rates |
| `GET /metrics/calibration` | AUROC / AUPRC / Brier per class |
### 4. Run the UI
```bash
BACKEND_PREDICT_URL=http://127.0.0.1:7860/predict python3 frontend/app.py
```
### 5. Docker (full stack)
```bash
docker compose up --build
# Backend β†’ http://localhost:7860
# Frontend β†’ http://localhost:7861
```
---
## Deployment β€” Hugging Face Spaces
### Manual push
```bash
# Add HF remote
git remote add space https://huggingface.co/spaces/Prakhar54-byte/PneumoOps
# Push (Spaces will build the Docker image automatically)
git push space main
```
### Automated (GitHub Actions)
Set these repository secrets on GitHub:
| Secret | Description |
|---|---|
| `HF_TOKEN` | Hugging Face access token (write permission) |
| `HF_SPACE_REPO` | e.g. `your-username/pneumoops` |
| `HF_MODEL_REPO` | *(optional)* e.g. `your-username/pneumoops-models` |
Every push to `main` triggers CI checks then deploys to your Space automatically.
---
## Real-World MLOps Challenges Addressed
| Challenge | Solution |
|---|---|
| Model degradation over time | Drift Monitor (KS-test on pixel distribution) |
| Serving latency variance | A/B routing between PyTorch and ONNX, latency tracked per arm |
| Class imbalance (rare diseases) | Per-class threshold tuning on val set + AUPRC tracking |
| Missed diagnoses | Per-class recall monitored at `/metrics/class-rates` |
| Production observability | Prometheus metrics β€” latency histograms, per-disease counters, drift alerts |
| Automated retraining signals | `DRIFT_DETECTED` flag logged + exposed via Prometheus counter |
---
## Libraries
`PyTorch` Β· `ONNX Runtime` Β· `FastAPI` Β· `Gradio` Β· `Docker` Β· `Hugging Face Hub/Spaces` Β· `scikit-learn` Β· `Prometheus` Β· `MedMNIST` Β· `SciPy`
---
## License
MIT