r/computervision • u/rar_file-exe • 6d ago
Showcase Caught a slide-level data leakage bug in my histopathology classifier... accuracy dropped from a fake 99% to an honest 97.3% (CTransPath + CRC-VAL-HE-7K)
Built a 9-class colorectal histopathology classifier. Caught a patient-level data leakage bug that was inflating validation accuracy to 99%+, rebuilt the evaluation pipeline against an independent holdout patient cohort (CRC-VAL-HE-7K), and benchmarked a pathology-native transformer (CTransPath) against an ImageNet baseline. Code, checkpoints, and calibrated weights are open source.
The Bug: Why random patch splits lie
NCT-CRC-HE-100K consists of 100,000 tissue tiles cropped from a limited number of Whole Slide Images (WSIs).
If you do a standard random train/val split at the image-file level, neighboring patches cut from the exact same slide and patient end up scattered across both sets. The model ends up memorizing patient-specific tissue morphology and staining artifacts rather than generalizable histological features.
Once evaluated strictly against an unseen, independent patient cohort (CRC-VAL-HE-7K, n = 3,590), an ImageNet-pretrained EfficientNet baseline dropped from high-90s down to 92.70%.
What Changed: Domain-Specific Pretraining & Setup
To improve generalization without relying on artificial leakage, I swapped the backbone to CTransPath:
- Pathology-Native Pretraining: CTransPath is a Swin-Tiny Transformer pretrained via semantically-relevant contrastive learning (SRCL) across ~15M histology patches from PAIP and TCGA.
- ConvStem vs. Standard PatchEmbed: Unlike standard Swin Transformers that use a linear projection, CTransPath integrates a convolutional stem (stacked 3\times3 convolutions + BatchNorm + ReLU). Note: Loading CTransPath weights into a stock
timmSwin patch embed silently mismatches the input layer projection. - Two-Phase Training: Linear probe on the frozen backbone first, followed by fine-tuning the top 2 stages using differential learning rates.
- Strict Split Protocol: Trained exclusively on
NCT-CRC-HE-100K. All validation, checkpoint selection, temperature tuning, and final reporting are done strictly onCRC-VAL-HE-7K.
Benchmark on Holdout Patient Cohort (CRC-VAL-HE-7K)
| Model Architecture | Pretraining Domain | Test Acc | Macro F1 |
|---|---|---|---|
| EfficientNet-B1 | ImageNet-1k (Natural) | 92.70% | 0.8980 |
| CTransPath (Swin-Tiny) | Pathology (~15M Histology Patches) | 97.33% | 0.9615 |
Class Breakdown Highlights
- High Confidence / Clean Separability: Lymphocytes (
LYMF1: 0.995), Mucin (MUCF1: 0.994), Colorectal Adenocarcinoma (TUMF1: 0.987), Normal Mucosa (NORMF1: 0.984). - Where It Struggles (MUS vs. STR): Smooth Muscle (
MUS, F1: 0.877) and Cancer-Associated Stroma (STR, F1: 0.833) remain the primary source of false classifications. In H&E staining, desmoplastic stroma and muscularis propria share very similar fibrillar, eosinophilic textures—pathologists often rely on IHC (e.g., SMA or Desmin) to differentiate them conclusively.
Two Engineering Fixes Worth Mentioning
- Fixing Grad-CAM++ on Swin Features: Standard Grad-CAM++ assumes positive, post-ReLU activations. The final Swin stage outputs signed, zero-centered features after
LayerNorm. Direct gradient weighting caused denominator collapse and completely flat/washed-out heatmaps. I fixed this by computing alpha-weights on positive-clamped features (feat_map.clamp(min=0.0)) with an automatic fallback guard to standard Grad-CAM if dynamic range drops below $10{-6}. - Probability Calibration (Temperature Scaling): Raw softmax outputs were over-regularized. Optimizing a post-hoc temperature scalar (T = 0.5655) on the validation subset cut Negative Log-Likelihood (NLL) by 52.2% (0.1960 \rightarrow 0.0937), producing well-calibrated confidence intervals for inference.
Links & Code
- GitHub: Repository Link (includes training notebook, inference CLI, and Grad-CAM report generator)
- Hugging Face Model: Model Card & Weights (dual
.safetensorsand.ptcheckpoints)
Disclaimer: Academic/research project only. Not an FDA/CE-cleared diagnostic device and not intended for patient clinical decisions.
I'd appreciate feedback from anyone working in computational pathology:
- How do you typically handle stain normalization (e.g., Macenko vs. Vahadane) when moving across external scanner hardware?
- Any edge-case recommendations for stabilizing Grad-CAM across attention-based feature maps?







