PathoCNN β PathMNIST colorectal histology classifier
A compact CNN (288,809 parameters), designed and trained from scratch for 9-class classification of 28Γ28 H&E colorectal histology patches, released with something most model uploads don't have: a script that re-derives every headline metric from the shipped weights and data, so the numbers below are checkable, not just claimed.
- Test accuracy 0.8712 and macro one-vs-rest AUC 0.9855 on the PathMNIST test split (7,180 patches), vs a 0.1864 majority-class baseline β independently reproduced from the artifacts in this repo on 2026-10-28 (see Verify it yourself).
- The test split is CRC-VAL-HE-7K, collected at a different clinical center than the training data β so these numbers include a real cross-center generalization gap (validation accuracy on same-center data was 0.9629). That gap is part of the result, not a footnote.
- Weights in three formats:
model.safetensors, the training checkpoint (assets/pathocnn.pt), and ONNX (pathocnn.onnx, parity vs PyTorch measured at 5.7e-06 max logit difference). - Trained from scratch by Habib Ur Rehman; sibling release to SonoCNN (BreastMNIST).
Research and benchmark use only. This is a 28Γ28 benchmark model. It is not a medical device, it has never been evaluated on clinical whole-slide data, and it must not be used for diagnosis or screening.
Verified results β PathMNIST test split (CRC-VAL-HE-7K, n = 7,180)
| Metric | Value | Source |
|---|---|---|
| Accuracy | 0.8712 (6,255/7,180) | reproduced 2026-10-28 |
| AUC (macro, one-vs-rest) | 0.9855 | reproduced 2026-10-28 |
| Balanced accuracy | 0.8251 | reproduced 2026-10-28 |
| Majority-class baseline | 0.1864 | reproduced 2026-10-28 |
| Best validation accuracy | 0.9629 (epoch 11) | recorded at training time |
| Best validation AUC | 0.9987 | recorded at training time |
Per-class recall on the test split (all reproduced):
| Class | Recall | Class | Recall | |
|---|---|---|---|---|
| adipose | 0.9477 | smooth muscle | 0.7348 | |
| background | 1.0000 | normal colon mucosa | 0.8516 | |
| debris | 0.7817 | cancer-associated stroma | 0.3848 | |
| lymphocytes | 0.9101 | colorectal adenocarcinoma epithelium | 0.9667 | |
| mucus | 0.8483 |
Read the weak row honestly: the model largely fails on cancer-associated stroma β it recalls only 162 of 421 stroma patches, and reads 155 of them as debris. Debris is the model's error sink: debris precision is just 0.4417, meaning most "debris" predictions are wrong (they are mostly stroma and smooth muscle). The clinically most important class, adenocarcinoma epithelium, is also the best detected (recall 0.9667). Accuracy's 95% confidence interval on 7,180 patches is roughly Β±0.8 points (β0.863β0.879). The full 9Γ9 confusion matrix and per-class precision are in assets/evaluation_results.json; the training-time record is in assets/pathocnn_metrics.json; they agree exactly on every headline number.
Context, not a claim of parity: the MedMNIST v2 paper's reference ResNet-18 (11.7M parameters, ~40Γ larger) reports 0.907 accuracy / 0.983 AUC on this split, and ResNet-50 reports 0.911 / 0.990. PathoCNN's AUC sits in that band; its accuracy trails by ~3.6 points, which is the price of the small model and shows up almost entirely in the stroma/debris/muscle confusions above.
Quickstart
pip install "git+https://github.com/habib-analyst/pathocnn.git"
from pathocnn import load_model, predict
model = load_model("model.safetensors") # or assets/pathocnn.pt
result = predict(model, "assets/demo_samples/8_colorectal_adenocarcinoma_epithelium.png")
# {'label': 'colorectal adenocarcinoma epithelium', 'confidence': 0.999,
# 'probabilities': {...9 classes...}}
Preprocessing contract (identical to training): RGB β resize to 28Γ28 if needed β /255 β normalize per channel with the PathMNIST train-split mean/std ([0.74055, 0.53298, 0.70583] / [0.12368, 0.17676, 0.12443]). Labels are the MedMNIST v2 PathMNIST order 0β8 (see config.json).
ONNX: pathocnn.onnx takes the same normalized (N, 3, 28, 28) float tensor and returns logits.
Verify it yourself
python examples/verify_metrics.py
This re-evaluates the shipped weights on the bundled test split (assets/pathmnist_test.npz) and compares against the training-time metrics file. On 2026-10-28 it printed ALL HEADLINE METRICS REPRODUCED β accuracy, AUC, the full confusion matrix, and every per-class recall matched exactly. One protocol warning the script and training code both encode: the train-split normalization statistics must be computed with chunked float64 accumulation. A single float32 NumPy reduction over ~90k images silently returns wrong channel means on this dataset (measured: 0.23778 for every channel instead of 0.74055/0.53298/0.70583) β the kind of silent error that makes "reproductions" fail for reasons nobody can see.
python examples/predict_demo.py # one patch per class + first misclassifications
python -m pytest -q # 8 tests: formats agree, metrics files agree, parity
The demo is honest about the weak spot: of the nine first-of-class test patches, seven are classified correctly, and the two misses β smooth muscle and cancer-associated stroma β are both confidently read as debris (95.4% and 99.7%). The demo prints them, and the test suite pins them.
Model details
- Architecture: 3 conv blocks (32β64β128 channels, BatchNorm, ReLU, max-pool, dropout) + 2-layer MLP head, designed for this release in the same compact family as SonoCNN. 288,809 trainable parameters; 1.2 MB in safetensors.
- Training: from scratch on the PathMNIST train split (89,996 patches), 12 epochs, AdamW (lr 2e-3, weight decay 1e-4, OneCycle cosine schedule), batch 256, plain cross-entropy (the train split's max/min class ratio is 1.63, so no class weighting), seed 42, checkpoint selected by best validation accuracy (epoch 11 of 12). Training took 1,990 s (~33 min) on a 2-core CPU. The exact script is
examples/train.py. - Augmentation: random dihedral transforms (90Β° rotations and flips) on the training split only. Histology patches have no canonical orientation, so the full D4 group is label-preserving here. No color jitter β H&E stain color carries class signal and was left alone.
What PathoCNN is not
- Not a clinical tool. It classifies 28Γ28 benchmark patches, not whole slides or patients, and its weakest class (cancer-associated stroma, 38.5% recall) is a tissue type a real workflow cares about. The cross-center drop from 0.9629 (validation) to 0.8712 (test) is what domain shift does to small models; expect worse on any other center.
- Not state of the art. Larger reference models score ~0.91 accuracy on this split. This release exists because its numbers are verified and its failure modes are documented, not because it tops a leaderboard.
- Not trained on private or clinical data. Only the public PathMNIST benchmark (below).
- Confidences are not calibrated. Softmax outputs are frequently extreme (several demo patches score a rounded 100.0%), including on the confidently-wrong stromaβdebris errors. Treat them as rankings, not probabilities of being right.
Data and attribution
PathMNIST is part of MedMNIST v2 (Yang et al., MedMNIST v2 β A large-scale lightweight benchmark for 2D and 3D biomedical image classification, Scientific Data 2023). It derives from the NCT-CRC-HE-100K dataset of 100,000 H&E histology patches (Kather et al., 2019), split 9:1 into train/validation, with CRC-VAL-HE-7K as the external-center test set. The dataset is licensed CC BY 4.0; assets/pathmnist_test.npz (the official test split only) is redistributed here for metric reproduction, with attribution. The source file used for training is Zenodo record 10519652, md5 a8b06965200029087d5bd730944a56c1. The MIT license of this repository covers the code and the trained weights, not the dataset.
Files
| File | Contents |
|---|---|
model.safetensors |
Release weights (safetensors) |
pathocnn.onnx |
ONNX export (logits) |
config.json |
Architecture + preprocessing config |
src/pathocnn/ |
model.py (architecture), infer.py (loading + prediction API) |
examples/train.py |
The exact training script that produced the weights |
examples/predict_demo.py |
Per-class demo + first misclassifications, printed honestly |
examples/verify_metrics.py |
Full metric reproduction from the artifacts |
assets/pathocnn.pt |
Training checkpoint (state dict + training record) |
assets/pathocnn_metrics.json |
Training-time metrics record |
assets/evaluation_results.json |
Independently reproduced metrics (2026-10-28) |
assets/pathmnist_test.npz |
PathMNIST official test split (CC BY 4.0, see attribution) |
assets/demo_samples/ |
First test patch of each class (28Γ28 PNGs) |
License
MIT for code and weights (see LICENSE). Dataset under CC BY 4.0 as above.
- Downloads last month
- 105