all projects

2026

Drift-Aware Medical AI

An agentic system that detects, explains, and mitigates model drift in chest X-ray classification — keeping medical AI reliable after deployment.

  • Agentic AI
  • Medical Imaging
  • PyTorch
  • FastAPI
  • Kafka
  • Drift Detection
View source

Problem

Medical imaging models degrade silently. A classifier that performs well at release can drift as scanners, populations, and acquisition protocols change — and in healthcare, silent failure is the most dangerous kind.

This is built and evaluated as a monitoring pipeline for an ML operations team, not a clinical decision-support tool. It treats drift as a first-class engineering problem: detect it early without new labels, trace it to a likely cause, explain it in plain English, and recommend a response.

Approach

A chest X-ray classifier is trained once on CheXpert, then monitored against a cross-source drift stream from NIH ChestX-ray14 using nine unsupervised two-sample drift tests — MMD, energy distance, Wasserstein, PSI, BBSD, C2ST, entropy, trainable MMD, and UMAP+JSD — run on pixels, embeddings, and predictions, with a streaming ensemble that votes across a rolling window.

`orchestrator.py` is the always-on agent: for each incoming batch it chains Detect → Analyze → Explain → Recommend end to end without a human driving each step. The Explanation Agent produces a rule-based and an LLM-generated (Phi-3) report; the Recommendation Agent picks from a fixed catalogue of responses — recalibrate, update a threshold, or flag a slice for retraining or targeted triage.

Root-cause attribution ranks metadata and image-level candidates by effect size to identify what actually drove a shift, validated live by injecting a known corruption and confirming the agent recovers it as the top driver.

Results

The best single detector (Wasserstein / C2ST) reaches AUROC ≈0.91; the 4-detector ensemble does not beat the best single detector in any of 16 tested conditions — an honest negative result, reported as such rather than hidden.

Streaming detection holds AUROC 0.989 at a mean latency of 6.6ms per batch (p95 11.1ms) under genuinely incremental arrival, not offline batching. Cross-dataset generalisation drops from 0.877 (CheXpert) to 0.841 (NIH) macro AUROC on five shared diseases.

Per-disease temperature scaling meaningfully outperforms a single global temperature, which barely moves calibration error (0.1094 → 0.1063) — the 14 diseases don't share one correction direction or magnitude.

What I learned

The ensemble not beating the best single detector was initially disappointing, then became the most useful result in the write-up — an honest negative finding, with the failure mode documented in an ethics/risk log, is worth more to an ML ops team than a cherry-picked win.

Reliability work is mostly about what happens after the model ships. Building the monitoring and orchestration layer taught me more about production ML than training the classifier did.