Skip to content

Repository files navigation

MIRROR

Multimodal Intelligent Radiology Reasoning and Observation Reporter

An explainable medical-AI system that reads radiological images, localizes its own evidence, and writes a clinician-style draft report. Completed as part of the Global Indian Scientists & Technocrats (GIST) 2026 Summer Internship Program.

Mentored by Mr. Sriram Venkatapathy (AI Research at Capital One, PhD-CS at IIT Hyderabad)

SSRN Preprint: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=7245078

Live Demo: https://mirror-ten-jet.vercel.app/


Tech Stack

AI / ML & Frameworks:

Backend:

Frontend:

Data & Tooling:

Paper & Writing:

What MIRROR does

Most medical-imaging models stop at a prediction. MIRROR adds the two layers that make a prediction trustworthy and usable: it shows where the evidence is and explains what it means in plain clinical language.

It analyzes a radiological study across three modalities (chest X-ray, brain MRI, and head CT), identifies potential abnormalities from that modality's finding taxonomy, highlights the diagnostic evidence with saliency overlays, and generates a structured natural-language report in the right clinical vocabulary.

Image → Prediction → Evidence Localization → Clinical Reasoning → Human-Readable Report

Research question

Can multimodal AI systems that combine image classification, visual explainability, and language generation improve interpretability and user trust in medical image analysis compared to classification-only approaches?

The repo is built to measure this: predictive metrics (AUROC/F1) and explanation metrics (pointing game / localization IoU) live side by side in evaluation/.

Why it's different (novelty)

While most medical-imaging systems focus solely on disease classification, MIRROR integrates three complementary layers into one framework:

  1. Radiological image understanding: a CNN/ViT classifier.
  2. Visual evidence localization: Grad-CAM / Score-CAM saliency.
  3. Natural-language clinical report generation: an LLM (or offline template) that reasons only over the structured evidence above.

The result not only predicts abnormalities but communicates why the prediction was made and how it relates to potential clinical findings; every finding it reports traces back to a probability and a saliency region (the descriptive prose around each finding is model-generated and not pixel-verified).

System architecture

MIRROR turns a single radiograph into a reviewable diagnostic draft by chaining three complementary layers, where each layer's output becomes the grounded input to the next, so the final report can always be traced back to a probability and a specific image region.

Architecture

Layer Module Does Produces
1 · Classification models/classification/ A CNN/ViT backbone (DenseNet121 · EfficientNet-B0 · ViT-B/16) with a multi-label head sized to the study's modality Per-label probabilities
2 · Evidence localization models/explainability/ Grad-CAM / Score-CAM hooks the target layer for each positive label Heatmap + region (centroid, bbox)
3 · Clinical reasoning models/report_generation/ An LLM (or an offline template) prompts over the structured evidence only, never the pixels FINDINGS / IMPRESSION report

The pipeline is modality-agnostic; a single registry (models/common/modalities.py) supplies the finding taxonomy, the anatomical vocabulary, and the report phrasing for each modality:

Modality Findings Grounded in Location vocabulary
Chest X-ray 14 NIH ChestX-ray14 lung zones (frontal)
Brain MRI 11 Brain Tumor MRI Dataset + routine neuro findings lobar regions (axial)
Head CT 11 RSNA Intracranial Hemorrhage + routine acute-CT findings lobar regions (axial)

Modality is chosen in the UI (or via --modality), or auto-detected from a DICOM Modality tag with --modality auto (MR→brain MRI, CT→head CT, CR/DX→chest).

models/pipeline.py orchestrates the four stages into one AnalysisResult. The two later layers are individually toggleable, which is exactly what recovers the ablation conditions the research question names (classification-only → +localization → full MIRROR) and lets the evaluation harnesses show added interpretability at no predictive cost.

Two interchangeable serving engines satisfy the same response contract, so the UI is identical in both:

  • Local full stack: FastAPI (backend/) wraps the real PyTorch pipeline; the frontend points at it via NEXT_PUBLIC_API_URL. Every input type (PNG/JPEG/BMP/WEBP + DICOM) and rendered Grad-CAM overlays.
  • Hosted on Vercel: a Next.js serverless route (frontend/app/api/analyze/route.ts) uses Claude's vision model as a drop-in engine (the PyTorch pipeline can't fit serverless), returning the same JSON with a bounding box per finding.

For the full write-up (per-layer module breakdowns, the grounding rationale, and the deployment topology table), see docs/architecture.md.

Live demo (v1.1.0)

The hosted build at mirror-ten-jet.vercel.app runs the full pipeline in the browser via a Next.js serverless route backed by Claude vision (claude-haiku-4-5): upload a study, score the modality's finding taxonomy, draw a bounding box per positive finding, and draft a grounded FINDINGS / IMPRESSION report.

Study input and predictions

A full annotated walkthrough (evidence overlays and the draft report on a real session) is in docs/deployment-showcase.md.

Quickstart

Run the full pipeline on a bundled sample with zero downloads (ImageNet weights, offline report backend, works anywhere):

git clone https://github.com/vignesh-nagarajan-vn/MIRROR.git && cd MIRROR
python -m venv .venv && source .venv/Scripts/activate   # macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
python -m demo.run_demo datasets/samples/chestxray14/images/synth_0001.png
# other modalities (or --modality auto to route a DICOM by its Modality tag):
python -m demo.run_demo datasets/samples/brain_mri/images/mri_0001.png --modality "brain MRI"
python -m demo.run_demo datasets/samples/head_ct/images/ct_0000.dcm --modality auto

This prints predictions and a draft report and writes Grad-CAM overlays to demo/assets/. Inputs may be PNG/JPEG/BMP/WEBP or DICOM (.dcm); on ImageNet weights the predictions are structurally valid but not diagnostic.

  • Full local stack (FastAPI backend + Next.js reading-room UI): docs/setup.md.
  • Deploy a live public site on Vercel, powered by Claude vision with no backend to host: docs/deployment.md.
  • Richer prose reports (optional): set ANTHROPIC_API_KEY and report.provider: anthropic in configs/default.yaml; it falls back to the offline template if the key is missing.

Repository layout

mirror/
├── frontend/                     # Next.js "reading-room" UI
│   ├── app/
│   │   ├── page.tsx              # the single-page reading room
│   │   ├── layout.tsx           # root layout + fonts
│   │   └── api/analyze/route.ts  # serverless analyze route (Vercel, Claude vision)
│   ├── components/               # UploadPanel · FilmViewer · FindingsList · ReportPanel
│   ├── lib/api.ts                # typed client + response contract
│   ├── styles/globals.css        # reading-room theme
│   ├── vercel.json               # Vercel build/function config
│   └── .env.local.example        # NEXT_PUBLIC_API_URL + ANTHROPIC_API_KEY
├── backend/                      # FastAPI service (lazy-loads the pipeline)
│   └── app/
│       ├── api/routes.py        # /api/analyze · /api/health · /api/labels
│       ├── core/config.py       # settings (upload limits, version)
│       ├── services/            # pipeline_service (singleton, lazy load)
│       ├── schemas/             # Pydantic request/response models
│       └── main.py              # app factory + CORS
├── models/                       # the three layers + orchestration
│   ├── classification/          # DenseNet121 / EfficientNet / ViT: model, dataset, train, infer
│   ├── explainability/          # Grad-CAM, Score-CAM, explainer, overlay rendering
│   ├── report_generation/       # LLM (Claude) + offline-template generator, prompts
│   ├── common/                  # constants, config, preprocessing (DICOM ingest)
│   └── pipeline.py              # Image → Prediction → Evidence → Report
├── evaluation/                   # AUROC/F1, localization IoU, ablation, multi-seed
│   ├── evaluate.py              # predictive quality + bootstrap CIs
│   ├── evaluate_localization.py # pointing game / IoU vs. NIH boxes
│   ├── ablation.py              # classification-only vs. +localization vs. full
│   ├── aggregate_seeds.py       # mean ± std across training seeds
│   └── metrics.py · repro.py    # metric defs + reproducibility stamping
├── results/                      # committed example outputs (see results/README.md)
│   ├── output_sheets/           # per-image prediction CSV + structured findings JSON
│   └── evaluation/              # eval / localization / ablation / aggregate snapshots
├── datasets/                     # dataset docs + prep scripts (+ tiny synthetic sample sets)
│   └── samples/                 # committed synthetic studies (one DICOM each):
│       ├── chestxray14/         #   24 chest studies (NIH layout)
│       ├── brain_mri/           #   12 brain-MRI studies (Modality=MR)
│       └── head_ct/             #   12 head-CT studies (Modality=CT)
├── notebooks/                    # data exploration + pipeline walkthrough
├── tests/                        # torch-free unit tests (metrics, ablation, repro, …)
├── docs/                         # architecture · setup · deployment · API reference
│   └── images/architecture.svg  # the system diagram
├── paper/                        # LaTeX draft (main.tex + figures/) + build notes
├── demo/                         # CLI demo (run_demo.py) + generated assets/
├── configs/default.yaml          # single source of tunables (backbone, CAM, report backend)
├── docker-compose.yml            # backend :8000 + frontend :3000
├── Makefile · requirements.txt
└── README.md

Datasets

MIRROR is multi-modality; each modality maps to a public benchmark:

Modality Primary dataset Taxonomy
Chest X-ray NIH ChestX-ray14 (112,120 images) 14 disease categories
Brain MRI Brain Tumor MRI Dataset (+ routine neuro findings) 11 findings
Head CT RSNA Intracranial Hemorrhage (+ routine acute-CT findings) 11 findings

Other secondary sources: RSNA Pneumonia Detection Challenge, MIMIC-CXR (images

  • reports), COVID-19 Radiography Database.

None are redistributed here. Tiny synthetic stand-ins ship under datasets/samples/ (chestxray14/, brain_mri/, and head_ct/, each with one DICOM carrying the correct Modality tag), so the demo, the DICOM auto-routing, loaders, and smoke tests run with zero downloads. See datasets/README.md for the expected layout, the NIH downloader (download_chestxray14.py), licensing notes, and the sample generators (make_synthetic_samples.py, make_synthetic_neuro_samples.py).

Configuration

Everything tunable lives in configs/default.yaml: swap the backbone, switch Grad-CAM ↔ Score-CAM, or change the report backend without touching code:

model:   { backbone: densenet121 }      # or efficientnet_b0 / vit_b_16
explain: { method: gradcam }            # or scorecam
report:  { provider: template }         # or anthropic (needs ANTHROPIC_API_KEY)

Train & evaluate

# Train (requires ChestX-ray14 locally)
python -m models.classification.train --config configs/default.yaml

# Evaluate prediction quality → evaluation/results/. Reports AUROC + AUPRC,
# sensitivity/specificity/PPV/NPV at the operating point, and calibration
# (Brier, ECE), all with bootstrap 95% CIs. Use --modality for brain MRI / CT.
python -m evaluation.evaluate --config configs/default.yaml \
    --checkpoint models/checkpoints/densenet121_best.pt --modality "chest X-ray"

# Evaluate explanation quality (pointing game / localization IoU) against the
# NIH ground-truth boxes (BBox_List_2017.csv) → JSON in evaluation/results/
python -m evaluation.evaluate_localization --config configs/default.yaml \
    --checkpoint models/checkpoints/densenet121_best.pt

# Ablation: classification-only baseline vs. +localization vs. full MIRROR.
# Folds the JSON above into one comparison table + a latency profile.
python -m evaluation.ablation --config configs/default.yaml \
    --prediction-results evaluation/results/eval_densenet121.json \
    --localization-results evaluation/results/loc_densenet121_gradcam.json

# Robustness across training seeds: train with --seed {0,1,2}, evaluate each,
# then aggregate to mean ± std → evaluation/results/aggregate_<backbone>.json
python -m evaluation.aggregate_seeds evaluation/results/eval_seed*.json

The harnesses answer the project's two questions side by side. evaluate.py scores what the model predicts, a clinical-grade panel of per-label and macro AUROC/AUPRC, macro F1, operating-point sensitivity / specificity / PPV / NPV, and calibration (Brier, ECE), all with bootstrap 95% CIs. evaluate_localization.py scores whether the highlighted evidence is in the right place against the ~984 NIH lesion boxes (pointing game, IoU). ablation.py builds the baseline comparison the research question names (classification-only vs. +localization vs. full MIRROR); because layers 2-3 are post-hoc, the predictive column is identical across rows, so interpretability is added at no predictive cost. evaluation/results/ is git-ignored; the committed snapshot in results/ holds the real measured results the paper reports (results/chestmnist/, results/synthetic_validation/) plus format-only illustrative examples. Details: evaluation/README.md.

Paper

The paper lives in paper/ (source paper/main.tex, compiled PDFs in paper/pdf-drafts/) and is preprinted on SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=7245078

Status: live on SSRN as a preprint (abstract 7245078), submitted August 6, 2026 and posted under a CC BY-NC-ND license. The paper first went through a medRxiv (Radiology) cycle: screening asked for author details and institutional affiliation clarified (addressed in v7 with a single-author title page), and medRxiv ultimately declined the work as a technical development rather than biomedical research, so it moved to SSRN. The v8 revision, the version submitted, restores the v6 two-author title block: the corresponding author (Texas A&M University) and the research mentor alongside with his qualifiers (Applied AI Researcher at Capital One, PhD in Computer Science from IIT Hyderabad), with the GIST 2026 Summer Research Internship affiliation on one line beneath both blocks. The paper remains complete and all-measured: every number is a real result from this repo's code, with no placeholder or pending values. LaTeX source: paper/main.tex. Compiled PDF snapshots (newest last) are in paper/pdf-drafts/, with v8 the current submission version (see the version table there).

Measured highlights: DenseNet-121 reaches macro AUROC 0.729 (95% CI [0.718, 0.738]) on ChestMNIST with a clinically sensible per-label ordering; the ablation verifies the interpretability layers are strictly post-hoc (maximum probability change 0), so they add no predictive cost, only a bounded ~40 ms Grad-CAM pass; and a synthetic control (0.917 vs 0.557 AUROC on signal vs no-signal labels) confirms the metrics measure real discrimination. Framed honestly for a clinical readership: ChestMNIST is a downsampled, reduced-budget systems demonstration, not a diagnostic benchmark; grounding is finding-level (the descriptive prose is not pixel-verified); and quantitative localization against the NIH boxes is future work.

See paper/README.md for the section map, build steps (Overleaf or pdflatex main), and how the result tables regenerate from the evaluation harnesses.

Documentation

Safety, ethics, and limitations

  • Not for clinical use. Outputs are drafts for research into explainability and trust; they require clinician verification.
  • No PHI in version control. Raw images, weights, and results are git-ignored.
  • Grounded by design. The language layer never sees pixels, only structured evidence, so it cannot invent findings the classifier didn't produce.
  • Honest about uncertainty. Predictions are probabilities; below-threshold findings are reported as pertinent negatives, not silently dropped.

License

MIT. See LICENSE, including the research-use medical disclaimer.

About

Explainable radiology AI that reads chest X-ray, brain MRI, and head CT scans, then chains classification, evidence localization, and language generation into a traceable clinician-style report.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages