Downloads · 30 days
0
tmkeating/ConvNeXt-Tiny-Heliobacter-Pylori-Detection
ConvNeXt-Tiny-Heliobacter-Pylori-Detection is a machine learning model from tmkeating. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
This project implements a High-Resolution Multi-Stage MIL Pipeline for the automated detection of H. pylori contamination in histology tissue samples. It features architecture designed to identify sparse bacterium clu…
Downloads · 30 days
0
Access
Public
Updated Jul 2, 2026
Repo size
29.9 GB
Likes
1
Public
Click a slice to open those files.
.pth28.2 GB · 94%
From the Hugging Face model README
This project implements a High-Resolution Multi-Stage MIL Pipeline for the automated detection of H. pylori contamination in histology tissue samples. It features architecture designed to identify sparse bacterium clusters in high-resolution whole-slide imaging, combined with an intelligent Hybrid Ensemble.
Transfer Learning with DeepHP H&E Pre-training (Available for backbone initialization)
The pipeline supports backbone pre-training on the DeepHP dataset (33 experiments, 394,926 H&E-stained histology patches, 120,374 positive / 274,551 negative, ratio 1:2.28) before fine-tuning on the patient-level IHC data from HelicoDataSet (268 patients total: 154 training / 114 holdout; 216,326 IHC-stained histology patches: 128,724 training [62,800 pos / 65,924 neg, ratio 1:1.05] + 87,602 holdout [40,642 pos / 46,960 neg, ratio 1:1.16])
train_deepHP_patches.py - Patch-level training on DeepHP H&E patches with CONFIG 87771 experiment-level stratificationdataset_deepHP.py - DeepHP dataset loader with CONFIG 87771 experiment-level fold splitting (prevents fold-specific artifact learning)domain_adversarial.py - Domain Adversarial Neural Networks (DANN) components for experiment-invariant feature learningload_pretrained_backbone.py - Utilities for loading and averaging backbone weightstrain.py - Added --pretrained_backbone_path argument for loading backbone/home/tkeating/datasets/8117177/ (Positive/ and Negative/ folders)All training scripts automatically verify the virtual environment before execution:
./verify_venv.sh
This script:
venv/) exists and is activatedrequirements.txt to check all dependencies are installedVENV_ROOT for all SLURM scripts to useNote: All 8 SLURM scripts automatically call this verification before submitting jobs, so manual execution is usually not required.
All paths and environment variables are centralized in config.py:
VENV_ROOT: Dynamically computed relative path to project virtual environmentDATASET_ROOT: HelicoDataSet permanent storage locationDEEPHP_DATASET_ROOT: DeepHP dataset locationSCRATCH_ROOT: Local node scratch for temporary training dataRECOMMENDED: Full Transfer Learning Pipeline (DeepHP Pre-training → Backbone Averaging → HelicoDataSet Fine-tuning)
To reproduce the best results, follow this specific execution order:
Run a comprehensive data integrity audit on the permanent HelicoDataSet before syncing to scratch:
Step 1: Identify Duplicates & Generate Blacklist
sbatch submit_duplicates_check.sh
Outputs: global_image_inventory.csv, global_image_duplicates.csv, suggested_blacklist.json - Identifies duplicate patches across folders.
Step 2: Validate Label Consistency & Patient Distribution
python3 verify_data_integrity.py
Outputs: data_integrity_summary.csv - Ensures patient-level labels are consistent across all slides/patches.
Step 3: Verify PNG Count
python3 audit_png_count.py
Outputs: audit_png_count_report.csv - Confirms 216,326 total patches available (128,724 training after blacklist, 87,602 HoldOut).
As part of the recommended full pipeline, audit the DeepHP H&E dataset for duplicates before syncing:
# Check for byte-level duplicates across all 394,926 patches
sbatch submit_duplicates_check_deepHP.sh
# Count PNG patches for verification
python3 audit_png_count_deepHP.py
Outputs:
deephp_image_inventory.csv, deephp_patch_duplicate_audit.csv, suggested_deephp_blacklist.json - Duplicate audit resultsdeephp_audit_report.csv - Class distribution verificationAfter integrity checks pass, sync the vetted datasets to local node storage for performance:
HelicoDataSet Sync (automatic in run_h_pylori.sh):
/home/tkeating/.scratch/h_pylori_data/ using suggested_blacklist.json to exclude problematic patchesDeepHP Sync (automatic in train_deepHP_patches.py):
/home/tkeating/.scratch/h_pylori_data/ using suggested_deephp_blacklist.json if availableLaunch the full transfer learning pipeline (preferred for best accuracy):
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 ./submit_transfer_learning.sh
This script automatically orchestrates:
--use_dann flag
--dann_lambda 1.0 (gradient scaling), --dann_weight 1.0 (loss weighting)--pos_weight parameter (e.g., 1.5)--pos_weight 1.5,1.8,1.6,1.4,1.7submit_train_deepHP.sh to each SLURM jobOutputs: results/*_model_brain.pth (trained models), results/*_patient_consensus.csv (per-fold predictions), results/*_evaluation_report.csv (fold metrics)
Alternative: Training Without Transfer Learning (random initialization) If you want to skip backbone pre-training, run:
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 ./submit_all_folds.sh
This script automatically orchestrates:
Note: This approach trains models from random initialization without pre-trained backbone weights.
Both training pipelines support additional environment variables for fine-tuning DeepHP pre-training behavior:
Per-Fold Positive Class Weights (for class imbalance compensation):
# Use same pos_weight for all folds (default: 1.5)
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 POS_WEIGHT=2.0 ./submit_transfer_learning.sh
# Use fold-specific pos_weights (comma-separated: fold0,fold1,fold2,fold3,fold4)
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 POS_WEIGHT=1.5,1.8,1.6,1.4,1.7 ./submit_transfer_learning.sh
Focal Loss Configuration (for hard example mining):
# Enable Focal Loss with gamma parameter (controls focus on hard examples)
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 USE_FOCAL_LOSS=True GAMMA=3.0 ./submit_transfer_learning.sh
Domain Adversarial Neural Networks (for experiment-invariant features):
# Enable DANN with gradient scaling and loss weighting
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 USE_DANN=True DANN_LAMBDA=1.0 DANN_WEIGHT=0.5 ./submit_transfer_learning.sh
All parameters are automatically propagated to all 5 SLURM training jobs and per-fold threshold calibration.
Both training pipelines (submit_transfer_learning.sh - RECOMMENDED and submit_all_folds.sh - ALTERNATIVE) automatically execute a complete post-processing pipeline after all training folds complete. No manual step required.
The automated post-processing job orchestrates four sequential stages:
Stage 1: calibrate_per_fold_thresholds_deepHP.py (after DeepHP pre-training only)
{run_id}_calibrated_thresholds_deepHP.json with fold-specific thresholds{
"fold_0_threshold": 0.52,
"fold_1_threshold": 0.48,
"fold_2_threshold": 0.55,
"fold_3_threshold": 0.50,
"fold_4_threshold": 0.51
}
Stage 2: apply_calibrated_thresholds_deepHP.py (after DeepHP pre-training only)
Stage 3: ensemble_voting_deepHP.py (after DeepHP pre-training only)
Strategy: F1-Score Weighted Backbone Fusion
After training all 5 folds on DeepHP H&E patches, the backbone weights are combined using a weighted ensemble approach based on per-fold validation F1 scores:
Per-Fold Performance Evaluation
Weight Calculation
weight_fold_i = F1_score_fold_i / sum(F1_scores_all_folds)Weighted Backbone Averaging
θ_ensemble = Σ(weight_i × θ_i) for each fold iAdvantages Over Simple Equal-Weight Averaging
Output
deephp_backbone_final_{run_id}_convnext_tiny_{iter}.pth: F1-weighted averaged backbone ready for transfer learning{run_id}_{iter}_ensemble_weights_f1.json: Per-fold weights used in averaging (for reproducibility)--pretrained_backbone_path argumentRationale: Simple equal-weight averaging assumes all folds contribute equally, but in practice, folds with different experiment distributions may learn at different rates. F1-weighted averaging lets the data speak: folds that better generalize to unseen experiments receive proportionally more weight in the final backbone, resulting in a transfer-learning-ready feature extractor optimized for H. pylori morphology recognition.
Stage 4: ensemble_voting.py (after HelicoDataSet fine-tuning only)
hybrid_ensemble_results_*.csv - Patient predictions with calibrated thresholds and ensemble confidence scoreshybrid_ensemble_summary_*.csv - Clinical metrics (92.11% accuracy, 100% precision, 100% specificity)hybrid_ensemble_roc_pr_*.png - ROC/PR curves with calibrated thresholdshybrid_ensemble_threshold_analysis_*.png - Per-fold threshold optimization visualization{run_id}_{iter}_calibrated_thresholds.json - Per-fold threshold values for reproducibilityensemble_voting_summary_*.csv - Voting ensemble summary metricsmeta_classifier_summary_*.csv - Meta-classifier comparison metricsweighted_ensemble_analysis_*.csv - Fold weights and contribution analysisManual Run (if needed):
For DeepHP Pre-training post-processing:
python3 calibrate_per_fold_thresholds_deepHP.py --run 32
python3 apply_calibrated_thresholds_deepHP.py --run 32
python3 ensemble_voting_deepHP.py --run 32 --strategy f1
For HelicoDataSet Fine-tuning post-processing:
python3 ensemble_voting.py --runs 31_0,31_1,31_2,31_3,31_4 --strategy f1
Generate visual evidence for the model's decisions and patch/patient-level metrics. Grad-CAM visualizations are generated during training, but you can also create supplementary analysis with this script:
sbatch run_visuals.sh
Outputs: results/*_gradcam_samples/ folder containing heatmaps, plus *_confusion_matrix.png, *_roc_curve.png, and *_pr_curve.png metric reports.
When to Run Rescue Inference:
Rescue inference is an optional post-pipeline enhancement for patients where the ensemble voting results warrant deeper inspection. Use it in these scenarios:
Borderline Cases with High Uncertainty
Known False Positives
Known False Negatives
Quality Assurance & Validation
How Rescue Inference Works:
Example: Rescue the Seven Misclassified Patients from Iteration 34
From the ensemble voting report, these 7 patients warrant investigation:
| Patient | True Label | Ensemble Pred | Max Vote | Reason |
|---|---|---|---|---|
| B22-12_1 | Negative | 0.497 | Positive | False Positive (confidence: 0.497) |
| B22-89_0 | Negative | 0.927 | Positive | Strong False Positive (confidence: 0.927) |
| B22-206_0 | Positive | 0.178 | Negative | False Negative (sparse signal) |
| B22-262_0 | Positive | 0.230 | Negative | False Negative (sparse signal) |
| B22-69_1 | Positive | 0.312 | Negative | False Negative (sparse signal) |
| B22-81_1 | Positive | 0.090 | Negative | False Negative (very sparse signal) |
| B22-85_0 | Positive | 0.469 | Borderline | Borderline case (confidence: 0.469) |
Command to Run Rescue:
# Rescue the 7 misclassified patients from a finalResults run
MODEL_DIR="finalResults/convnext_tiny_pretrained_backbone_34.4_weight_1.5_gamma_3.0_focalLoss_false" \
FOLDS="01_34.4_9077_f0 01_34.4_9078_f1 01_34.4_9079_f2 01_34.4_9080_f3 01_34.4_9081_f4" \
TARGETS="B22-12_1,B22-206_0,B22-262_0,B22-69_1,B22-81_1,B22-85_0,B22-89_0" \
OUTPUT_DIR="finalResults/convnext_tiny_pretrained_backbone_34.4_weight_1.5_gamma_3.0_focalLoss_false/rescue_ensemble" \
STRIDE=128 \
sbatch submit_rescue.sh
Interpreting Results:
After rescue completes, examine:
rescue_*.csv files in OUTPUT_DIR containing dense-stride predictionspython3 ensemble_voting.py --runs 34-34
This auto-detects rescue data and merges predictions back into ensemble votingWhen NOT to Use Rescue Inference:
⚠️ METHODOLOGICAL CAVEAT - Holdout Set Reuse:
Rescue inference operates on the same holdout set used for baseline ensemble evaluation. This does NOT violate data integrity (no model retraining, weights frozen) but means you're applying an improved inference strategy to data where you've already seen baseline results:
For final deployment or publication, apply rescue inference to a completely separate held-out test set (never evaluated with baseline) to avoid optimistic bias.
Acceptable current use cases:
For more details, see rescue_inference.py documentation.
config.py: Centralized configuration with dynamic path resolution and environment variable overrides. Defines VENV_ROOT, dataset paths, and scratch directories for portability across systems.dataset.py: Multi-Pass coverage loader with 16-way Contrast-Boosted TTA. Handles live data integrity checks.model.py: Gated Attention MIL with Top-3 Chunk Aggregation for signal resilience.train.py: Unified engine featuring SWA BN Recalibration and Grad-CAM Ghost Audits.generate_visuals.py: Dedicated analysis script to render interpretable visual clinical layouts using Matplotlib cleanly.global_duplicates_check.py: A high-performance byte-level image duplication checker that checks the first 8kb and compares file size for high confidence in results.audit_png_count_report.csv: Ensures that the blacklist is being adhered to.DeepHP Pre-training Post-Processing:
calibrate_per_fold_thresholds_deepHP.py ⭐: Computes per-fold optimal thresholds from DeepHP validation predictions. Output: {run_id}_calibrated_thresholds_deepHP.jsonapply_calibrated_thresholds_deepHP.py ⭐: Applies per-fold calibrated thresholds to DeepHP test predictions.weighted_ensemble_deepHP.py ⭐: Fuses DeepHP predictions from all 5 folds using fold-performance-weighted voting. Generates averaged backbone for transfer learning.HelicoDataSet Fine-tuning Post-Processing:
ensemble_voting.py ⭐: Hybrid Ensemble Fusion for HelicoDataSet predictions combining three methods: (1) Majority Vote Ensemble, (2) Random Forest Meta-Classifier (LOO-CV), (3) Hybrid Ensemble (RECOMMENDED ⭐). Generates final patient-level predictions.profiles.sh: Centralized hyperparameters (Learning rates, Weights, Data paths).To Do
--use_dann flag (default: disabled for faster training).seed = 42 + fold_index), ensuring validation sets are identical across training runs. This enables reliable model comparison and debugging without randomness in fold assignment. For example, Fold 0 always contains the same 20% of data as validation, while Folds 1-4 use their own consistent partitions. Training and validation indices are strictly disjoint with no overlap.config.py support dynamic resolution and environment variable overrides for portability across different systems.torch.amp.GradScaler with automatic device detection instead of deprecated torch.cuda.amp.GradScaler, ensuring forward compatibility with future PyTorch versions.torch.set_float32_matmul_precision('high')./tmp storage sync via run_h_pylori.sh.