四模态病理嵌入模型(H&E · mIF · RNA · 文本)
这个模型把四种模态嵌入到同一个 1536 维空间里:
- H&E 图像;
- mIF:多重免疫荧光,即蛋白;
- RNA:空间转录组 spot 表达;
- 病理文本。
做法和 ImageBind 一样。冻结的 UNI2-h 图像空间是锚点,其余每种模态只和 H&E 配对训练。mIF↔RNA、mIF↔文本、文本↔RNA 之间的对齐是"涌现"出来的,没有直接训练过。
- 训练数据: 只用真实的配对数据。
- 评估数据: 虚拟数据和合成数据只用于评估,从不参与训练。
| 内容 | 位置 |
|---|---|
| 发布版模型 | models/ej_ad_mv/ |
| fold-0 模型(带留出测试集) | models/ej_ad_mv_fold0/ |
| 推理接口 | embed.py |
| 训练 | 52_final_model.py |
| 训练用的编码器特征和数据划分 | 私有数据集仓库 Pathstudy/fourmodal-pathology-features |
| 图文报告 | report/fourmodal_report.html |
| 全部实验记录 | RESULTS.md |
1. 数据
没有任何数据集同时测量了全部四种模态,所以每种模态各用一个和 H&E 配对的真实数据集。
| 数据集 | 配对 | 规模 | 用途 |
|---|---|---|---|
| ORION CRC(1% 图块子集) | H&E – mIF(17 通道,使用 16 个标记) | 3,187 个 333×333 图块,约 40 名病人 | 训练 + 测试 |
| HEST-1k Visium | H&E – RNA(14,802 基因) | 9,484 spots,57 项研究,16 个器官 | 训练 + 测试 |
| TCGA / PathGen-1.6M | H&E – 文本 | 6,144 张图像,6,115 条清洗后的描述 | 训练 + 测试 |
| STPath 虚拟 RNA / MIPHEI 虚拟 mIF / GPT 合成描述 | 给没有真实配对的模态对构建测试集 | ORION、TCGA 测试图块 | 只用于测试 |
| DLPFC(spatialLIBD,脑) | H&E – RNA | 482 spots,3 名供体 | 外部测试 |
- 划分: 按病人划分 train/val/test。HEST 按研究划分,病人分组见
splits/。做 5 折交叉验证。 - 验证集: val 只用于早停,所有报告的数字都是 test 上的。
- 虚拟模态的校准: 每种虚拟模态先在同一批有真实数据的样本上校准,即用虚拟数据替换真实数据,看配对结果能否接近。
| 虚拟模态 | 校准结果(真实 → 虚拟) | 结论 |
|---|---|---|
| STPath 虚拟 RNA | 0.148 → 0.126 | 可用 |
| GPT 合成描述 | 0.219 → 0.162 | 可用,偏保守 |
| MIPHEI 虚拟 mIF | 配对准确率 0.92 → 0.55 | 可用 |
| GigaTIME 虚拟 mIF | 0.644 → 0.038 | 不可用,已弃用 |
2. 最佳架构:EJ-ad+MV(两阶段,3 种子适配器平均)
H&E ──► UNI2-h (frozen, 1536) ───────────────┬──────────────► (+) ──► z_HE
└► MedVTok (frozen, 1152) ─► Adapter×3 ◄┘ (zero-init, mean of 3 seeds) ┐
mIF ──► VirTues (16 markers, 512) ─► MLP head ─────────────────────► z_mIF │ 1536-d
RNA ──► hvg · Tahoe-x1 · SE-600M · AIDO.Cell ─► 4 linear heads ─► fuse ─► z_RNA │ shared
text ──► KEEP · BiomedCLIP · Qwen3-Emb-0.6B ─► 3 linear heads ─► fuse ─► z_text ┘ space
第一阶段:每个编码器一个映射头。
- 每个映射头用 InfoNCE 对齐到冻结的 UNI2 CLS 特征。
- 文本用多正样本 InfoNCE:同一张图像的多条文本都算正样本。
- RNA 和文本是后期融合:
z = normalise(Σ_e normalise(head_e(x_e)))。
第二阶段:只训练 H&E 一侧。
- 冻结所有映射头,只训练一个零初始化的残差适配器:
H&E = UNI2 + mean_s A_s([UNI2, c·MedVTok])。 - 损失:三种配对的 InfoNCE 之和,加上对 UNI2 相似度结构的蒸馏(λ=1)。
- 优化:AdamW,学习率 1e-4,1000 步,OneCycle 学习率调度。
- 选择规则:每个种子按验证集上三种 R@1 的几何平均早停,再把 3 个种子的适配器残差取平均。
为什么这样设计: mIF、RNA、文本的嵌入和第一阶段完全一样,所以涌现配对不受第二阶段影响,只有 H&E 这一侧变好。以下结论都来自 5 折配对检验,详见 RESULTS.md:
| 设计选择 | 依据 |
|---|---|
| UNI2-h 做锚点 | 在任何训练配对上都没有被显著超过。GigaPath 在 RNA 上低 0.035;CONCH 在 H&E↔mIF 上低 0.155;MedVTok 当锚点在 H&E↔RNA 上只有 0.131(UNI2 是 0.192)。 |
| 多编码器后期融合 | 最大的单项提升:H&E↔RNA +0.037,H&E↔文本 +0.062,4 个涌现配对全部提升(5/5 折)。拼接(早期融合)和单编码器多种子平均都达不到这个效果。 |
| 只动 H&E 侧的联合训练 | 共享 H&E 头会让涌现配对损失 26–74%;只训练残差适配器时,H&E↔mIF 提升 0.10,涌现配对完全不变。 |
| MedVTok 作为额外输入 | H&E↔mIF +0.015,H&E↔文本 +0.016。换成同尺寸的 UNI2 随机投影没有提升。 |
| 3 种子平均 | 单次早停的步数在 100–900 步之间波动,同一设置重跑 H&E↔mIF 可以差 0.05。3 个种子平均后,H&E↔文本再提高 0.015(5/5 折,p=0.02)。 |
| RNA 和文本用线性头 | 训练配对持平,涌现配对 +5%。mIF 保留 MLP 头。 |
| 编码器挑选 | RNA:4 个编码器融合(+0.037)接近 10 个融合(+0.044)。文本:3 个融合(0.299)接近 5 个融合(0.303)。mIF:VirTues 的跨模态迁移比从头训练的 CNN 好得多。 |
3. 结果(5 折测试集均值,100 个样本的检索库,随机水平 R@1 = 0.01)
| 配对 | 类型 | R@1 | R@10 | 配对准确率 |
|---|---|---|---|---|
| H&E ↔ mIF(ORION) | 训练 | 0.801 ± 0.043 | 0.991 | 0.942 |
| H&E ↔ RNA(HEST) | 训练 | 0.203 ± 0.033 | 0.625 | 0.258 |
| H&E ↔ 文本(TCGA) | 训练 | 0.323 ± 0.007 | 0.813 | 0.347 |
| mIF ↔ RNA(虚拟) | 涌现 | 0.141 ± 0.007 | 0.657 | 0.194 |
| mIF ↔ 文本(合成) | 涌现 | 0.089 ± 0.008 | 0.491 | 0.104 |
| 文本 ↔ RNA(虚拟) | 涌现 | 0.095 ± 0.006 | 0.436 | 0.100 |
| 文本 ↔ mIF(MIPHEI 虚拟) | 涌现 | 0.046 ± 0.005 | 0.271 | 0.051 |
| H&E ↔ RNA(DLPFC 脑,外部) | 外部 | 0.012 | 0.112 | 0.012 |
各阶段的提升见下表(训练配对 R@1,5 折均值)。逐折结果在 results/final_cv_long.csv,各阶段的完整比较在 results/medvtok_*.csv、results/joint_ens_*.csv。
| 阶段 | H&E↔mIF | H&E↔RNA | H&E↔文本 |
|---|---|---|---|
| 单编码器(S4) | 0.675 | 0.155 | 0.236 |
| 多编码器融合(E,第一阶段) | 0.675 | 0.192 | 0.299 |
| + H&E 适配器 | 0.776 | 0.201 | 0.299 |
| + MedVTok | 0.792 | 0.200 | 0.315 |
| 最终(3 种子平均) | 0.801 | 0.203 | 0.323 |
4. 使用方法
环境:Python 3.11 和一块 CUDA GPU。依赖见 requirements.txt。所有脚本都用 python -I 运行。
pip install -r requirements.txt
用预先算好的编码器特征(不需要任何冻结编码器):
from embed import Embedder
E = Embedder("models/ej_ad_mv")
z_he = E.he_from_feats(uni2_feats, medvtok_feats) # (N,1536) / (N,1152)
z_mif = E.mif_from_feats(virtues_feats) # (N,512)
z_rna = E.rna_from_feats({"hvg": X, "tahoex1": X, "se600m": X, "aidocell": X})
z_text = E.text_from_feats({"keep": X, "biomedclip": X, "qwen3-0.6b": X})
sim = z_he @ z_mif.T # 输出都是 L2 归一化的 (N, 1536) CPU tensor
用原始输入。需要先运行 bash setup_encoders.sh 下载第三方代码和权重。UNI2-h 是受限仓库,需要账号有访问权限,或者设置 UNI2_PATH。
z = E.he(images) # PIL 图像列表或 (N,H,W,3) uint8;约 0.5 µm/px,视野 112–166 µm
z = E.text(["Tumor cells with ...", ...])
z = E.rna(counts, genes) # 原始计数(spots × genes),HGNC 基因名
z = E.mif(tiles, slide) # (N,16,H,W) 8 位强度,通道顺序为 embed.MIF_MARKERS,每个图块附 slide id
注意:
- mIF 标准化: 统计量是在一次调用给定的全部图块上计算的,所以请一次传入整张切片或整个数据集。
- 新平台的 RNA 数据: 建议用
zscore="self",并且一次至少传入几百个 spots。
5. 复现(已验证:从 HF 下载到全新目录 + 全新虚拟环境)
PYTHON=python bash reproduce.sh # 约 20 分钟(单卡 RTX A5000)
RAW=1 PYTHON=python bash reproduce.sh # 再加上原始输入检查(需要先运行 setup_encoders.sh)
reproduce.sh 依次执行:
- 下载特征仓库,得到
cache/和splits/,共约 1.1 GB。 evaluate_saved.py:用已发布的 fold-0 模型在留出测试集上重算结果,必须和models/ej_ad_mv_fold0/test.csv完全一致。- 从特征重新训练 fold 0 和 5 折交叉验证,然后用
compare_reproduction.py和已发布的数字对比。- 在相同硬件和相同依赖版本下,结果逐位一致。2026-10-28 在 RTX A5000 上用全新的
requirements.txt环境验证:fold 0 和 5 折的全部配对差值都是 0。 - 换 GPU 或库版本时,第二阶段(H&E 适配器)可能在种子波动范围内变化,约 ±0.01;
compare_reproduction.py的容差就是按这个设的。
- 在相同硬件和相同依赖版本下,结果逐位一致。2026-10-28 在 RTX A5000 上用全新的
- 重新训练发布版模型,输出到
models/repro_release/。 - 加
RAW=1时运行example_check.py:把examples/(每个数据集 64 个 fold-0 测试样本)的原始输入送进embed.py,检查编码器特征和缓存特征是否一致,再检查检索结果。
已发布的结果不会被覆盖:复现的输出写到 repro_* 名下。
6. 局限
- 外部泛化差: 脑组织 DLPFC 上处于随机水平。训练用的 HEST 里脑组织也只有 R@1 0.021。所以模型只适用于训练数据覆盖过的组织类型。
- H&E↔文本的 MedVTok 增益可能偏高: MedVTok 预训练时见过 PathGen 的图像,包括我们 TCGA 测试集的图像(只有图像,没有文本)。ORION 上的 mIF 增益不受影响。
- 涌现配对的数值偏保守: 涌现配对的一侧是虚拟或合成数据,所以这些数值是保守估计。
- 实例级涌现对齐仍然弱: mIF↔RNA 只有 0.141。概念级的对齐(AUROC 0.6–0.7)更可靠。
7. 许可证
只能用于非商业研究。 本仓库的权重是在以下冻结编码器的特征上训练的,使用时需要分别遵守它们的许可:
| 编码器 | 许可 |
|---|---|
| UNI2-h | CC-BY-NC-ND,受限访问 |
| MedVTok | MIT;它对齐的 CONCH v1.5 是 CC-BY-NC-ND |
| SE-600M、AIDO.Cell | 非商业 |
| Tahoe-x1 | Apache-2.0 |
| VirTues、KEEP、BiomedCLIP | MIT |
| Qwen3-Embedding | Apache-2.0 |
数据本身也有各自的条款,见各数据集的原始发布:ORION、HEST-1k(CC-BY-NC-SA)、TCGA、PathGen-1.6M、spatialLIBD。
8. 文件
embed.py 推理接口 (Bind4 模型 + Embedder)
52_final_model.py 训练 (cv / fold0 / release)
evaluate_saved.py 特征级评估 (fold-0 测试, 与 test.csv 完全一致)
example_check.py 原始输入端到端检查 (examples/)
reproduce.sh, compare_reproduction.py, setup_encoders.sh, requirements.txt
14_ 43_ 45_ 45b_ 50_ *.py, biomedclip_text.py, common.py, rna_sets.py 冻结编码器的特征提取 (embed.py 调用)
53_embed_check.py, 54_make_examples.py 在完整原始数据上做的检查 / 生成 examples/ (需要原始数据集)
models/ ej_ad_mv (发布版), ej_ad_mv_fold0 (+ test.csv, test_items.npz)
results/ 所有实验的 csv 结果
experiments/ 01_–51_ 全部实验脚本 (记录用; 依赖原始数据, 不在本仓库)
RESULTS.md 完整实验记录; report/fourmodal_report.html 图文报告