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])
- ✅ Backbone initialization from large-scale histology patches instead of random weights
- ✅ Faster convergence on small patient-level dataset (114 patients)
- ✅ Cross-domain feature transfer from H&E patches to IHC domain
- ✅ Reduced overfitting risk with limited IHC training data
- New:
train_deepHP_patches.py- Patch-level training on DeepHP H&E patches with CONFIG 87771 experiment-level stratification - New:
dataset_deepHP.py- DeepHP dataset loader with CONFIG 87771 experiment-level fold splitting (prevents fold-specific artifact learning) - New:
domain_adversarial.py- Domain Adversarial Neural Networks (DANN) components for experiment-invariant feature learning - New:
load_pretrained_backbone.py- Utilities for loading and averaging backbone weights - Modified:
train.py- Added--pretrained_backbone_pathargument for loading backbone - DeepHP Data:
/home/tkeating/datasets/8117177/(Positive/ and Negative/ folders)
All training scripts automatically verify the virtual environment before execution:
./verify_venv.shThis script:
- ✅ Verifies the project virtual environment (
venv/) exists and is activated - ✅ Dynamically reads
requirements.txtto check all dependencies are installed - ✅ Auto-installs missing packages if needed (with error handling)
- ✅ Exports
VENV_ROOTfor all SLURM scripts to use
Note: 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 data- All variables support environment variable overrides for flexibility
RECOMMENDED: 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.shOutputs: 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.pyOutputs: data_integrity_summary.csv - Ensures patient-level labels are consistent across all slides/patches.
Step 3: Verify PNG Count
python3 audit_png_count.pyOutputs: 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.pyOutputs:
deephp_image_inventory.csv,deephp_patch_duplicate_audit.csv,suggested_deephp_blacklist.json- Duplicate audit resultsdeephp_audit_report.csv- Class distribution verification- Result: Verified 394,926 patches, 0 duplicates found
After integrity checks pass, sync the vetted datasets to local node storage for performance:
HelicoDataSet Sync (automatic in run_h_pylori.sh):
- Syncs to
/home/tkeating/.scratch/h_pylori_data/usingsuggested_blacklist.jsonto exclude problematic patches - 128,724 training patches (after blacklist removal) + 87,602 HoldOut patches
DeepHP Sync (automatic in train_deepHP_patches.py):
- Syncs to
/home/tkeating/.scratch/h_pylori_data/usingsuggested_deephp_blacklist.jsonif available - 394,926 clean patches (verified 0 duplicates)
- CONFIG 87771 Stratification: Hardcoded experiment-level 5-fold cross-validation:
- Each of 33 experiments assigned to exactly ONE fold (zero data leakage)
- Fold 0 val: 7 experiments (5 pos, 2 neg) → 85,854 patches, ratio 1:2.33
- Fold 1 val: 10 experiments (8 pos, 2 neg) → 37,093 patches, ratio 1:2.06
- Fold 2 val: 5 experiments (3 pos, 2 neg) → 78,085 patches, ratio 1:2.31
- Fold 3 val: 4 experiments (2 pos, 2 neg) → 78,189 patches, ratio 1:2.29
- Fold 4 val: 7 experiments (3 pos, 4 neg) → 115,704 patches, ratio 1:2.29
- Each fold trains on ALL experiments except its validation experiments (309K-357K patches per fold, maintaining 1:2.27-2.31 class balance)
- Mathematically optimized from 500,000+ greedy configuration searches
- Critical Data Integrity: The Macenko normalization reference patch is automatically excluded from all 5 folds before k-fold assignment (not after), mathematically guaranteeing zero leakage between training and validation sets
Launch the full transfer learning pipeline (preferred for best accuracy):
PROFILE=SEARCHER MODEL_NAME=convnext_tiny ITER=34.0 ./submit_transfer_learning.shThis script automatically orchestrates:
- DeepHP Backbone Pre-training (5-fold CONFIG 87771 stratification on 394,926 H&E patches)
- Uses CONFIG 87771 experiment-level hardcoded stratification from greedy_fold_configs.json
- Each fold validates on unique experiments (prevents fold-specific artifact learning)
- Fold validation sets: 85,854 / 37,093 / 78,085 / 78,189 / 115,704 patches respectively
- Fold validation ratios: 1:2.33 / 1:2.06 / 1:2.31 / 1:2.29 / 1:2.29 (target 1:2.28, total distance 0.6441)
- Fold training sets: 309,071 / 357,832 / 316,840 / 316,736 / 279,221 patches respectively
- All training sets maintain excellent balance: 1:2.27 / 1:2.31 / 1:2.27 / 1:2.28 / 1:2.28 (target 1:2.28)
- Domain Adversarial Neural Networks (DANN): Optionally enabled with
--use_dannflag- Prevents learning of experiment-specific staining artifacts
- Adversary head predicts experiment ID from features → forces experiment-invariant representations
- Gradient reversal layer negates gradients during backprop → confuses adversary
- Parameters:
--dann_lambda 1.0(gradient scaling),--dann_weight 1.0(loss weighting)
- Per-Fold Training Weights (Optional): Support for fold-specific class weighting during training
- By default, all folds use the same
--pos_weightparameter (e.g., 1.5) - For fine-tuning, specify comma-separated per-fold weights:
--pos_weight 1.5,1.8,1.6,1.4,1.7 - Fold 0 trains with pos_weight=1.5, Fold 1 with pos_weight=1.8, etc.
- Use case: Compensate for per-fold class imbalance or fold-specific convergence issues
- Automatically distributed by
submit_train_deepHP.shto each SLURM job - Example: Folds with more negative patches can use higher pos_weight to balance gradient magnitudes
- By default, all folds use the same
- Generates per-fold cross-leakage audits and experiment distribution audit
- Includes automatic Macenko reference image check (creates if missing)
- Applies Macenko stain normalization during DeepHP pre-training
- Runs on login node before SLURM job submission (fast, non-intensive)
- Backbone Averaging (creates unified pre-trained backbone from 5-fold CV)
- HelicoDataSet Fine-tuning (5-fold stratified CV on 114 patients with pre-trained backbone)
- No stain normalization (IHC stains don't use Macenko)
- Automatic venv verification before each phase
Outputs: 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.shThis script automatically orchestrates:
- Pre-sync (syncs HelicoDataSet to scratch)
- 5-Fold Training (trains models on all folds in parallel, initialized randomly)
- Summary & Ensemble Fusion (automatically runs after all folds complete)
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.shFocal 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.shDomain 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.shAll 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)
- Analyzes validation predictions from each of the 5 DeepHP folds
- Computes optimal classification thresholds per-fold that maximize F1 score
- Outputs:
{run_id}_calibrated_thresholds_deepHP.jsonwith fold-specific thresholds - Example output:
{ "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)
- Applies per-fold calibrated thresholds to DeepHP validation predictions
- Converts probability outputs (0-1) to binary decisions (0 or 1)
- Prepares predictions for backbone ensemble fusion
- Outputs: Per-fold predictions with threshold-optimized binary labels
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
- Each fold is evaluated on its validation set (unique experiments not seen during training)
- F1 score computed as: F1 = 2 × (Precision × Recall) / (Precision + Recall)
- F1 score represents the fold's ability to correctly identify H. pylori patches on unseen experiments
- Higher F1 → better fold performance → higher weight in final ensemble
-
Weight Calculation
- Fold weights normalized so they sum to 1.0:
weight_fold_i = F1_score_fold_i / sum(F1_scores_all_folds)
- Example: If fold F1 scores are [0.25, 0.22, 0.28, 0.24, 0.26], weights become [0.25, 0.22, 0.28, 0.24, 0.26]
- Folds with superior validation performance receive proportionally higher influence in the averaged backbone
- Fold weights normalized so they sum to 1.0:
-
Weighted Backbone Averaging
- For each model parameter θ (weights and biases), compute weighted average:
θ_ensemble = Σ(weight_i × θ_i)for each fold i
- Example: ConvNeXt-Tiny backbone has ~28M parameters
- Each parameter averaged across 5 folds, weighted by respective F1 scores
- Result: Unified backbone that captures the best-performing feature extractors from all 5 folds
- For each model parameter θ (weights and biases), compute weighted average:
-
Advantages Over Simple Equal-Weight Averaging
- ✅ Better generalization: Folds with poor validation performance have reduced influence
- ✅ Data-driven optimization: Weights automatically adjust based on actual fold performance
- ✅ Noise reduction: High-variance folds (unstable performance) have lower weight
- ✅ Experiment-robust features: Folds that generalize better to unseen experiments dominate
- ✅ Prevents bad fold contamination: A poorly-trained fold won't degrade final backbone
-
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)- Can be loaded directly into fine-tuning pipeline with
--pretrained_backbone_pathargument - Generates ensemble predictions on validation sets for further analysis
Rationale: 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)
- Fuses patient-level predictions from all 5 HelicoDataSet folds using weighted voting
- Each fold receives weight based on its validation performance (F1 score)
- Higher-performing folds contribute more to final predictions
- Implements three fusion strategies for comparison:
- Majority Voting - Simple majority across 5 folds
- Weighted Average - Fold weights based on validation F1 scores
- Hybrid Ensemble ⭐ (RECOMMENDED) - Intelligent fusion with confidence-based switching:
- High Confidence (>0.95): Uses weighted ensemble
- Uncertainty Zone (0.35-0.55): Uses meta-classifier fallback
- Medium Confidence (0.55-0.95): Blends both methods (60% weighted + 40% meta)
- Outputs: Patient-level predictions with ensemble confidence scores
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 reproducibility
ensemble_voting_summary_*.csv- Voting ensemble summary metricsmeta_classifier_summary_*.csv- Meta-classifier comparison metricsweighted_ensemble_analysis_*.csv- Fold weights and contribution analysis
Manual 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 f1For HelicoDataSet Fine-tuning post-processing:
python3 ensemble_voting.py --runs 31_0,31_1,31_2,31_3,31_4 --strategy f1Generate 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.shOutputs: 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
- Patients with ensemble confidence between 0.35-0.65 (confidence zone where voting ensemble is least decisive)
- Predictions that barely cross the decision threshold (e.g., 0.505 probability when threshold is 0.5)
- Cases where different folds strongly disagree (e.g., 2 folds predict positive, 3 predict negative)
-
Known False Positives
- Patients incorrectly classified as positive (high ensemble score but clinical review suggests negative)
- Faint, irregular signals that may be staining artifacts rather than actual bacteria
- Benefit: Dense-stride (Stride=128) windowing with 50% overlap ensures no sparse bacteria clusters are missed if they do exist
-
Known False Negatives
- Patients incorrectly classified as negative (low ensemble score but clinical review suggests positive)
- Sparse bacterium clusters that may have fallen through the gaps of standard Stride=250 windows
- Benefit: 16-way contrast-boosted TTA (rotations, flips, 1.1x contrast enhancement) can recover faint IHC signals
-
Quality Assurance & Validation
- Verifying difficult-to-diagnose cases before clinical sign-off
- Building secondary evidence for edge cases with borderline pathology
- Computational cost is justified for a small subset of 5-20 priority patients
How Rescue Inference Works:
- Dense-Stride Windowing (Stride=128): Standard inference uses Stride=250 (4-pixel overlap), which can miss very sparse bacterial clusters (5-10 organisms in an entire slide). Rescue uses Stride=128 (50% overlap) to guarantee no bacterium is bisected by a patch boundary.
- 16-Way Contrast-Boosted Test-Time Augmentation (TTA):
- 6 spatial transforms: Original, H-flip, V-flip, 90°, 180°, 270° rotations
- 1.1x contrast boost (targets faint IHC organisms with weak staining)
- Combined transforms (rotations + contrast, flips + contrast)
- All 16 predictions are averaged for consensus voting, reducing noise
- Output: Dense predictions with per-patient scores that can be compared against ensemble baseline
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.shInterpreting Results:
After rescue completes, examine:
rescue_*.csvfiles in OUTPUT_DIR containing dense-stride predictions- Compare rescue predictions against original ensemble scores
- If rescue still predicts negative for false positives → likely staining artifacts
- If rescue now predicts positive for false negatives → sparse bacteria was present but missed
- (Optional) Re-run ensemble voting with rescue data included:
This auto-detects rescue data and merges predictions back into ensemble voting
python3 ensemble_voting.py --runs 34-34
When NOT to Use Rescue Inference:
- Already confident in ensemble predictions (>0.95 or <0.05 confidence scores)
- High false positive rate expected on specific patients (use rescue to differentiate signal vs artifact instead)
- Resource constraints prevent running dense-stride inference (10-20x slower than standard stride)
- Standard clinical workflow requires rapid turnaround (rescue adds 30-60 minutes per patient set)
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:
- ✅ Data Integrity: PRESERVED (no training/test leakage, no model retraining)
⚠️ Generalization Risk: Results may be optimistic for truly new patients beyond the 114 holdout set⚠️ Sequential Testing: You've diagnosed which patients failed, then applied better method to same data
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:
- Post-hoc clinical analysis and troubleshooting
- Research ablations demonstrating inference technique improvements
- Quality assurance deep-dives on specific borderline 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
- CONFIG 87771 Stratification (DeepHP Pre-training): Hardcoded experiment-level 5-fold cross-validation optimized from 500,000+ greedy configuration searches. Each of 33 experiments assigned to exactly ONE fold, preventing data leakage and fold-specific artifact learning. Folds validate on different experiments (85.9K / 37.1K / 78.1K / 78.2K / 115.7K patches) with balanced ratios (1:2.06 to 1:2.33, target 1:2.28, total distance 0.6441). All training sets maintain excellent balance (1:2.27-2.31 ratio) across all folds.
- Domain Adversarial Neural Networks (DANN - Optional): Advanced technique for DeepHP pre-training that prevents models from learning experiment-specific staining artifacts. Adversary head predicts experiment ID from features while gradient reversal layer forces the backbone to ignore experiment signals. Result: experiment-invariant representations that generalize across different H&E staining protocols and scanners. Enable with
--use_dannflag (default: disabled for faster training). - Deterministic Validation Sets (Reproducible Cross-Validation): All folds use stratified k-fold splitting with fixed random seeds (
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. - Macenko Stain Normalization: Applied exclusively during DeepHP H&E pre-training to normalize color variations across different staining protocols and tissue scanners, improving backbone generalization. Reference image is automatically created/verified on login node before training starts.
- Proactive Environment Verification: All scripts verify virtual environment dependencies before SLURM job submission, preventing runtime failures with early, actionable error messages.
- Centralized Configuration: All paths and environment variables in
config.pysupport dynamic resolution and environment variable overrides for portability across different systems. - Stride-128 Rescue Pass: Dense-window overlap to "catch" sparse bacteria that fall in gaps at default strides.
- Top-3 Mixed MIL: Balances sensitivity with noise resilience by averaging the top 3 most confident tissue chunks.
- Contrast-Boosted TTA: 16-way transforms (8 spatial + 1.25x contrast jitter) to "pop" faint IHC signals.
- Modern PyTorch API: Uses current
torch.amp.GradScalerwith automatic device detection instead of deprecatedtorch.cuda.amp.GradScaler, ensuring forward compatibility with future PyTorch versions. - Per-Fold Threshold Calibration (Post-Processing): After training all 5 folds, each fold's validation predictions are analyzed to compute optimal classification thresholds that maximize F1 score. These per-fold thresholds are then applied to test predictions before ensemble fusion, improving decision boundary quality and eliminating unnecessary false positives.
- Weighted Ensemble Voting (Post-Processing): Combines predictions from all 5 folds using fold-performance-weighted voting. Folds with higher validation F1 scores receive greater weight, ensuring the most reliable folds contribute more to the final patient-level decision. This hierarchical confidence weighting significantly improves robustness and generalization.
- Hybrid Ensemble Strategy: Intelligently fuses predictions using three parallel methods:
- High Confidence Zone (>0.95): Uses weighted ensemble voting
- Uncertainty Zone (0.35-0.55): Uses meta-classifier fallback for difficult cases
- Medium Confidence (0.55-0.95): Intelligently blends both methods (60% ensemble + 40% meta)
- Compute: Optimized for NVIDIA L40S/A40/A100 (48GB/80GB).
- Precision:
torch.set_float32_matmul_precision('high'). - Data Locality: Automated node-local
/tmpstorage sync viarun_h_pylori.sh.