Download 53_embed_check.py from Pathstudy/fourmodal-pathology-bind: direct link, hf CLI and curl.
- Browser
- Download file 8.06 kB
-
https://huggingface.co/Pathstudy/fourmodal-pathology-bind/resolve/main/53_embed_check.py
- Command line
-
hf download hf://Pathstudy/fourmodal-pathology-bind/53_embed_check.py
-
curl -L -o 53_embed_check.py https://huggingface.co/Pathstudy/fourmodal-pathology-bind/resolve/main/53_embed_check.py
8.06 kB
| """Check embed.py from RAW inputs (pixels, strings, counts) against the cached training features and the fold-0 test. | |
| .venv/bin/python -I 53_embed_check.py [n] (n = items per raw check, default 300) | |
| 1. feature reproduction: embed.py raw-input encoders vs the cached features the model was trained / tested on | |
| (per-item cosine of the raw encoder features), for every encoder: | |
| H&E UNI2 + MedVTok ORION tiles (PNG), TCGA/PathGen patches (PNG), HEST spot crops (cache/hest/he_img.npy) | |
| text KEEP / BiomedCLIP / Qwen3 TCGA real captions (alltxt) | |
| RNA hvg / Tahoe-x1 / SE-600M / AIDO.Cell HEST spots (rna_sets.load('hest') rows) | |
| mIF VirTues (all 3187 ORION tiles: standardisation statistics are per slide / per dataset) | |
| 2. end-to-end: models/ej_ad_mv_fold0 on held-out fold-0 test items, embeddings from raw inputs vs from cached | |
| features (same items, g100 R@1) | |
| Output results/embed_check.csv | |
| """ | |
| import os | |
| import sys | |
| import time | |
| import numpy as np | |
| import pandas as pd | |
| import torch | |
| ROOT = os.path.dirname(os.path.abspath(__file__)) | |
| sys.path.insert(0, ROOT) | |
| from common import CACHE, ORION, load_all_tiles # noqa: E402 | |
| from embed import MIF_MARKERS, RNA_E, TXT_E, Embedder # noqa: E402 | |
| N = int(sys.argv[1]) if len(sys.argv) > 1 else 300 | |
| MD = os.path.join(ROOT, "models", "ej_ad_mv_fold0") | |
| E = Embedder(MD) | |
| TI = np.load(os.path.join(MD, "test_items.npz")) | |
| rng = np.random.default_rng(0) | |
| rows, t0 = [], time.time() | |
| f32 = lambda a: np.asarray(a, np.float32) | |
| def cos(a, b): | |
| a, b = torch.as_tensor(f32(a)), torch.as_tensor(f32(b)) | |
| return torch.nn.functional.cosine_similarity(a, b, dim=-1).numpy() | |
| def report(mod, enc, src, c): | |
| rows.append({"check": "features", "modality": mod, "encoder": enc, "source": src, "n": len(c), | |
| "cos_median": float(np.median(c)), "cos_min": float(c.min())}) | |
| print(f"[{time.time() - t0:.0f}s] {mod:5s} {enc:11s} {src:14s} n={len(c)} cos median {np.median(c):.4f} min {c.min():.4f}", | |
| flush=True) | |
| def r1_g100(a, b, seed=0): | |
| a, b = torch.nn.functional.normalize(a, dim=-1), torch.nn.functional.normalize(b, dim=-1) | |
| g = np.random.default_rng(seed) | |
| out = [] | |
| for _ in range(50): | |
| s = torch.from_numpy(g.choice(len(a), min(100, len(a)), replace=False)) | |
| S = a[s] @ b[s].T; d = S.diag() | |
| out.append((((S > d[:, None]).sum(1) == 0).float().mean() + ((S.T > d[:, None]).sum(1) == 0).float().mean()).item() / 2) | |
| return float(np.mean(out)) | |
| # ------------------------------------------------------------------ H&E | |
| tiles = load_all_tiles() | |
| ot = rng.choice(TI["orion"], min(N, len(TI["orion"])), replace=False) | |
| U, M = E.he_feats([os.path.join(ORION, p) for p in tiles.image_path.values[ot]]) | |
| report("H&E", "uni2", "ORION", cos(U, np.load(os.path.join(CACHE, "he_uni2.npy"), mmap_mode="r")[ot, 0])) | |
| report("H&E", "medvtok", "ORION", cos(M, np.load(os.path.join(CACHE, "he_medvtok.npy"), mmap_mode="r")[ot, 0])) | |
| he_raw = {"orion": (ot, U, M)} | |
| I = pd.read_csv(os.path.join(CACHE, "allimg_meta.csv")) | |
| tt_img = rng.choice(len(TI["tcga_img"]), min(N, len(TI["tcga_img"])), replace=False) | |
| ti = TI["tcga_img"][tt_img] | |
| U, M = E.he_feats(I.image_path.values[ti]) | |
| report("H&E", "uni2", "TCGA/PathGen", cos(U, np.load(os.path.join(CACHE, "allimg_he_uni2.npy"), mmap_mode="r")[ti, 0])) | |
| report("H&E", "medvtok", "TCGA/PathGen", cos(M, np.load(os.path.join(CACHE, "allimg_he_medvtok.npy"), mmap_mode="r")[ti, 0])) | |
| he_raw["tcga"] = (tt_img, U, M) | |
| hsp = rng.choice(TI["hest"], min(N, len(TI["hest"])), replace=False) | |
| U, M = E.he_feats(np.load(os.path.join(CACHE, "hest", "he_img.npy"), mmap_mode="r")[hsp]) | |
| report("H&E", "uni2", "HEST", cos(U, np.load(os.path.join(CACHE, "hest", "he_uni2.npy"), mmap_mode="r")[hsp, 0])) | |
| report("H&E", "medvtok", "HEST", cos(M, np.load(os.path.join(CACHE, "hest", "he_medvtok.npy"), mmap_mode="r")[hsp, 0])) | |
| he_raw["hest"] = (hsp, U, M) | |
| E.release() | |
| # ------------------------------------------------------------------ text | |
| T = pd.read_csv(os.path.join(CACHE, "alltxt_meta.csv")) | |
| txt_ids = TI["tcga_txt"][tt_img] # the captions paired with the TCGA test images above | |
| Ft = E.text_feats(T.caption.fillna("").astype(str).values[txt_ids].tolist()) | |
| for e in TXT_E: | |
| report("text", e, "TCGA captions", cos(Ft[e], np.load(os.path.join(CACHE, f"alltxt_text_{e}.npy"), mmap_mode="r")[txt_ids, 0])) | |
| E.release() | |
| # ------------------------------------------------------------------ RNA | |
| from rna_sets import load # noqa: E402 | |
| Xh, genes = load("hest") | |
| Fr = E.rna_feats(Xh[hsp], genes) | |
| for e in RNA_E: | |
| ref = (np.load(os.path.join(CACHE, "hest", "hvg.npy"), mmap_mode="r") if e == "hvg" else | |
| np.load(os.path.join(CACHE, "rnafm", f"{e}_hest.npy"), mmap_mode="r"))[hsp] | |
| report("RNA", e, "HEST", cos(Fr[e], ref)) | |
| E.release() | |
| # ------------------------------------------------------------------ mIF (whole ORION set: dataset-level standardisation) | |
| class LazyIF: | |
| """(N, 16, 333, 333) ORION mIF tiles read on demand (uint8 tifs, 17 channels -> MIF_MARKERS)""" | |
| def __init__(self, df): | |
| import tifffile | |
| self.paths, self.rd = [os.path.join(ORION, p) for p in df.target_path], tifffile.imread | |
| V = E._get("virtues")[0] | |
| names = [m for m, _ in V.MARKERS] | |
| self.ch = [names.index(m) for m in MIF_MARKERS] | |
| def __len__(self): | |
| return len(self.paths) | |
| def __getitem__(self, s): | |
| return np.stack([self.rd(p)[..., self.ch].transpose(2, 0, 1) for p in self.paths[s]]) | |
| Fm = E.mif_feats(LazyIF(tiles), tiles.in_slide_name.values) | |
| report("mIF", "virtues", "ORION (all)", cos(Fm, np.load(os.path.join(CACHE, "if_virtues_m16.npy"), mmap_mode="r")[:, 0])) | |
| E.release() | |
| # ------------------------------------------------------------------ end-to-end on held-out fold-0 test items | |
| UO, MO = np.load(os.path.join(CACHE, "he_uni2.npy"), mmap_mode="r"), np.load(os.path.join(CACHE, "he_medvtok.npy"), mmap_mode="r") | |
| IFc = np.load(os.path.join(CACHE, "if_virtues_m16.npy"), mmap_mode="r") | |
| ot, U, M = he_raw["orion"] | |
| e2e = {"H&E<->mIF (ORION)": ((E.he_from_feats(U, M), E.mif_from_feats(Fm[ot])), | |
| (E.he_from_feats(UO[ot, 0], MO[ot, 0]), E.mif_from_feats(IFc[ot, 0])))} | |
| hsp, U, M = he_raw["hest"] | |
| ref_r = {e: (np.load(os.path.join(CACHE, "hest", "hvg.npy"), mmap_mode="r") if e == "hvg" else | |
| np.load(os.path.join(CACHE, "rnafm", f"{e}_hest.npy"), mmap_mode="r"))[hsp] for e in RNA_E} | |
| e2e["H&E<->RNA (HEST)"] = ((E.he_from_feats(U, M), E.rna_from_feats(Fr)), | |
| (E.he_from_feats(np.load(os.path.join(CACHE, "hest", "he_uni2.npy"), mmap_mode="r")[hsp, 0], | |
| np.load(os.path.join(CACHE, "hest", "he_medvtok.npy"), mmap_mode="r")[hsp, 0]), | |
| E.rna_from_feats(ref_r))) | |
| _, U, M = he_raw["tcga"] | |
| ref_t = {e: np.load(os.path.join(CACHE, f"alltxt_text_{e}.npy"), mmap_mode="r")[txt_ids, 0] for e in TXT_E} | |
| e2e["H&E<->text (TCGA)"] = ((E.he_from_feats(U, M), E.text_from_feats(Ft)), | |
| (E.he_from_feats(np.load(os.path.join(CACHE, "allimg_he_uni2.npy"), mmap_mode="r")[ti, 0], | |
| np.load(os.path.join(CACHE, "allimg_he_medvtok.npy"), mmap_mode="r")[ti, 0]), | |
| E.text_from_feats(ref_t))) | |
| for pair, v in e2e.items(): | |
| (a_raw, b_raw), (a_c, b_c) = v | |
| rows.append({"check": "end-to-end", "modality": pair, "n": len(a_raw), "R@1_raw": r1_g100(a_raw, b_raw), | |
| "R@1_cached": r1_g100(a_c, b_c), "emb_cos_median_a": float(np.median(cos(a_raw, a_c))), | |
| "emb_cos_median_b": float(np.median(cos(b_raw, b_c)))}) | |
| print(f"{pair:20s} n={len(a_raw)} g100 R@1 raw-input {rows[-1]['R@1_raw']:.3f} | cached features " | |
| f"{rows[-1]['R@1_cached']:.3f}; embedding cos median {rows[-1]['emb_cos_median_a']:.4f} / " | |
| f"{rows[-1]['emb_cos_median_b']:.4f}", flush=True) | |
| pd.DataFrame(rows).to_csv(os.path.join(ROOT, "results", "embed_check.csv"), index=False) | |
| print(f"done [{time.time() - t0:.0f}s]") | |