Instructions to use hakim78/Cancer_pathos with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- timm
How to use hakim78/Cancer_pathos with timm:
import timm model = timm.create_model("hf-hub:hakim78/Cancer_pathos", pretrained=True) - Notebooks
- Google Colab
- Kaggle
- Cancer_pathos
- The patch classifier of Pathos Pro: metastasis detection on 96 px lymph node patches, evaluated on a test set opened once
- What is Cancer_pathos?
- Updates
- How it works
- Results
- Where it sits in Pathos Pro
- Files in this repository
- Quick start
- Intended use
- License and Terms of Use
- Acknowledgements
- Reference
- The patch classifier of Pathos Pro: metastasis detection on 96 px lymph node patches, evaluated on a test set opened once
Cancer_pathos
The patch classifier of Pathos Pro: metastasis detection on 96 px lymph node patches, evaluated on a test set opened once
Independent engineering project · 2026 · part of Pathos Pro, AI assistance for breast sentinel lymph nodes
Live demo | Code | Results | Quick start | Files | Cite | English · Français
Abstract: Cancer_pathos is a ConvNeXt-Tiny classifier with a residual head (28.3 M parameters) that tells whether the centre of a 96 px haematoxylin and eosin patch of lymph node contains metastatic tissue. It reaches an AUC of 0.9979 [0.9975 ; 0.9982] on a locked PatchCamelyon test set of 33,004 patches that was never used for training, model selection or tuning. Five-fold cross-validation gives 0.9975 ± 0.0001. The repository also documents what the model looks at (Grad-CAM, counterfactual masking), how sure it is (Monte Carlo dropout) and which known cases resemble a query (FAISS). This is a research model. It is not a certified medical device and it must not be used for diagnosis.
What is Cancer_pathos?
- A patch-level tumour detector: one 96 × 96 px RGB patch in, one probability out. The label describes the central 32 × 32 px only, as in PatchCamelyon.
- Measured on a locked test set: 70 / 15 / 15 stratified split, test opened once at the very end, 95% bootstrap confidence interval reported with the AUC.
- Explainable: Grad-CAM maps, a check that attention sits on the labelled centre, and a counterfactual test that masks the attended pixels and measures the drop.
- Aware of its doubt: Monte Carlo dropout flags uncertain patches. Reviewing the 10% most uncertain ones catches 20.2% of the errors.
- One brick of a product: in Pathos Pro it supplies Grad-CAM, uncertainty and similar cases at tile level. The whole-slide verdict comes from another model, described below.
Why it matters: on sentinel lymph nodes, AI assistance raised micrometastasis sensitivity from 83.3% to 91.2% and cut the review time of micrometastases from 116 s to 61 s (Steiner et al., Am J Surg Pathol 2018). A patch model is the smallest unit of such assistance, and the place where its claims are easiest to check.
Updates
- 11/14/2026: Model card rewritten with animations, the v2 figures and a tested loading snippet.
- 10/12/2026: The Pathos Pro whole-slide verdict moves to H-optimus-0 with attention pooling. This patch model stays in the product for tile-level explanation.
- 09/09/2026: Master's thesis defended.
- 06/15/2026: v2 released: strict three-way split, five-fold cross-validation, locked test, DeLong test on the gain of test-time augmentation.
- Earlier in 2026: v1 training run (50 epochs on about 95% of the labels). Its checkpoints are kept here for history only.
How it works
1. From a patch to a probability
- Input: RGB patch, 96 × 96 px, ImageNet normalisation (mean
[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]). - Backbone:
timmconvnext_tiny, ImageNet initialisation, no classification layer, 768-dimensional features (27.82 M parameters). - Head: residual MLP,
768 → 256 → 256 → 1with batch normalisation, GELU, dropout 0.3 and a linear shortcut (460,801 parameters). One logit, then a sigmoid. - Test-time augmentation ×5: original, horizontal flip, vertical flip, 90° rotation and transpose. The five probabilities are averaged.
2. Training
| Setting | Value |
|---|---|
| Data | PatchCamelyon as distributed by the Kaggle Histopathologic Cancer Detection challenge, 220,025 labelled patches, 40.50% tumour |
| Split | 70 / 15 / 15 stratified, seed 42: 154,017 train · 33,004 validation · 33,004 locked test |
| Loss | Focal loss, α = 0.25, γ = 2.0 |
| Optimiser | AdamW, learning rate 1e-4, weight decay 1e-5 |
| Schedule | CosineAnnealingLR, 20 epochs at most, early stopping on validation AUC with patience 4 |
| Batch and precision | 64, automatic mixed precision |
| Augmentation | Albumentations: flips, 90° rotations, transpose, shift-scale-rotate, elastic and grid distortion, colour jitter, hue-saturation, CLAHE, noise, blur, coarse dropout |
| Hardware | One NVIDIA Tesla T4 |
3. Evaluation protocol
- Cross-validation first: five folds on train + validation with identical hyperparameters, to measure the spread before touching the test set.
- Then one final model, early-stopped on the validation split.
- Then the test set, once: no threshold, epoch or hyperparameter was chosen on it.
Results
All values come from the result files in results_v2/.
No value is rounded up.
| Metric | 5-fold cross-validation | Locked test, TTA ×5 | Locked test, no TTA |
|---|---|---|---|
| AUC-ROC | 0.9975 ± 0.0001 | 0.9979 [0.9975 ; 0.9982] | 0.9974 |
| Accuracy | 0.9821 ± 0.0008 | 0.9847 | 0.9827 |
| F1 | 0.9778 ± 0.0010 | 0.9810 | 0.9787 |
| Sensitivity | 0.9753 ± 0.0015 | 0.9794 | 0.9779 |
| Specificity | 0.9867 ± 0.0006 | 0.9882 | 0.9860 |
| Brier score | 0.0212 ± 0.0005 | 0.0172 | 0.0183 |
Confusion matrix on the 33,004 test patches at threshold 0.5: 19,405 true negatives, 231 false positives, 275 false negatives, 13,093 true positives.
Top: ROC over the five cross-validation folds, and confusion matrix on the locked test (counts, then share per row). Bottom: reliability diagram, and bootstrap distribution of the test AUC (2,000 resamples). Some figure labels are in French.
Test-time augmentation: the gain is statistically significant (paired DeLong test, z = 6.62, p = 3.5 × 10⁻¹¹) and small in size, +0.00045 AUC. It is kept for stability, not for performance.
Calibration: Brier score 0.0172, expected calibration error 0.0449 on the locked test.
Explainability
Grad-CAM on locked-test patches: tumour on the top row, normal tissue on the bottom row.
- Attention on the labelled centre: the centre-to-periphery attention ratio is 1.96 on tumour patches and 0.60 on normal ones (300 patches).
- Counterfactual masking: hiding the 20% most attended pixels lowers the tumour probability by a median of 0.085 (250 patches). 44% of patches drop by more than 0.1.
Uncertainty
Share of the model's errors caught (vertical) against share of patches reviewed (horizontal), most uncertain first. The dashed line is a random review.
Monte Carlo dropout, 30 passes on 20,000 locked-test patches (346 errors):
- Wrong predictions are 1.68 times more uncertain than correct ones (standard deviation 0.0142 against 0.0085, one-sided Mann-Whitney p = 5.6 × 10⁻⁷⁰).
- Reviewing the 10% most uncertain patches catches 20.2% of the errors. That set holds 3.50% errors against 1.73% overall, an enrichment of ×2.02.
- The errors concentrate near the decision threshold.
Similar cases
The 768-dimensional features are indexed with FAISS (exact flat index, cosine similarity). With a base of 20,000 training patches and 1,000 test queries, 97.9% of the five nearest neighbours share the class of the query (98.2% normal, 97.6% tumour).
What these numbers do not say
- Patch level only. A 1.18% false-positive rate per patch adds up over the thousands of patches of a slide. This model alone does not give a slide-level answer.
- One dataset. PatchCamelyon comes from two Dutch centres. No other centre, scanner or staining protocol was tested with this model.
- The split is by patch, not by slide. Patches from the same slide can sit in train and in test, so the test figures and the FAISS precision are optimistic compared with a slide-level split.
- Uncertainty covers the head only. The backbone has no stochastic depth, so the Monte Carlo dropout standard deviations are small in absolute value.
- The only published reference on this benchmark is Veeling et al., 2018, AUC 0.963. This model was never submitted to the Kaggle leaderboard.
- Self-reported results from a single developer, without an external audit.
Where it sits in Pathos Pro
Pathos Pro is a complete second-read system for breast sentinel lymph nodes: slide intake, whole-slide analysis, a viewer that records the pathologist's impression before showing any AI output, a sourced copilot and an audit journal. The slide-level verdict is not produced by this patch model. It comes from H-optimus-0 tile features pooled by gated-attention multiple instance learning:
| Level | Data | Model | Metric | Value |
|---|---|---|---|---|
| Patch | PatchCamelyon, locked test, 33,004 patches | This model, TTA ×5 | AUC [95% CI] | 0.9979 [0.9975 ; 0.9982] |
| Slide | CAMELYON16 test, 129 slides | ABMIL + H-optimus-0, five-fold ensemble | AUC | 0.9949 |
| Slide, external | SLN-Breast, 130 slides, 36 positive | Same ensemble, no retraining | AUC [95% CI] | 0.9566 [0.9019 ; 0.9964] |
The slide-level weights are not in this repository. Code, design notes and the full product description are on GitHub.
Files in this repository
| Path | Content |
|---|---|
models/final_model_v2_locked.pth |
The model described on this page (v2, raw state_dict, 113 MB). Also the one served by the demo. |
results_v2/ |
Test metrics, cross-validation folds, DeLong and bootstrap significance, summary table |
assets/ |
Animations and v2 figures of this page |
models/best_model_epoch*.pth |
v1 training history, 31 checkpoints of 340 MB each. Their file names carry validation AUCs, which also drove early stopping. Do not quote them as results. |
figures/ |
v1 figures, measured on the v1 validation split. Kept for history. |
Quick start
pip install torch timm huggingface_hub
import torch, timm
import torch.nn as nn
from huggingface_hub import hf_hub_download
class ResidualHead(nn.Module):
def __init__(self, in_features, hidden=256, dropout=0.3):
super().__init__()
self.fc1, self.bn1 = nn.Linear(in_features, hidden), nn.BatchNorm1d(hidden)
self.fc2, self.bn2 = nn.Linear(hidden, hidden), nn.BatchNorm1d(hidden)
self.fc_out, self.shortcut = nn.Linear(hidden, 1), nn.Linear(in_features, hidden)
self.gelu, self.dropout = nn.GELU(), nn.Dropout(dropout)
def forward(self, x):
identity = self.shortcut(x)
out = self.dropout(self.gelu(self.bn1(self.fc1(x))))
out = self.gelu(self.bn2(self.fc2(out)) + identity)
return self.fc_out(self.dropout(out))
class CancerClassifier(nn.Module):
def __init__(self):
super().__init__()
self.backbone = timm.create_model("convnext_tiny", pretrained=False, num_classes=0)
self.head = ResidualHead(self.backbone.num_features)
def forward(self, x):
return self.head(self.backbone(x))
model = CancerClassifier()
path = hf_hub_download("hakim78/Cancer_pathos", "models/final_model_v2_locked.pth")
model.load_state_dict(torch.load(path, map_location="cpu", weights_only=True))
model.eval()
def predict(x):
"""x: float tensor (N, 3, 96, 96), ImageNet-normalised. Returns the tumour probability, TTA x5."""
views = [x, x.flip(-1), x.flip(-2), x.rot90(1, (-2, -1)), x.transpose(-2, -1)]
with torch.no_grad():
return torch.stack([torch.sigmoid(model(v)) for v in views]).mean(0)
This snippet was run against the published file: all keys match and the model counts 28,280,929 parameters.
Or try it in the browser: Cancer_pathos_demo (CPU Space, about 0.8 s per patch once warm, test-time augmentation included).
Intended use
Research and teaching on computational pathology: benchmarking, explainability studies, a feature extractor for tile-level analysis. Patches should match PatchCamelyon: haematoxylin and eosin, lymph node tissue, about 0.97 µm per pixel (10× equivalent).
Out of scope: any diagnostic use, any decision about a patient, other organs or stains, other magnifications without rescaling. This model is not a medical device and carries no CE marking.
License and Terms of Use
Weights and code are released under the MIT License, for research use. PatchCamelyon is derived from CAMELYON16 and distributed under CC0. No patient data is stored in this repository.
Acknowledgements
This work builds on PatchCamelyon (Veeling et al., 2018), the CAMELYON16
challenge, ConvNeXt (Liu et al., 2022) and timm, Grad-CAM
(Selvaraju et al., 2017), and the Mahmood Lab's
UNI and CLAM repositories, whose README conventions this page follows.
Reference
@software{djaalal2026pathos,
author = {Djaalal, Hakim},
title = {Pathos Pro: AI assistance for breast sentinel lymph node metastasis detection},
year = {2026},
url = {https://github.com/Hakim78/histopathologic-cancer-detection}
}
import timm model = timm.create_model("hf-hub:hakim78/Cancer_pathos", pretrained=True)