Anonymized code release accompanying the submission. This repository reproduces the explanation-faithfulness audit: whether attention and saliency heatmaps from medical Vision-Language Models (VLMs) point to the image evidence a model actually uses, tested against radiologist annotations and causal perturbation.
All author-, institution-, and account-identifying information has been removed for
double-blind review. Absolute paths appear as /path/to/... or read from
environment variables.
scripts/cxr/ # evaluation pipeline
run_counterfactuals.py # 16x16 patch occlusion -> causal-importance maps; ROI-delete; mild-contrast
run_method_vs_occlusion.py # per-method saliency-vs-causal Spearman (raw attn, rollout, grad x attn, Winsor-CAM, integrated_gradients)
run_rise_attribution.py # RISE (model-agnostic perturbation saliency), grid-aligned to the causal map
run_chexagent_roi_grounding.py# CheXagent ROI causal-grounding probe (separate conda env, see below)
run_chexlocalize_eval.py # pixel-mask attribution metrics (pointing-game, AMiM, pixel-AP)
run_densenet_baseline.py # DenseNet121-CXR Grad-CAM positive control
run_resnet_baseline.py # ResNet50-CXR Grad-CAM positive control
run_qwen3_*.py # Qwen3-VL cross-family probe
run_llavarad_*.py # LLaVA-RAD cross-family probe
saliency.py # attribution methods incl. integrated_gradients
data_loaders.py # PadChest, CheXlocalize, VinDr-CXR loaders
constants.py, metrics.py, model_loader.py, roi_masking.py
vlm_explain/ # Winsor-CAM and activation-capture helpers
results/cxr/ # cached outputs that back the paper's numbers (see "Results map")
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
transformers==4.57.transformers==4.40.0
(its modeling code asserts that version). Create it and point the runner at it:
conda create -n chexagent python=3.10 && conda activate chexagent
pip install "transformers==4.40.0" torch albumentations pillow tqdm numpy
CUDA_VISIBLE_DEVICES=0 /path/to/conda/envs/chexagent/bin/python \
scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill gray
Set DATA_ROOT to the directory holding the datasets (default fallbacks point to
${DATA_ROOT}/...). Datasets are obtained from their original sources under their
own licenses:
| Dataset | Access | Use |
|---|---|---|
| MIMIC-CXR | credentialed (PhysioNet) | in-distribution sanity check |
| PadChest | public | bounding-box overlap, causal grounding |
| CheXlocalize | public | pixel-mask attribution |
| VinDr-CXR | public | second annotated grounding dataset |
export DATA_ROOT=/your/datasets
# 1) Patch-occlusion causal maps (PadChest; add --dataset vindr for VinDr-CXR)
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model base
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model targeted_lora
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model full_lora
# 2) Per-method saliency vs causal importance (adds integrated gradients)
python scripts/cxr/run_method_vs_occlusion.py --model base --methods integrated_gradients
# 3) RISE (model-agnostic perturbation saliency)
python scripts/cxr/run_rise_attribution.py --model base --max-samples 200 --n-masks 320
# 4) CheXagent ROI causal-grounding 2x2 (run in the chexagent env, see Setup)
python scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill gray --max-samples 500
python scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill blur --max-samples 300
python scripts/cxr/run_chexagent_roi_grounding.py --dataset vindr --fill gray --max-samples 300
python scripts/cxr/run_chexagent_roi_grounding.py --dataset vindr --fill blur --max-samples 300
# 5) Positive-control classifier baselines (Grad-CAM)
python scripts/cxr/run_densenet_baseline.py
python scripts/cxr/run_resnet_baseline.py
results/cxr/)| Paper claim | File |
|---|---|
| Integrated-gradients Spearman rho (per MedGemma variant) | method_vs_occlusion_ig/<model>/summary.json |
| RISE near-uniform saliency | rise/<model>/summary.json |
| Patch-occlusion causal grounding (PadChest, VinDr) | counterfactuals/<model>[ _vindr]/patch_occlusion/{per_case.jsonl,summary.json} |
| CheXagent ROI grounding 2x2 (dataset x fill) | chexagent_roi_<dataset>[_<fill>]/summary.json |
Per-patch causal-map .npy files are omitted for size; regenerate them with step 1.
results/.../summary.json carries bootstrap 95% confidence intervals (2000 resamples).1 commits
Python
99.4%
Anonymized code release accompanying the submission. This repository reproduces the explanation-faithfulness audit: whether attention and saliency heatmaps from medical Vision-Language Models (VLMs) point to the image evidence a model actually uses, tested against radiologist annotations and causal perturbation.
All author-, institution-, and account-identifying information has been removed for
double-blind review. Absolute paths appear as /path/to/... or read from
environment variables.
scripts/cxr/ # evaluation pipeline
run_counterfactuals.py # 16x16 patch occlusion -> causal-importance maps; ROI-delete; mild-contrast
run_method_vs_occlusion.py # per-method saliency-vs-causal Spearman (raw attn, rollout, grad x attn, Winsor-CAM, integrated_gradients)
run_rise_attribution.py # RISE (model-agnostic perturbation saliency), grid-aligned to the causal map
run_chexagent_roi_grounding.py# CheXagent ROI causal-grounding probe (separate conda env, see below)
run_chexlocalize_eval.py # pixel-mask attribution metrics (pointing-game, AMiM, pixel-AP)
run_densenet_baseline.py # DenseNet121-CXR Grad-CAM positive control
run_resnet_baseline.py # ResNet50-CXR Grad-CAM positive control
run_qwen3_*.py # Qwen3-VL cross-family probe
run_llavarad_*.py # LLaVA-RAD cross-family probe
saliency.py # attribution methods incl. integrated_gradients
data_loaders.py # PadChest, CheXlocalize, VinDr-CXR loaders
constants.py, metrics.py, model_loader.py, roi_masking.py
vlm_explain/ # Winsor-CAM and activation-capture helpers
results/cxr/ # cached outputs that back the paper's numbers (see "Results map")
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
transformers==4.57.transformers==4.40.0
(its modeling code asserts that version). Create it and point the runner at it:
conda create -n chexagent python=3.10 && conda activate chexagent
pip install "transformers==4.40.0" torch albumentations pillow tqdm numpy
CUDA_VISIBLE_DEVICES=0 /path/to/conda/envs/chexagent/bin/python \
scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill gray
Set DATA_ROOT to the directory holding the datasets (default fallbacks point to
${DATA_ROOT}/...). Datasets are obtained from their original sources under their
own licenses:
| Dataset | Access | Use |
|---|---|---|
| MIMIC-CXR | credentialed (PhysioNet) | in-distribution sanity check |
| PadChest | public | bounding-box overlap, causal grounding |
| CheXlocalize | public | pixel-mask attribution |
| VinDr-CXR | public | second annotated grounding dataset |
export DATA_ROOT=/your/datasets
# 1) Patch-occlusion causal maps (PadChest; add --dataset vindr for VinDr-CXR)
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model base
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model targeted_lora
python scripts/cxr/run_counterfactuals.py --mode patch_occlusion --model full_lora
# 2) Per-method saliency vs causal importance (adds integrated gradients)
python scripts/cxr/run_method_vs_occlusion.py --model base --methods integrated_gradients
# 3) RISE (model-agnostic perturbation saliency)
python scripts/cxr/run_rise_attribution.py --model base --max-samples 200 --n-masks 320
# 4) CheXagent ROI causal-grounding 2x2 (run in the chexagent env, see Setup)
python scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill gray --max-samples 500
python scripts/cxr/run_chexagent_roi_grounding.py --dataset padchest --fill blur --max-samples 300
python scripts/cxr/run_chexagent_roi_grounding.py --dataset vindr --fill gray --max-samples 300
python scripts/cxr/run_chexagent_roi_grounding.py --dataset vindr --fill blur --max-samples 300
# 5) Positive-control classifier baselines (Grad-CAM)
python scripts/cxr/run_densenet_baseline.py
python scripts/cxr/run_resnet_baseline.py
results/cxr/)| Paper claim | File |
|---|---|
| Integrated-gradients Spearman rho (per MedGemma variant) | method_vs_occlusion_ig/<model>/summary.json |
| RISE near-uniform saliency | rise/<model>/summary.json |
| Patch-occlusion causal grounding (PadChest, VinDr) | counterfactuals/<model>[ _vindr]/patch_occlusion/{per_case.jsonl,summary.json} |
| CheXagent ROI grounding 2x2 (dataset x fill) | chexagent_roi_<dataset>[_<fill>]/summary.json |
Per-patch causal-map .npy files are omitted for size; regenerate them with step 1.
results/.../summary.json carries bootstrap 95% confidence intervals (2000 resamples).1 commits
Python
99.4%