Diabetic Retinopathy is a leading cause of blindness worldwide. Early detection through retinal imaging can prevent vision loss. This project builds an automated pipeline that:
Takes a retinal fundus image as input
Segments all lesions (Microaneurysms, Haemorrhages, Exudates, Optic Disc)
Predicts the DR severity grade (0-4)
Generates a clinical report explaining the findings
The entire pipeline was trained on the IDRiD (Indian Diabetic Retinopathy Image Dataset) using a single NVIDIA A100 40GB GPU on Lambda Labs cloud.
SegFormer combines a hierarchical Transformer encoder with a lightweight MLP decoder. It captures both local details (important for tiny microaneurysms) and global context (important for understanding overall retinal structure). It outperforms U-Net on medical image segmentation with fewer parameters.
Training Configuration
Parameter
Value
Image Size
512 x 512
Batch Size
8
Epochs
60
Optimizer
AdamW (weight_decay=1e-4)
Learning Rate
3e-4
LR Scheduler
CosineAnnealingLR (eta_min=1e-6)
Mixed Precision
Yes (AMP with GradScaler)
Train/Val Split
80/20 (43 train, 11 val)
Test Set
27 images (separate, provided by IDRiD)
Loss Function: Combined Dice + Focal Loss
Total Loss = 0.5 * Dice Loss + 0.5 * Focal Loss
Dice Loss: Directly optimizes the overlap between prediction and ground truth. Handles class imbalance well.
Focal Loss (gamma=2.0): Down-weights easy-to-classify pixels, focuses training on hard pixels (lesion boundaries).
Class Weights (to handle extreme imbalance)
Class
Weight
Reason
Background
0.02
Dominates 95%+ of pixels
Microaneurysms
4.0
Extremely tiny, <0.1% of pixels
Haemorrhages
3.5
Small lesions
Hard Exudates
2.0
Moderate size
Soft Exudates
3.0
Rare
Optic Disc
0.5
Large, easy to segment
Data Augmentation (Critical for 54 images)
Since we only have 54 training images, heavy augmentation is essential:
Individual binary masks from the dataset are combined into a single multi-class mask with priority ordering (higher class ID overwrites lower if overlapping):
Background (0) → MA (1) → HE (2) → EX (3) → SE (4) → OD (5)
Stage 2: Disease Severity Grading
Model Architecture
Model: EfficientNet-B0 (pretrained on ImageNet)
Input: 224x224 RGB fundus image
Output: 5-class probability (Grades 0-4)
Final Layer: Linear(1280, 5)
Why EfficientNet?
EfficientNet uses compound scaling (depth, width, resolution) to achieve high accuracy with fewer parameters. B0 is the smallest variant — ideal for a dataset of 413 images.
Training Configuration
Parameter
Value
Image Size
224 x 224
Batch Size
16
Epochs
30
Optimizer
Adam (lr=1e-4)
LR Scheduler
StepLR (step=10, gamma=0.5)
Loss
CrossEntropyLoss
Train/Val Split
80/20 stratified (330 train, 83 val)
Test Set
103 images (separate)
Grading Data Augmentation
RandomHorizontalFlip
RandomVerticalFlip
RandomRotation (15 degrees)
ColorJitter (brightness=0.2, contrast=0.2)
Stage 3: Clinical Report Generation (VLM)
This stage uses a Vision-Language Model (VLM) approach to generate structured clinical reports from the model outputs. Two approaches were explored:
Approach 1: Template-Based VLM (Used in Final Pipeline)
The production pipeline uses a template-based deterministic approach that combines segmentation and grading outputs to generate clinically accurate reports without requiring an external LLM API:
Runs the trained segmentation model to detect lesions and compute pixel-level coverage
Runs the trained grading model to predict DR severity (0-4)
Maps the predicted grade to a pre-authored clinical narrative written by domain experts
Appends lesion-specific findings (name + coverage %) with clinical interpretation
This approach was chosen because:
Deterministic output — same input always produces the same report (important for medical AI)
No hallucination risk — all text is pre-validated by clinical templates
No API dependency — runs fully offline on any hardware
Fast inference — no LLM generation latency
Approach 2: LLaVA Fine-tuning (Experimental, Not Deployed)
An attempt was made to fine-tune LLaVA (Large Language and Vision Assistant) on the IDRiD dataset for open-ended report generation:
Training data was formatted as conversation-style JSON (human asks for diagnosis, model provides report)
The 03_dr_grading_vlm.py notebook prepares the LLaVA-compatible training JSON from the grading labels
Due to compute constraints (LLaVA-7B requires >24GB VRAM for fine-tuning), this was explored in Google Colab but not deployed in the final pipeline
The formatted training JSONs (idrid_vlm_train.json, idrid_vlm_val.json) are available for future fine-tuning
Alternative: Google Gemini Vision API
For richer, context-aware reports without fine-tuning, you can use the Gemini Vision API as a drop-in replacement:
python
1import google.generativeai as genai
2from PIL import Image
34genai.configure(api_key="YOUR_GEMINI_API_KEY")5model = genai.GenerativeModel("gemini-2.0-flash")67img = Image.open("fundus_image.jpg")89prompt ="""You are an ophthalmologist. Analyze this retinal fundus image.
10The segmentation model detected: Microaneurysms (58.08%), Hard Exudates (6.30%).
11The grading model predicted: Severe DR (Grade 3).
1213Provide a structured clinical report with:
141. Overall assessment
152. Lesion analysis
163. Clinical significance
174. Recommended follow-up"""1819response = model.generate_content([prompt, img])20print(response.text)
Gemini Vision API requirements:
pip install google-generativeai
A Google AI Studio API key (free tier: 15 RPM / 1M tokens per day)
Internet connection for API calls
This gives more natural, detailed reports but introduces non-determinism and API dependency.
Report Content
Each generated report includes:
Overall DR severity assessment
Description of each detected lesion type
Clinical significance of the findings
Coverage percentage of each lesion
Recommended follow-up actions
Example Report Output
json
1{2"image_id":"IDRiD_55",3"dr_grade":3,4"grade_name":"Severe DR",5"lesions_detected":[6{"name":"Microaneurysms","percentage":58.08},7{"name":"Haemorrhages","percentage":0.67},8{"name":"Hard Exudates","percentage":6.30},9{"name":"Optic Disc","percentage":1.53}10],11"clinical_report": "Severe non-proliferative diabetic retinopathy is detected.
12 Extensive retinal lesions are observed with significant hemorrhages, cotton wool
13 spots, and venous abnormalities. Urgent referral to a retinal specialist is
14 recommended. Microaneurysms detected (58.08% coverage), indicating focal
15 capillary wall weakness. Retinal hemorrhages observed (0.67% coverage),16 suggesting vessel wall rupture. Hard exudates present (6.30% coverage),17 indicating lipid leakage from damaged vessels."
18}
Results
Segmentation Results (Test Set — 27 images)
Class
Dice Score
IoU Score
Background
0.5089
0.3419
Microaneurysms
0.0026
0.0013
Haemorrhages
0.4420
0.3045
Hard Exudates
0.5047
0.3500
Soft Exudates
0.3889
0.2859
Optic Disc
0.9289
0.8689
Mean (excl. BG)
0.4534
0.3621
Key Observations:
Optic Disc achieves excellent segmentation (Dice 0.93) due to its large, consistent shape
Hard Exudates perform well (Dice 0.50) as they have bright, distinct appearance
Microaneurysms are nearly impossible to segment (Dice 0.003) because they are only 2-5 pixels in diameter
With only 54 training images, these results are reasonable for the IDRiD benchmark
Disease Grading Results (Test Set — 103 images)
Overall Test Accuracy: 58.25%
Grade
Precision
Recall
F1-Score
Support
No DR (0)
0.6250
0.7353
0.6757
34
Mild DR (1)
0.0000
0.0000
0.0000
5
Moderate DR (2)
0.4773
0.6562
0.5526
32
Severe DR (3)
0.7059
0.6316
0.6667
19
Proliferative DR (4)
1.0000
0.1538
0.2667
13
Key Observations:
Severe DR has the best F1-score (0.67) with good precision and recall
No DR is well-classified (F1 0.68) since healthy retinas are distinct
Mild DR has 0 samples correctly predicted (only 5 test samples — too few to learn)
Class imbalance is the main challenge (20 mild samples vs 136 moderate in training)
VLM Report Generation Results
27 clinical reports generated for all test images
Each report includes lesion-level analysis with coverage percentages
Main script — runs the entire pipeline end-to-end. Contains all model definitions, training loops, evaluation, preprocessing, and report generation. ~1400 lines.
generate_reports.py
Standalone script to generate clinical reports using already-trained models. Loads both model weights, runs inference on test set, outputs JSON reports.
setup_lambda.sh
Shell script to set up a Lambda Labs GPU instance — installs all Python packages and creates required directories.
Results (results/)
File
Description
segmentation/best_segformer.pth
Trained SegFormer-B2 model weights (94 MB). Load with PyTorch.
segmentation/training_history.png
Plot showing loss, Dice, and IoU curves over 60 epochs.
segmentation/per_class_metrics.png
Bar chart comparing Dice and IoU for each lesion class.
segmentation/test_metrics.csv
CSV with exact Dice and IoU values per class.
segmentation/predictions/*.png
Color-coded predicted segmentation masks for all 27 test images.