Problem
DrivenData's DaT Parkinson's Challenge asked for one number per 3D DaT-SPECT brain scan: the probability that the scan is abnormal. Entries were scored by log loss. It measures how far the predicted probabilities were from the truth; lower is better. So the model had to be right about how sure it was, not only about which scans look abnormal.
The data was 1,362 scans from ten French hospitals, labelled by 11 nuclear medicine specialists. Scans came in 21 acquisition families with different sizes and resolutions. In the widest, the head filled about 1% of the image[src].
Approach
- n = 1,362 (747 abnormal, 615 normal)
- 10 French hospitals
- 21 acquisition families
- FOV 176–630 mm per axis
- Reorient to RAS
- Resample to 2.0 mm isotropic
- Centre-of-mass crop 96 × 96 × 96
- Reference-region intensity normalisation
- GroupNorm, widths 16/32/64/128, dropout 0.3
- AdamW lr 3e-4, cosine, 30 epochs, early stopping
- Run 2 augmentation: elastic, PSF blur, signed gamma, count noise, mixup
- No left–right flip: asymmetry is signal
- TTA: 9 laterality-preserving views, logit mean
- Logit correlation with the CNN ensemble ρ = 0.821
- CNN +0.694, trees +0.364, intercept +0.048
- Carries the calibration: no separate temperature
- Clip to [1e-6, 1 − 1e-6]
- Crop around the brain, not the image. A fixed centre crop cut off the striatum, the region that matters, in wide scans. Each scan is cropped around its centre of mass instead.
- Never flip left and right. Abnormality is often one-sided, and mirroring a scan would blur that signal.
- Two different model families. The tree model on hand-built striatal measurements is weaker alone. But its outputs correlate only 0.821 with the CNN's, so it is wrong on different scans. It carries 34% of the weight in the final stack, and adding it cut log loss by 0.0184 at 3.3 sigma[src].
- Let the stack do the calibration. The stack's CNN weight sits below 1, which works like temperature scaling. So there is no separate calibration step to fit and maintain.
- Choose calibrators out of sample. Early on, isotonic regression was picked because it had been scored on its own training predictions. Under cross-validation it did worse than no calibration: 0.3520 against 0.3271 log loss[src].
Result
The final model ranks scans well: out-of-fold AUROC 0.9455[src]. AUROC is the chance that a random abnormal scan scores above a random normal one; 1 is perfect. The CNN ensemble's probabilities are close to honest. ECE, the average gap between predicted probability and the rate actually observed, is 0.0187 for the CNN ensemble. For the baseline, calibrating each family with a temperature fitted only on the other families cost just +0.0006 log loss overall, so the calibration carries over to acquisitions it was not fitted on[src].
The weak spots are the small families. The 30-scan 1.5 mm family and the pooled small families have the lowest AUROC and the highest ECE, so a probability on an uncommon acquisition deserves less trust. The per-family breakdown exists only for the baseline, and every family was seen in training[src]. On the leaderboard my entry finished #159 of 1009 (top 16%), with private scores worse than public by a similar margin for every build[src].
What I learned
- Diversity beats quality in a stack. The trees and the second CNN run were each weaker alone, yet they gave the largest gains, because their errors fell in different places.
- Pooled calibration hides the groups that matter. The baseline looked well calibrated on all scans together, yet its ECE on the 30-scan 1.5 mm family was 0.1552[src]. I only broke results down by family for the baseline, so I cannot say whether the final model closes that gap.
Tools
Python, PyTorch, LightGBM, scikit-learn, NumPy, pandas, SciPy, pytest, Docker, Claude Code. The assistant never saw competition data. It wrote scripts and received only aggregate summaries.
Links
- Competition: https://www.drivendata.org/competitions/311/dat-parkinsons-challenge/
- Code repository: https://github.com/feitandodatascience/dat-parkinsons-challenge
Sources
Each [src] marker cites one of these project records:
- DaT Parkinson's Challenge (DrivenData): 3D DaT-SPECT normal vs abnormal