Award: https://www.youtube.com/live/b7zUINbHg14?si=S2vh_or8GvM80QNH&t=2296 Website: https://surca.wsu.edu/
Reproducible research pipeline for measuring shortcut-learning susceptibility in computational pathology by injecting a synthetic color-border cue and tracking how strongly models rely on it over training.
This public repository is intended to expose the runnable toolkit, documentation, and data-preparation helpers. Large datasets, generated outputs, caches, previews, and draft-only internal writing are intentionally excluded from version control.
- Trains binary image classifiers on histopathology datasets with optional class-correlated border cues.
- Evaluates each checkpoint on three aligned test variants:
- clean
- matched cue
- flipped cue
- Logs per-epoch shortcut-emergence metrics and final per-condition summaries.
- Computes shortcut risk scores from emergence speed and final reliance strength.
- Produces plots, including a dataset x model risk heatmap and a speed-vs-strength decomposition chart.
Create a Python environment and install the dependencies from requirements.txt.
Example on Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txtExample on macOS or Linux:
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txtRegistered datasets:
CRCMHISTDHMC
Supported models:
resnet18efficientnet_b0googlenetdensenet121convnext_tiny
Current shortcut metrics assume binary classification.
Each dataset should be prepared in ImageFolder format:
dataset_root/
train/
class0/
class1/
val/
class0/
class1/
test/
class0/
class1/
Default roots come from the dataset registry:
CRC -> crc_binary/MHIST -> mhist_binary/DHMC -> dhmc_binary/
Use --dataset_root to override the default path.
- Run one condition at a time for a chosen dataset/model/mitigation.
- Let each run append to
output/experiment_results.csvandoutput/emergence_curves.csv. - Compute shortcut risk scores with
python score_risks.py. - Generate plots and the final heatmap with
python -m shortcut_audit.plotting.plot_results.
This is the recommended workflow when you want to run models and datasets independently, then combine everything later into a single heatmap.
Pipeline summary:
run_experiment.pyis the root CLI entry point and forwards intoshortcut_audit.experiments.run_experiment.- The experiment orchestrator resolves dataset/model settings, optional sweep mode, and output locations.
shortcut_audit.training.injection_crcis the current shared training engine for all registered binary datasets.- Training writes one final-row table (
experiment_results.csv) and one per-epoch table (emergence_curves.csv). score_risks.pyconverts final-run metrics intorisk_scores.csvandrisk_summary.csv.shortcut_audit.plotting.plot_resultsreads the experiment and scoring CSVs and writes figures intooutput/plots/.
Verify the CLI is available:
python run_experiment.py --helpRun one baseline condition:
python run_experiment.py --dataset CRC --model resnet18Run MHIST with an explicit dataset root:
python run_experiment.py --dataset MHIST --dataset_root mhist_binary --model googlenetPrepare MHIST into ImageFolder format before running:
python .data_prep/prepare_mhist_binary.py --images_dir /path/to/mhist/images --annotations /path/to/annotations.csv --out_dir mhist_binary --overwriteThe MHIST prep helper expects binary labels HP and SSA in the annotation file and will raise a clear error if you accidentally point it at a different dataset.
Run DHMC using the default registered root:
python run_experiment.py --dataset DHMC --model resnet18Run a quick smoke test:
python run_experiment.py --dataset CRC --model resnet18 --smoke --skip_preview --no_checkpointsThat smoke run performs a short 2-epoch validation pass and is the recommended first command to confirm your environment, dataset layout, and model-loading path are working.
Quick MHIST smoke tests after preparation:
python run_experiment.py --dataset MHIST --dataset_root mhist_binary --model resnet18 --epochs 1 --max_samples_per_split 32 --batch_size 8 --num_workers 0 --skip_preview --no_checkpoints
python run_experiment.py --dataset MHIST --dataset_root mhist_binary --model googlenet --epochs 1 --max_samples_per_split 32 --batch_size 8 --num_workers 0 --skip_preview --no_checkpointsCompute risk scores from accumulated runs:
python score_risks.pyIf no results CSV exists yet, the scorer exits cleanly with a message instead of failing.
Generate plots and heatmaps:
python -m shortcut_audit.plotting.plot_resultsIf no experiment CSVs exist yet, the plotting command exits cleanly after reporting that there is nothing to plot.
Core run selection:
--dataset: dataset key. Choices areCRC,MHIST, andDHMC.--dataset_root: optional path override for the prepared dataset.--model: model name. Choices areresnet18,efficientnet_b0,googlenet,densenet121,convnext_tiny.--mitigation: mitigation key. Current options arebaseline,augmentation,label_smoothing,mixup,strong_weight_decay.
Shortcut injection controls:
--p_train: probability of injecting the cue into each training image.--border_width: reference border width in pixels.--alpha: cue blend strength.--seed: training seed.--seed_test: test cue seed. Defaults to the training seed if omitted.
Runtime controls:
--epochs: override default epoch count.--batch_size: override batch size.--lr: override learning rate.--num_workers: override dataloader workers.--max_samples_per_split: optional cap per split for faster debug runs.--smoke: shorthand for a 2-epoch, 500-samples-per-split validation run with checkpoints disabled.
Output controls:
--results_path: final per-condition CSV. Defaultoutput/experiment_results.csv.--emergence_path: per-epoch CSV. Defaultoutput/emergence_curves.csv.--checkpoint_dir: where best/final checkpoints are written. Defaultoutput/checkpoints.--preview_dir: where preview images are written. Defaultpreviews.--skip_preview: skip preview image generation.--no_checkpoints: do not save best/final checkpoint files.--cluster_safe_outputs: write intooutput/jobs/<job_tag>/...instead of the shared output files.--job_tag: explicit per-job tag for--cluster_safe_outputs. Defaults to a SLURM job id when available, otherwisejob_local.
Sweep controls:
--full_grid: run the built-in grid over datasets, mitigations, models, widths, seeds, andp_train.--datasets: optional dataset subset to use with--full_grid.
Single baseline run:
python run_experiment.py --dataset CRC --model resnet18 --mitigation baseline --p_train 0.25Independent run for one model-dataset pair:
python run_experiment.py --dataset MHIST --model googlenet --mitigation mixup --p_train 0.5 --seed 1Custom output paths for incremental collection:
python run_experiment.py --dataset CRC --model resnet18 --results_path output/experiment_results.csv --emergence_path output/emergence_curves.csvLow-cost debugging run:
python run_experiment.py --dataset CRC --model resnet18 --epochs 1 --max_samples_per_split 64 --batch_size 32 --num_workers 0 --skip_preview --no_checkpointsFull sweep across all registered datasets:
python run_experiment.py --full_gridFull sweep for a subset of datasets:
python run_experiment.py --full_grid --datasets CRC MHISTPrimary run outputs:
output/experiment_results.csv- one final row per completed condition
- includes metadata, clean/matched/flipped metrics,
SET,susceptibility_slope, andAURC
output/emergence_curves.csv- one row per epoch per run
- includes emergence dynamics such as
flip_rate,delta_flip_auc,prob_shift, andcue_effect_size
output/checkpoints/- best and final checkpoints unless
--no_checkpointsis used
- best and final checkpoints unless
previews/- example clean/matched/flipped images unless
--skip_previewis used
- example clean/matched/flipped images unless
Risk scoring outputs:
output/risk_scores.csv- per-run scored table with
speed_score,strength_score, andrisk_score
- per-run scored table with
output/risk_summary.csv- dataset-level and model-level aggregates
Plot outputs are written to output/plots/.
If --cluster_safe_outputs is enabled, the same files are written under output/jobs/<job_tag>/ instead of the shared top-level output paths.
If you want the final dataset x model risk heatmap:
- Run whichever dataset/model/mitigation conditions you want, independently and in any order.
- Keep appending to the shared results CSVs.
- Run
python score_risks.py. - Run
python -m shortcut_audit.plotting.plot_results. - Open
output/plots/risk_heatmap_dataset_x_model.png.
Related output:
output/plots/risk_decomposition_speed_vs_strength.png
- Training, cue sampling, and dataloader shuffle are seeded.
- Matched and flipped test variants are aligned sample-by-sample.
- If the same
run_nameis written multiple times, scoring and plotting keep the latest row for that run to avoid duplicate-counting. score_risks.pywill fall back to the legacy fileoutput/results_crc_border.csvifoutput/experiment_results.csvdoes not exist yet.
docs/PROJECT_DETAILS.md: methodology, metrics, scoring, and experiment behaviordocs/REPO_GUIDE.md: file/folder guide and practical usage flowdocs/CHANGELOG.md: implementation-focused change history
run_experiment.py- thin root wrapper for the experiment CLI
score_risks.py- thin root wrapper for risk scoring
shortcut_audit/data/dataset_registry.py- dataset registry and default roots
shortcut_audit/models/model_registry.py- model construction and pretrained-weight handling
shortcut_audit/injectors/border_injector.py- synthetic border cue injection utilities
shortcut_audit/training/injection_crc.py- current end-to-end training and evaluation engine
shortcut_audit/scoring/risk_scorer.py- risk-score computation and summary aggregation
shortcut_audit/plotting/plot_results.py- plotting and heatmap generation