--- 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