File size: 3,690 Bytes
9a5439c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | """Synthetic captions (27_azure_caption.py, GPT, 3-shot PathGen style) -> per-set meta for 08_extract_text.py.
VALIDATION ONLY: these texts are never used to train any head.
Output cache/orion_gentext_meta.csv (row i = ORION tile_id i of load_all_tiles(); `caption` column)
"""
import json
import os
import pandas as pd
from common import CACHE, load_all_tiles
C = pd.DataFrame([json.loads(l) for l in open(os.path.join(CACHE, "gen_text", "captions.jsonl"))])
C = C[(C.set == "orion") & C.caption.notna() & (C.caption.str.len() > 0)].drop_duplicates("path", keep="last")
cap = dict(zip(C.path.map(os.path.basename), C.caption))
df = load_all_tiles()
df["caption"] = df.image_path.map(lambda p: cap.get(os.path.basename(p)))
print(f"ORION tiles {len(df)}, with synthetic caption {df.caption.notna().sum()}")
assert df.caption.notna().all(), "missing captions -> rerun 27_azure_caption.py (resumable)"
df[["tile_id", "image_path", "caption"]].to_csv(os.path.join(CACHE, "orion_gentext_meta.csv"), index=False)
# TCGA calibration set (27_ --sets tcga_calib): synthetic captions of patches that also have REAL text
A = pd.DataFrame([json.loads(l) for l in open(os.path.join(CACHE, "gen_text", "captions.jsonl"))])
A = A[(A.set == "tcga_calib") & A.caption.notna()].drop_duplicates("path", keep="last")
if len(A):
I = pd.read_csv(os.path.join(CACHE, "allimg_meta.csv"))
shots = [s["key"][:12] for s in json.load(open(os.path.join(CACHE, "gen_text", "prompt.json")))["shots"]]
A["img_idx"] = A.path.map(dict(zip(I.image_path, I.index)))
A = A[A.img_idx.notna() & ~A.img_idx.map(lambda i: I.patient[int(i)] in shots)] # drop few-shot patients
A["img_idx"] = A.img_idx.astype(int)
A[["img_idx", "path", "caption"]].reset_index(drop=True).to_csv(os.path.join(CACHE, "tcga_calib_meta.csv"), index_label="idx")
print(f"TCGA calibration captions: {len(A)} (few-shot patients excluded: {shots})")
# external test sets (27_ --sets dlpfc idc): row i = row i of cache/external/<set>_meta.csv
for st in ("dlpfc", "idc"):
X = pd.DataFrame([json.loads(l) for l in open(os.path.join(CACHE, "gen_text", "captions.jsonl"))])
X = X[(X.set == st) & X.caption.notna() & (X.caption.str.len() > 0)].drop_duplicates("key", keep="last")
if not len(X):
continue
n = len(pd.read_csv(os.path.join(CACHE, "external", f"{st}_meta.csv")))
cap = dict(zip(X.path.str.split(":").str[2].astype(int), X.caption))
out = pd.DataFrame({"row": range(n), "caption": [cap.get(i) for i in range(n)]})
print(f"{st}: {n} spots, with synthetic caption {out.caption.notna().sum()}")
assert out.caption.notna().all(), "missing captions -> rerun 27_azure_caption.py --sets dlpfc idc (resumable)"
out.to_csv(os.path.join(CACHE, f"{st}_gentext_meta.csv"), index=False)
# TCGA images without real text after junk removal (40_clean_text.py; 27_ --sets tcga_notext). A caption made for
# the same image under another set (tcga_calib) is reused. Row i of the output = row i of notext_meta.csv.
N = pd.read_csv(os.path.join(CACHE, "notext_meta.csv"))
X = pd.DataFrame([json.loads(l) for l in open(os.path.join(CACHE, "gen_text", "captions.jsonl"))])
X = X[X.caption.notna() & (X.caption.str.len() > 0)].drop_duplicates("path", keep="last")
cap = dict(zip(X.path.map(os.path.abspath), X.caption))
N["caption"] = N.image_path.map(lambda p: cap.get(os.path.abspath(p)))
print(f"TCGA no-text images {len(N)}, with synthetic caption {N.caption.notna().sum()}")
assert N.caption.notna().all(), "missing captions -> rerun 27_azure_caption.py --sets tcga_notext"
N[["img_idx", "image_path", "patient", "caption"]].to_csv(os.path.join(CACHE, "tcga_notext_meta.csv"), index=False)
|