四模态病理嵌入模型(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 依次执行:

  1. 下载特征仓库,得到 cache/ 和 splits/,共约 1.1 GB。
  2. evaluate_saved.py:用已发布的 fold-0 模型在留出测试集上重算结果,必须和 models/ej_ad_mv_fold0/test.csv 完全一致。
  3. 从特征重新训练 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 的容差就是按这个设的。
  4. 重新训练发布版模型,输出到 models/repro_release/。
  5. 加 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  图文报告
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support