★ Featured · Fall 2025 – Oct 2026 · Georgia Institute of Technology
FundusVision — Retinal Disease Screening
Team lead · CS 7641 Machine Learning
Roughly 40 million people are blind and half or more of those cases were preventable with early detection; diabetic retinopathy, glaucoma and macular degeneration all leave visible traces on the retina long before symptoms. A fundus camera is cheap and fast, but the specialist who reads the photograph is neither. FundusVision started as a CS 7641 team project asking how far standard deep learning gets on two parts of that reading task: deciding whether an eye needs a specialist at all, and tracing the retinal vessels whose shape carries much of the diagnostic signal.
The system is two PyTorch models behind one command-line package. A ResNet34 pretrained on ImageNet is fine-tuned on 6,392 fundus photographs from the ODIR-5K dataset to output a single Normal-vs-Abnormal screening score, with the decision threshold chosen on validation data for balanced sensitivity and specificity. A 31-million-parameter U-Net trained from scratch labels every pixel of a photograph as vessel or background. Both train in minutes on an Apple-silicon GPU and are exported to ONNX so the demo on this page runs entirely in your browser.
The most important finding was not a model but an evaluation bug. ODIR-5K lists both eyes of a patient on one row, and the team's first pipeline looped over both, duplicating every image roughly twice and then splitting the rows at random, so about half of the "test" images had also been trained on. That version reported 84% accuracy and 0.91 AUC. When I rebuilt the pipeline in October 2026 I deduplicated to one row per physical eye, labelled each eye from its own diagnostic keywords, and split by patient with a grouped stratified fold so no patient straddles train and test. The honest ROC AUC is 0.82, and the repository now asserts the absence of leakage before any training run.
Rebuilding the segmentation model exposed a second lesson in the opposite direction. Two textbook additions, random flips and cosine learning-rate decay, dropped test Dice from 0.82 to 0.65; a five-run ablation isolated the flips as the cause. With only 480 training images, a from-scratch U-Net converges far faster when it can rely on the fixed geometry of a fundus photograph, so the shipped recipe is the plain one and both options stay available as flags. The final model scores Dice 0.82 and IoU 0.69 on 200 held-out images, reproducing the course result from code anyone can run.
The engineering around the models is what makes the numbers trustworthy: a hexagonal `fundusvision` package with data, model, training and evaluation layers; a synthetic-data test suite that exercises the full train-evaluate-explain path on CPU in under ten seconds and runs in GitHub Actions; model cards that record every run's config, history and metrics; Grad-CAM for the classifier; and int8 ONNX exports that lose less than 0.005 AUC or Dice while shrinking the weights to 61 MB. The 1.6 GB of images that had been committed to git were purged from history, so a clone now takes a second.
What I would do next, in order of expected payoff: train the U-Net on 512-pixel patches, since at 224 pixels the capillaries are one to three pixels wide and dominate the error; move the classifier to a per-disease multi-label head at higher input resolution; and validate both models on a second dataset such as Messidor or EyePACS, because ODIR-5K comes from a handful of hospitals and one camera family.
Architecture
Results




Live demo
Loading demo…
Key Contributions
- Found and fixed train/test leakage in the team's original pipeline (duplicated images, row-level split); replaced it with per-eye labels and a patient-grouped, class-stratified split guarded by leakage assertions
- Rebuilt the project as an installable PyTorch package with a CLI for download, training, evaluation and Grad-CAM; ran lint, synthetic-data smoke tests and the full test suite in GitHub Actions
- Re-trained both models with honest numbers: ResNet34 screener at ROC AUC 0.82 / PR AUC 0.88, 71% sensitivity at 79% specificity on 913 held-out eyes from 480 patients; U-Net at Dice 0.82 / IoU 0.69 on 200 held-out images
- Ran a five-configuration ablation showing flip augmentation costs 0.13 Dice on the small vessel set while cosine annealing is neutral, and documented it in the model card
- Chose the screening operating point by Youden's J on validation rather than max-F1, which on 55%-positive data drifts to a threshold with 48% specificity
- Exported int8 ONNX models (22 MB + 39 MB) with verified parity and built the in-browser demo below with ONNX Runtime Web; images never leave the device
- Led the five-person course team: scoping, task allocation, the proposal and final report