|
| 1 | +# Experiment: Does weakly-supervised attention recover spatial biology? |
| 2 | + |
| 3 | +**Status:** v2 redesign, revised 2026-07-30. |
| 4 | + |
| 5 | +Corpus is complete: **421/421 human Visium slides** have CTransPath features and |
| 6 | +depth-aware pathway targets (`format_version 3`); H-Optimus-0 features exist for |
| 7 | +the 73 Bowel slides only. Pipeline validated against the published |
| 8 | +HEST-Benchmark. §2 records the v1 assumptions that measurement falsified; §6 |
| 9 | +records why the backbone choice is load-bearing. |
| 10 | + |
| 11 | +**Not yet run:** the model matrix itself. Outstanding build items are in §10. |
| 12 | + |
| 13 | +## 1. The question |
| 14 | + |
| 15 | +> Can a *weakly-supervised* (slide/bag-level) model resolve the **actual |
| 16 | +> spatial distribution of pathway activity** through its attention — and does |
| 17 | +> **direct spatial supervision** improve on this? |
| 18 | +
|
| 19 | +Weakly-supervised pathology models (MIL; SURVPATH for survival) routinely |
| 20 | +visualise attention spatially and argue it highlights the biologically relevant |
| 21 | +regions. None of them could *verify* that claim: they had no spatially-resolved |
| 22 | +ground truth. We do. This connects to the *Attention is/is-not Explanation* |
| 23 | +debate (Jain & Wallace 2019; Wiegreffe & Pinter 2019) by grounding attention |
| 24 | +validity in a biological signal rather than a proxy task. |
| 25 | + |
| 26 | +## 2. What v1 got wrong (measured, not assumed) |
| 27 | + |
| 28 | +Five findings from the review. Each is reproducible via the scripts named. |
| 29 | + |
| 30 | +**(a) The shared component is sequencing depth, not "tissue density."** |
| 31 | +`|r(PC1, log total_counts)| = 0.93` median across slides (0.91 vs genes |
| 32 | +detected). Depth is itself spatially autocorrelated (Moran's I 0.76), which is |
| 33 | +*why* every pathway inherits a high raw Moran's I (~0.61). The old scorer's |
| 34 | +docstring claimed it was "depth-normalised via the prior CP10k step" — CP10k |
| 35 | +fixes the per-spot *total*, but the mean over a gene subset is still driven by |
| 36 | +dropout, so that claim was false. |
| 37 | + |
| 38 | +**(b) PC1 removal is the wrong instrument.** Compared against regressing out |
| 39 | +the *measured* depth covariate: |
| 40 | + |
| 41 | +| | variance destroyed | residual depth correlation | |
| 42 | +| --- | --- | --- | |
| 43 | +| PC1 removal | 63.0% | 0.077 | |
| 44 | +| depth regression | 51.3% | **0.000** | |
| 45 | + |
| 46 | +Depth regression removes the confound completely while preserving ~12 |
| 47 | +percentage points more variance. PC1 is an unsupervised direction that merely |
| 48 | +*correlates* with depth, so it also destroys biology aligned with it — and |
| 49 | +since tumour/stroma tracks cell density tracks depth, that plausibly includes |
| 50 | +the dominant biological axis. |
| 51 | + |
| 52 | +**(c) The v1 headline contrast was close to tautological.** v1 compared |
| 53 | +`stf_dense[prediction]` (a directly supervised dense output) against |
| 54 | +`stf_weak[attention]` (an unsupervised internal mechanism). The supervised |
| 55 | +output was always going to win; that conflates *supervision* with *readout*. |
| 56 | +See §5 for the corrected contrasts. |
| 57 | + |
| 58 | +**(d) Absolute fidelity numbers are uninterpretable on their own.** Three |
| 59 | +distinct quantities must not be conflated: |
| 60 | + |
| 61 | +| quantity | value | meaning | |
| 62 | +| --- | --- | --- | |
| 63 | +| measurement reliability | 0.67 | how well the target reproduces itself (split-half, `measure_target_reliability.py`) | |
| 64 | +| **achievable** | **0.28 within-study / 0.19 cross-study** | what a strong linear baseline reaches (`baseline_pca_ridge.py`, H-Optimus-0) | |
| 65 | +| observed | — | what a given model scores | |
| 66 | + |
| 67 | +Split-half reliability (binomial UMI split, both halves scored, Spearman-Brown |
| 68 | +corrected) is **0.85 for raw maps and 0.67 for depth-residualised maps** — so |
| 69 | +roughly a third of the pathway-specific variance is sampling noise. But |
| 70 | +reliability is an upper bound on *measurement*, not on *predictability from |
| 71 | +morphology*: the achievable figure is far lower. **Normalise reported fidelity |
| 72 | +by achievable, not by reliability**, and quote the baseline alongside every |
| 73 | +model number. |
| 74 | + |
| 75 | +**(e) The selected pathways are ~6 axes, not 14.** Participation ratio 6.1; |
| 76 | +EMT↔MYOGENESIS r=0.78, IFN-γ↔IFN-α r=0.77, E2F↔G2M r=0.64. Averaging over 14 |
| 77 | +as if independent overstates precision. |
| 78 | + |
| 79 | +**Also corrected:** `pathway_morans_i` stored in each `.h5` is the **raw, |
| 80 | +zero-clipped** Moran's I, not the residual — it cannot shortcut pathway |
| 81 | +selection (`scripts/select_residual_pathways.py` recomputes properly). |
| 82 | + |
| 83 | +## 3. Scope: all human Visium, not Bowel-only |
| 84 | + |
| 85 | +v1 used 73 Bowel/Visium slides across 10 studies — 5 of them singletons, with |
| 86 | +COLON MAP at 56% of the corpus. That is structurally underpowered: a two-sided |
| 87 | +Wilcoxon on *n* paired folds cannot return p below 2^-(n-1), so with n<6 folds |
| 88 | +significance is unreachable *regardless of effect size*. |
| 89 | + |
| 90 | +**v2 uses all human Visium: 421 samples, 61 studies, 16 organs.** LOSO becomes |
| 91 | +n=61 (floor ~0), COLON MAP drops to 10% of the corpus, and cross-organ |
| 92 | +generalisation becomes claimable rather than assumed. Acquisition needs 348 |
| 93 | +downloads (~178 GB; storage is not a constraint) via |
| 94 | +`scripts/download_hest_visium.py`, which fetches only `st/` and `patches/` — |
| 95 | +feature extraction reads pre-extracted patches, so the 25 GB of whole-slide |
| 96 | +images per ~95 samples is skipped. |
| 97 | + |
| 98 | +Excluded: Xenium (73), Visium HD (21), Spatial Transcriptomics (163) — different |
| 99 | +chemistries and panels, so pathway-target semantics are not comparable. |
| 100 | + |
| 101 | +## 4. Targets: depth-robust scoring + explicit QC |
| 102 | + |
| 103 | +The v1 target (`mean log1p CP10k over member genes`) is ~65% sequencing depth |
| 104 | +and is not, strictly, "pathway activity" — it is gene-set mean expression. |
| 105 | +p53 activity is post-translational; averaging P53_PATHWAY transcripts does not |
| 106 | +measure it. This is a framing exposure as much as a technical one, and it is |
| 107 | +why PROGENy uses fitted downstream-responsive genes instead of nominal |
| 108 | +membership. |
| 109 | + |
| 110 | +**Decision (revised after tuning, `scripts/tune_aucell.py`): keep the mean |
| 111 | +log1p CP10k score and regress out measured depth. Do not adopt AUCell.** |
| 112 | + |
| 113 | +AUCell was the initial choice because within-spot ranking is depth-robust |
| 114 | +*and* preserves slide-stationarity. Tuning falsified the premise: |
| 115 | + |
| 116 | +| config | depth `\|r\|` | reliability (ceiling) | |
| 117 | +| --- | --- | --- | |
| 118 | +| mean log1p (raw) | 0.751 | — | |
| 119 | +| **mean log1p + depth-regression** | **0.000** | **0.668** | |
| 120 | +| AUCell R=100 (raw) | 0.274 | — | |
| 121 | +| AUCell R=100 + depth-regression | 0.000 | 0.531 | |
| 122 | + |
| 123 | +Depth regression removes the confound *completely*, so AUCell's rank-robustness |
| 124 | +buys nothing while its discarding of magnitude costs 0.14 of ceiling. Switching |
| 125 | +residualisation from PC1 to depth-regression also lifts the ceiling from 0.49 |
| 126 | +to **0.668** on its own — the single largest improvement available here. |
| 127 | + |
| 128 | +**The slide-stationarity objection dissolves under inspection.** The property |
| 129 | +was never actually achieved: median depth varies **83×** across studies and the |
| 130 | +score correlates with depth at 0.93, so identical biology already yields wildly |
| 131 | +different target values on different slides. Per-slide depth regression |
| 132 | +*restores* cross-slide comparability rather than breaking it — and the primary |
| 133 | +metric is within-slide anyway (§7), where per-slide transforms are harmless. |
| 134 | + |
| 135 | +**Tuning also exposed a trap worth recording.** Optimising |
| 136 | +`reliability − depth_leakage` naively selects `max_rank=25`, which looks |
| 137 | +excellent (depth `|r|` 0.09) because **98% of scores are exactly zero and only |
| 138 | +5 of 50 pathways retain any variance** — a near-constant correlates with |
| 139 | +nothing. `tune_aucell.py` now rejects configurations failing a |
| 140 | +non-degeneracy guard (`--min-live-frac`, `--max-frac-zero`). Best *viable* |
| 141 | +AUCell setting was common-universe `max_rank=100` (all 50 pathways live), which |
| 142 | +is what the table above uses. |
| 143 | + |
| 144 | +A second slide-stationarity hazard surfaced en route: HEST gene universes range |
| 145 | +**17,943–36,601** genes, so any *fractional* rank cutoff means a different |
| 146 | +absolute cutoff per slide. Irrelevant now that AUCell is dropped, but it would |
| 147 | +bite any future rank-based scorer. |
| 148 | + |
| 149 | +Remaining requirements: |
| 150 | + |
| 151 | +- **QC-filter on reliability, not just depth.** Slides whose targets barely |
| 152 | + reproduce against themselves contribute noise: MISC69 (607 genes/spot) has |
| 153 | + residual reliability 0.255 vs 0.550 for MISC73. Drop below a preregistered |
| 154 | + threshold. |
| 155 | +- **Apply the residualisation to training targets too**, so training, |
| 156 | + checkpoint selection and evaluation all optimise the same quantity. v1 |
| 157 | + trained and selected on raw targets while grading on the residual, which |
| 158 | + would have made a weak `stf_dense` result ambiguous between "dense |
| 159 | + supervision fails" and "we never optimised for it." |
| 160 | + |
| 161 | +## 5. Design: hold the readout fixed, vary the supervision |
| 162 | + |
| 163 | +The corrected primary contrasts — same readout on both sides, so only |
| 164 | +supervision differs: |
| 165 | + |
| 166 | +| Contrast | Isolates | |
| 167 | +| --- | --- | |
| 168 | +| `stf_dense[attention]` vs `stf_weak[attention]` | **Primary.** Same mechanism, different supervision. | |
| 169 | +| `stf_dense[prediction]` vs `stf_weak[dense-head]` | **Primary.** Same head, different supervision. | |
| 170 | +| `stf_dense[prediction]` vs `stf_weak[attention]` | Reported for continuity with prior work, flagged as readout-confounded. | |
| 171 | + |
| 172 | +Both ingredients were already being computed in v1 — this is a choice-of-contrast |
| 173 | +fix, not new data collection. |
| 174 | + |
| 175 | +## 6. Model matrix |
| 176 | + |
| 177 | +Identical features (**H-Optimus-0**, `--backbone h_optimus_0`), study-grouped |
| 178 | +splits, pathway set, loss and epochs. |
| 179 | + |
| 180 | +**Backbone choice is load-bearing, not incidental.** CTransPath is second-worst |
| 181 | +of the eleven encoders in the HEST-Benchmark, and on this task it is the |
| 182 | +difference between an experiment and a null result: |
| 183 | + |
| 184 | +| backbone | within-study | cross-study (LOSO) | |
| 185 | +| --- | --- | --- | |
| 186 | +| CTransPath | 0.122 | **-0.026** | |
| 187 | +| H-Optimus-0 | **0.280** | **+0.192** | |
| 188 | + |
| 189 | +With CTransPath, cross-study transfer collapses to nothing and every arm of the |
| 190 | +matrix would score ~0 — the study-grouped LOSO protocol of §3 would be |
| 191 | +unrunnable. With H-Optimus-0 cross-study *exceeds* CTransPath's within-study |
| 192 | +figure, so LOSO is viable. UNI / GigaPath / Virchow need institutional access |
| 193 | +and are unavailable; Phikon is reachable but only ~6% better than CTransPath on |
| 194 | +average. **Spatial PE enabled on both STF arms** — the experiment is about |
| 195 | +spatial biology, so a weak-attention result must not be attributable to a |
| 196 | +missing positional encoding; PE-on remains architecture-matched across the pair. |
| 197 | + |
| 198 | +| ID | `--model` | Supervision | Per-pathway signal(s) | |
| 199 | +| --- | --- | --- | --- | |
| 200 | +| `stf_dense` | `interaction` | dense per-spot | dense prediction; pathway→patch attention; gradient saliency | |
| 201 | +| `stf_weak` | `interaction --weak-supervision` | bag | **dense-head output** (never spot-supervised); attention; saliency | |
| 202 | +| `attn_mil` | `attention_mil --weak-supervision` | bag | shared attention (single map); saliency | |
| 203 | +| `transmil` | `transmil --weak-supervision` | bag | shared CLS→patch attention; saliency | |
| 204 | +| `random` | `interaction` (untrained) | — | attribution floor | |
| 205 | + |
| 206 | +MIL shared attention is one map broadcast across pathways, so its flat |
| 207 | +per-pathway profile is a *structural property*, not an empirical finding — |
| 208 | +state it as such. Gradient saliency is what gives MIL a genuinely per-pathway |
| 209 | +map. |
| 210 | + |
| 211 | +## 7. Metric: fidelity as a fraction of the achievable ceiling |
| 212 | + |
| 213 | +Per held-out slide, per pathway, produce an `(N, P)` signal map and compare to |
| 214 | +ground truth: |
| 215 | + |
| 216 | +- **Primary — residual fidelity, reported against the linear baseline:** |
| 217 | + Pearson between depth-residualised signal and depth-residualised truth, quoted |
| 218 | + *alongside* `baseline_pca_ridge.py` run on the identical split (§2d). A model |
| 219 | + scoring 0.19 cross-study has merely matched Ridge; beating it is the claim |
| 220 | + worth making. Split-half reliability is reported as context, not as the |
| 221 | + denominator. |
| 222 | +- **Secondary — raw fidelity**, for comparability with prior work, explicitly |
| 223 | + flagged as depth-inflated. |
| 224 | +- **Report by cluster** (§2e): aggregate within the ~6 empirical pathway |
| 225 | + clusters before averaging, so no axis is counted five times. |
| 226 | +- Per-slide z-scoring before correlating; Spearman alongside Pearson. |
| 227 | +- **Statistics at study level**, paired across held-out studies (n=61). |
| 228 | + |
| 229 | +## 8. Controls |
| 230 | + |
| 231 | +- **Negative:** untrained `random` → fidelity ≈ 0. |
| 232 | +- **Ceiling:** split-half reliability per slide and per pathway. |
| 233 | +- **Sanity:** dense-prediction fidelity must match engine `validate()` |
| 234 | + per-pathway PCC (implemented, agrees to 1.4e-08). |
| 235 | +- **Batch shortcut:** `dataset_title` is 98.5% predictable from CTransPath |
| 236 | + features (vs 60.3% majority baseline), and median depth varies **83×** across |
| 237 | + studies — so "predict depth from H&E" partly reduces to study recognition. |
| 238 | + Study-grouped LOSO handles test leakage but not within-training shortcutting; |
| 239 | + report this alongside results. Note this was measured on CTransPath, and much |
| 240 | + of it appears to be a CTransPath weakness: per-slide feature standardisation |
| 241 | + is essential there (-0.026 → +0.044) but nearly irrelevant for H-Optimus-0 |
| 242 | + (+0.192 → +0.198), whose embeddings are already far more study-invariant. |
| 243 | + Worth re-measuring the shortcut on H-Optimus-0 before quoting it. |
| 244 | +- **Two attributions** (attention + gradient) so conclusions aren't artefacts of |
| 245 | + one explainer. |
| 246 | + |
| 247 | +## 9. Expected outcomes |
| 248 | + |
| 249 | +| Observation | Interpretation | |
| 250 | +| --- | --- | |
| 251 | +| `stf_dense[attention]` ≫ `stf_weak[attention]` | Dense supervision improves the *same* mechanism — supports the thesis. | |
| 252 | +| `stf_dense[attention]` ≈ `stf_weak[attention]` | Attention localises comparably regardless of supervision. | |
| 253 | +| `stf_weak[dense-head]` > 0 | Bag supervision localises implicitly, without spot labels. | |
| 254 | +| All arms ≈ 0 **and** ceiling ≈ 0 | Targets are noise-dominated; report as a measurement-limit result, not a modelling one. | |
| 255 | +| Raw fidelity high, residual ≈ 0 | Model is riding depth, not resolving pathway-specific biology. | |
| 256 | +| Shared-attention MIL flat across pathways | Structural, not empirical (§6). | |
| 257 | + |
| 258 | +## 10. Build status |
| 259 | + |
| 260 | +Reusable from v1: `attribution.py`, dataset-grouped splitting + CLI, |
| 261 | +`evaluate_spatial_attribution.py` (incl. §8 sanity check), |
| 262 | +`run_attribution_experiment.py`, `diagnose_batch_shortcut.py`, tests. |
| 263 | +New in v2: `select_residual_pathways.py`, `measure_target_reliability.py`, |
| 264 | +`download_hest_visium.py`. |
| 265 | + |
| 266 | +Still to build: AUCell scorer in `compute_pathway_activities.py` (with |
| 267 | +`max_rank` tuned per §4 and a `format_version` bump), depth-residualised |
| 268 | +training targets, reliability-normalised metric and cluster aggregation in the |
| 269 | +eval script, and the corrected primary contrasts in the orchestrator. |
| 270 | + |
| 271 | +## 11. Sequencing |
| 272 | + |
| 273 | +1. **Acquire** (running) — 348 human-Visium samples. |
| 274 | +2. **Fix targets on the existing 73** — implement AUCell, tune `max_rank` |
| 275 | + against depth correlation, re-measure reliability. Validate small before |
| 276 | + scaling: recomputing 421 samples with a bad scorer is the expensive mistake. |
| 277 | +3. **Extract features + score pathways** at full scale. |
| 278 | +4. **Pilot** COLON-MAP-vs-rest to validate the pipeline end-to-end. |
| 279 | +5. **Full LOSO** (n=61) for the headline result. |
0 commit comments