Team BreakingGood — Rémi Al Ajroudi & Bruny Soutarson
Master MVA, ENS Paris-Saclay
Binary classification of H&E histopathology patches with strong inter-center distribution shift (train: centers 0,3,4 — val: center 1 — test: unknown center).
Best public LB score: 0.98705 (UNI2-h + LoRA + EMA + HED augmentation + pseudo-labeling + 8× TTA)
src/
├── data.py # H5Dataset (multi-worker safe), HED jitter, transforms
├── models.py # Foundation model loaders (Phikon-v2, UNI2-h, DINOv2-L, etc.), LoRA wrap, ClassifHead
├── train_lora.py # DDP LoRA training (torchrun), EMA, pseudo-labels, train+val combined
├── infer_tta.py # DDP TTA inference, generates float + int CSVs
├── ensemble.py # Weighted average of multiple submission CSVs
├── generate_pseudo_labels.py # Generate pseudo-label JSON from float predictions
└── to_int_submit.py # Convert float CSV → int 0/1 for Kaggle
overnight_pipeline.sh # Automated overnight pipeline (pseudo-labeling rounds)
overnight_extended.sh # Extended pipeline (multi-seed, ensembles)
pip install torch torchvision h5py timm transformers huggingface_hub peft scikit-learn accelerate einops
kaggle competitions download -c mva-dlmi-2026-histopathology-ood-classification
unzip mva-dlmi-2026-histopathology-ood-classification.zip -d data/
torchrun --nproc_per_node=4 src/train_lora.py \
--model uni2h --train-h5 data/train.h5 --val-h5 data/val.h5 \
--epochs 5 --batch-size 32 --lr 1e-4 --head-lr 1e-3 \
--lora-r 16 --lora-alpha 32 --hed-sigma 0.10 --use-ema \
--output-dir runs/uni2h_v1
# Inference with current best
torchrun --nproc_per_node=4 src/infer_tta.py \
--model uni2h --checkpoint runs/uni2h_v1/best \
--test-h5 data/test.h5 --tta 8 --output submissions/uni2h_base.csv
# Generate pseudo-labels
python src/generate_pseudo_labels.py \
--csv submissions/uni2h_base.csv --high 0.97 --low 0.03 \
--output cache/pseudo_labels.json
# Retrain with pseudo-labels
torchrun --nproc_per_node=4 src/train_lora.py \
--model uni2h --train-h5 data/train.h5 --val-h5 data/val.h5 --test-h5 data/test.h5 \
--pseudo-labels cache/pseudo_labels.json \
--epochs 4 --batch-size 32 --lr 1e-4 --hed-sigma 0.10 --use-ema \
--output-dir runs/uni2h_pseudo
# Final inference
torchrun --nproc_per_node=4 src/infer_tta.py \
--model uni2h --checkpoint runs/uni2h_pseudo/best \
--test-h5 data/test.h5 --tta 8 --output submissions/final.csv
kaggle competitions submit -c mva-dlmi-2026-histopathology-ood-classification \
-f submissions/final_INT.csv -m "UNI2-h LoRA + pseudo-labeling + TTA"
2 commits
Python
79.7%
Shell
20.3%
Team BreakingGood — Rémi Al Ajroudi & Bruny Soutarson
Master MVA, ENS Paris-Saclay
Binary classification of H&E histopathology patches with strong inter-center distribution shift (train: centers 0,3,4 — val: center 1 — test: unknown center).
Best public LB score: 0.98705 (UNI2-h + LoRA + EMA + HED augmentation + pseudo-labeling + 8× TTA)
src/
├── data.py # H5Dataset (multi-worker safe), HED jitter, transforms
├── models.py # Foundation model loaders (Phikon-v2, UNI2-h, DINOv2-L, etc.), LoRA wrap, ClassifHead
├── train_lora.py # DDP LoRA training (torchrun), EMA, pseudo-labels, train+val combined
├── infer_tta.py # DDP TTA inference, generates float + int CSVs
├── ensemble.py # Weighted average of multiple submission CSVs
├── generate_pseudo_labels.py # Generate pseudo-label JSON from float predictions
└── to_int_submit.py # Convert float CSV → int 0/1 for Kaggle
overnight_pipeline.sh # Automated overnight pipeline (pseudo-labeling rounds)
overnight_extended.sh # Extended pipeline (multi-seed, ensembles)
pip install torch torchvision h5py timm transformers huggingface_hub peft scikit-learn accelerate einops
kaggle competitions download -c mva-dlmi-2026-histopathology-ood-classification
unzip mva-dlmi-2026-histopathology-ood-classification.zip -d data/
torchrun --nproc_per_node=4 src/train_lora.py \
--model uni2h --train-h5 data/train.h5 --val-h5 data/val.h5 \
--epochs 5 --batch-size 32 --lr 1e-4 --head-lr 1e-3 \
--lora-r 16 --lora-alpha 32 --hed-sigma 0.10 --use-ema \
--output-dir runs/uni2h_v1
# Inference with current best
torchrun --nproc_per_node=4 src/infer_tta.py \
--model uni2h --checkpoint runs/uni2h_v1/best \
--test-h5 data/test.h5 --tta 8 --output submissions/uni2h_base.csv
# Generate pseudo-labels
python src/generate_pseudo_labels.py \
--csv submissions/uni2h_base.csv --high 0.97 --low 0.03 \
--output cache/pseudo_labels.json
# Retrain with pseudo-labels
torchrun --nproc_per_node=4 src/train_lora.py \
--model uni2h --train-h5 data/train.h5 --val-h5 data/val.h5 --test-h5 data/test.h5 \
--pseudo-labels cache/pseudo_labels.json \
--epochs 4 --batch-size 32 --lr 1e-4 --hed-sigma 0.10 --use-ema \
--output-dir runs/uni2h_pseudo
# Final inference
torchrun --nproc_per_node=4 src/infer_tta.py \
--model uni2h --checkpoint runs/uni2h_pseudo/best \
--test-h5 data/test.h5 --tta 8 --output submissions/final.csv
kaggle competitions submit -c mva-dlmi-2026-histopathology-ood-classification \
-f submissions/final_INT.csv -m "UNI2-h LoRA + pseudo-labeling + TTA"
2 commits
Python
79.7%
Shell
20.3%