2026
Kaggle, Computer Vision, Deep Learning
RSNA Knee Abnormality DetectionMRI Deep Learning
Detected 12 knee problems (ACL and meniscus tears, arthritis, fractures) in MRI scans, training on report-derived soft labels because only 58 of 4,407 scans had expert labels. Built the full DICOM pipeline and a custom 2.5D model.
In numbers
- 2,647 / 6,299
- final leaderboard, top 43%
- 0.851 → 0.876
- validation AUC from tuning my own 2.5D model (public DINOv2: 0.850)
- 0.883 → 0.911
- leaderboard AUC with a 5-fold ensemble of my model
- 0.944 / 0.929
- final public / private AUC, up ~70 places on private
What I did
- 1.
Worked on detecting 12 knee findings in MRI in a competition with 6,400+ teams. With expert labels for only 58 of 4,407 scans, I trained on soft labels taken from radiology reports written in 9 languages, using LLM-extracted label sets.
- 2.
Built the full MRI pipeline for 24,371 DICOM series: read the scan type straight from DICOM headers (the provided metadata missed it, leaving one model input empty; after the fix it was filled for 62% of studies), stacked 3 neighbouring slices into one image, cropped every scan to the same 130 mm field of view and flipped left knees to match right. 358,000 slices processed with zero failures.
- 3.
Designed and trained my own 2.5D model (a ResNet50/101 backbone with attention over slices for each finding) across 20+ tracked experiments on Kaggle T4 GPUs. Tuning raised validation AUC from 0.851 to 0.876, beating a public DINOv2 model (0.850), and a 5-fold ensemble lifted leaderboard AUC from 0.883 to 0.911 (0.895 private).
- 4.
Built a training setup that ran unattended: it benchmarked speed and memory before each run, fitted the number of epochs to the GPU time limit, recovered from crashed runs and logged every setting and result. Checks before spending GPU time caught bugs such as a label leak that inflated validation by about 0.005.
- 5.
Final submission: a rank-averaged ensemble of public models with a fallback path to stay inside the 9-hour offline limit. It scored 0.944 public / 0.929 private AUC, moving up ~70 places when the private leaderboard was revealed.
Notes
The hard part of this competition wasn't the model. It was the labels. Almost none of the scans had expert annotations, so everything depended on how well labels could be pulled out of free-text radiology reports in nine languages.
What I learned from the top solutions
- –Our main gap was label quality, not architecture. The top teams used vision LLMs to read the MRI images directly, reaching about 0.95 label AUC against the 0.895 of the report-derived labels we trained on.
- –Better labels would have moved the score more than any backbone or ensembling change I tried.
What I'd keep doing
- –Fixing data problems at the source (the missing scan type) before touching the model.
- –Making every GPU hour count: pre-flight speed and memory checks, time-fitted epochs, automatic recovery and full experiment logs.
- –Hunting for leaks: catching a 0.005 validation inflation before trusting any result.
Built with
Python · PyTorch · timm · pydicom · ResNet50/101 · Kaggle T4 GPUs · LLM-generated labels
Next project
Contact Intent & Complaints ML →