Loading the model into your browser…

What happens to a model after training?

159,329 X-rays. One pipeline.

A DenseNet121 reads chest X-rays and shows its evidence. The real work is everything after training: tests, a quality gate that blocks worse models, drift monitoring, and a browser build checked against PyTorch before every release.

By the numbers

The project, flipped into view.

Live demo

Drag a film in. Get a second look.

Pick any of the 20 sample films, drag one into the box, or upload your own PNG or JPG. Your image never leaves your device.

Sample filmsdrag or click
Your image will appear here
    How it works

    A model is the easy part. Here's the rest.

    Train & track

    PyTorch training with patient-level splits, logged to MLflow. Weights versioned on Hugging Face and pinned by SHA-256.

    Gate before release

    CI runs tests and a quality gate: a new model can't ship if its AUROC drops against the baseline.

    Export to the browser

    CI exports the weights to ONNX and checks the output matches PyTorch and Grad-CAM before this page is published.

    Guard the input

    Colour photos, tiny images and odd shapes are flagged before anyone trusts the answer.

    Explain

    Grad-CAM shows where the evidence came from — and when the model is looking at the wrong thing.

    Serve & monitor

    The same model ships as a FastAPI Docker image with Prometheus, Grafana and drift detection for server deployments.

    Live pipeline

    Every change goes through this. Live.

    Pulled from GitHub Actions each time this page loads: the latest test run and the latest release of this site, stage by stage.

    Loading the latest runs…
    Model card

    What this model is — and isn't.

    Model
    DenseNet121 initialised from ImageNet, multi-label sigmoid head. 224 × 224 input, ImageNet normalisation. Exported to ONNX for in-browser inference; Grad-CAM baked into the graph.
    Training data
    Stanford CheXpert: 159,329 frontal and lateral radiographs after dropping uncertain labels (U-Ignore). Labels were extracted from reports by an NLP labeller, so they're noisy.
    Training
    BCE with per-class positive weights, Adam 1e-4, 10 epochs, batch 32, one Colab T4 GPU (~4.5 h). Tracked in MLflow.
    Evaluation
    Mean AUROC 0.879 on the 234-image CheXpert validation set (radiologist consensus labels).
    Atelectasis 0.818Cardiomegaly 0.855Consolidation 0.897Edema 0.906Pleural Effusion 0.919
    Intended use
    Research, education and demonstrating MLOps practice. Not a medical device; never for diagnosis or treatment decisions.
    Limitations
    Single-hospital training data, mostly adult inpatients. The checkpoint was selected on the validation set, so reported AUROC is likely optimistic. Performance drops on images from other hospitals, and Grad-CAM can highlight tubes or markers.
    Versioning
    Weights on Hugging Face, pinned by SHA-256 (7d88ee05…); the server refuses to start with any other file.
    FAQ

    Questions people ask.

    The model

    Is this a medical device?

    No. It's a research and portfolio project. It hasn't been clinically validated and must not be used for diagnosis.

    How accurate is it?

    Mean AUROC 0.879 on the 234-image CheXpert validation set. That number is optimistic because the best epoch was picked on the same set — the next version fixes this with a held-out patient split and bootstrap confidence intervals. Expect lower scores on images from other hospitals.

    What was it trained on?

    159,329 chest radiographs from Stanford's CheXpert dataset (rows with uncertain labels were dropped), using a DenseNet121 pretrained on ImageNet, 10 epochs on one Colab T4 GPU.

    What is the heatmap?

    Grad-CAM: it highlights the regions that pushed the model's score up. It shows where the evidence came from, not whether the model is right — it can latch onto tubes, markers or text.

    Your data

    Where does my image go?

    Nowhere. The model is downloaded once and runs in your browser with ONNX Runtime Web. Open your browser's network tab while you drop an image — nothing is sent.

    Why did I get an input warning?

    Chest X-rays are grayscale, reasonably large and roughly square. Colour photos, tiny thumbnails and panoramas are flagged so nobody trusts an answer the model was never trained to give.

    Engineering

    What keeps the model honest?

    CI runs unit and API tests, a quality gate that blocks releases if AUROC drops, SHA-256 pinning of the weights, and a parity check proving the browser model matches PyTorch and Grad-CAM before this page is published.

    Can I run it as a server?

    Yes — docker compose up starts a FastAPI service with Prometheus, Grafana and live drift detection. The code is on GitHub.