文章目录
-
- ✅ 空间转录组测序方式总体划分
- 🧬 成像型空间转录组(Imaging-based ST)
- 🧬 测序型空间转录组(Sequencing-based ST)
- 📊 成像型 vs 测序型空间转录组对比表
- ✅ 回到你问的 SpatialHuman30M 构建策略理解:
- 🎯 总结你的问题:
- ✅ ① **Neighborhood Enrichment Analysis:空间邻近富集分析**
- ✅ ② **Graph-based tissue segmentation:STAGATE 空间聚类方法**
- ✅ ③ **Spatial Autocorrelation (Moran's I):空间自相关性分析**
- 🎯 三者之间的关系总结图
- ✅ 总结对照表
- ✅ 按照“数据流动顺序”重新完整讲解模型预训练流程(函数+结构)
- ✅ 你的理解核心是正确的:
- ✅ 所以你说的结论完全正确:
非常好的问题!你提到的 SpatialHuman30M 数据集中采用了两大类空间转录组技术:成像型(imaging-based) 和 测序型(sequencing-based)。这是目前空间转录组研究中最核心的技术划分之一。
下面我会系统总结这两种方式的原理差异、技术代表、优缺点对比,并结合你列出的 Xenium、MERFISH、Visium、Visium HD 来分别讲解它们的技术特点与使用意义。
✅ 空间转录组测序方式总体划分
分类 | 成像型空间转录组 | 测序型空间转录组 |
---|---|---|
代表技术 | MERFISH, Xenium, seqFISH, CosMx | 10x Visium, Visium HD, Slide-seq |
数据获取方式 | 通过荧光成像识别RNA分子在组织切片中的位置 | 通过高通量测序读取转录本并结合位置条码还原空间分布 |
主要原理 | 原位杂交(FISH) + 图像识别 | 条码探针(barcode)定位 + RNA捕获 + RNA-seq |
🧬 成像型空间转录组(Imaging-based ST)
原理:
直接在组织切片上,通过荧光探针原位杂交(FISH),结合高分辨率显微成像,将每个mRNA分子精确定位到单细胞甚至亚细胞水平。
技术代表 & 特点:
技术 | 特点 |
---|---|
MERFISH | 基于多轮次荧光杂交编码,检测数百到数千个基因;精度高,分辨率达亚细胞级,空间结构精准 |
Xenium(10x Genomics) | 最新成像平台,支持 400+ 目标转录本检测,支持FFPE样本,兼具通量与空间分辨率 |
CosMx(NanoString) | 支持 RNA + 蛋白同时空间成像,适合细胞间互作分析 |
优点:
- 🔍 单细胞/亚细胞级别的精度
- 🔬 保留完整组织结构,可分辨组织微环境
- ✅ 非破坏性检测,适合组织病理配合分析
局限:
- ⚠️ 探针数目有限(目标基因型,数百到几千个)
- 💰 成本高、流程复杂、图像处理计算量大
- 🧪 不支持全转录组检测
🧬 测序型空间转录组(Sequencing-based ST)
原理:
将组织切片放置在带有空间条码探针的芯片(如Visium)上,通过位置条码捕获组织中的mRNA,然后提取RNA进行高通量测序,将表达谱回推至空间位置。
技术代表 & 特点:
技术 | 特点 |
---|---|
Visium | 主流平台,基于 55 μm 大小 spot,支持全转录组测序,空间分辨率中等 |
Visium HD | 10x 最新升级版,spot 缩小至 <5μm,空间分辨率接近单细胞 |
Slide-seqV2 | 用珠子阵列实现 10μm 分辨率的全转录组捕获,数据稀疏度高 |
优点:
- 🧬 全转录组覆盖(不限制目标基因)
- 🚀 通量高,支持大组织切片或批量样本处理
- 💰 成本相对较低,适合大规模Atlas构建
局限:
- 🧭 分辨率有限(Visium为spot级,通常包括多个细胞)
- ❌ 需组织穿透处理,会影响某些组织结构
- 🔬 需要计算反卷积来恢复单细胞信息
📊 成像型 vs 测序型空间转录组对比表
比较维度 | Imaging-based(如Xenium, MERFISH) | Sequencing-based(如Visium) |
---|---|---|
空间分辨率 | ✅ 高(单细胞甚至亚细胞) | ⚠️ 中(Visium为55μm spot) |
检测通量 | ⚠️ 中(几百-几千基因) | ✅ 高(全转录组) |
成本 | 高 | 较低 |
适合用途 | 精细结构、生物互作验证 | Atlas构建、基因发现、区域表达 |
数据类型 | 图像 + 表达矩阵 | 表达矩阵 + 空间坐标 |
分析难度 | 图像分割复杂 | 表达建模复杂(需反卷积) |
✅ 回到你问的 SpatialHuman30M 构建策略理解:
技术 | 占比 | 使用目的 |
---|---|---|
Xenium (48%) | 大量使用,兼顾成像和商业可及性 | 在多个器官中精确定位细胞类型,用于组织微结构标注 |
MERFISH (40%) | 大规模精细标注 epithelial/免疫细胞位置 | 用作细胞互作、高保真空间验证 |
Visium/HD (12%) | 虽占比低,但是全转录组 backbone | 提供组织级表达图谱,是反卷积训练和标注核心来源 |
🎯 总结你的问题:
问题 | 答案 |
---|---|
为什么有成像和测序两类? | 因为两者各有优势:成像精准但通量低,测序全景但分辨率低,互补 |
Xenium和MERFISH的特点? | 都是成像型技术,分辨率极高,适合做cell type定位和组织微结构分析 |
Visium为什么也被使用? | 它是最成熟的测序型 ST平台,虽然分辨率不高,但可用于构建全器官转录组表达Atlas,是基础“骨架”数据 |
如果你需要,我可以:
- 提供成像型 ST(如MERFISH)数据的常用预处理/空间配准/细胞分割流程
- 帮你设计一个用于反卷积训练的 ST数据整合策略(多平台混合训练)
- 或进一步分析 SpatialHuman30M 的样本分布与器官组织编码结构
是否继续?
A spatially resolved single-cell genomic atlas of the adult human breast 文章总结
你对空间结构分析部分的关注非常精准!这是目前空间组学中最具研究潜力的方向之一 —— 如何从表达数据中识别出组织结构与细胞互作的“空间逻辑”。下面我将围绕你关心的三项方法:
① Neighborhood enrichment analysis
② Graph-based tissue segmentation (STAGATE)
③ Spatial autocorrelation (Moran’s I)
进行详细解释,每一项都结合论文原文使用情况 + 原理 + 应用效果,帮助你建立空间建模完整认知。
✅ ① Neighborhood Enrichment Analysis:空间邻近富集分析
🔍 方法目标:
识别不同细胞类型是否在组织切片中有特定的共定位模式,即:谁跟谁经常靠在一起?
🧠 背后原理:
- 基于 smFISH/CODEX 空间坐标数据,每个细胞都有(x, y)位置和 cell type。
- 统计某一细胞类型A周围的细胞类型B是否显著富集(与随机分布相比)。
- 利用 permutation test 或 Monte Carlo 模拟进行显著性检验。
📘 文章中怎么用的?
在 Fig. 3 中,作者使用该方法分析:
- 哪些细胞类型具有共生关系(如 LumSec 常与 CD4+ T cell 相邻)
- 哪些细胞类型具有互斥关系(如 fibroblast 避开免疫细胞)
原文:
“To investigate potential cell–cell interactions, we performed neighborhood enrichment analysis using spatial coordinates of smFISH-identified cells…”
📌 应用意义:
应用 | 举例 |
---|---|
构建组织微环境图谱 | 发现免疫细胞聚集区域、上皮细胞嵌套结构 |
指导功能研究 | 识别免疫抑制区、旁分泌调控热点 |
增强空间反卷积可信度 | 如果某类细胞总是一起出现,可以作为结构先验 |
✅ ② Graph-based tissue segmentation:STAGATE 空间聚类方法
🔍 方法目标:
让ST表达数据不只是表达上的聚类,还能融合空间邻接信息,实现空间感知的组织分割。
🧠 背后原理:
- 每个 spot 看作图节点,构建空间图(邻接spot用边连接)。
- 表达数据作为节点特征。
- 利用图神经网络(Graph Attention Network),在聚类前对节点进行空间感知的特征更新。
- 最终聚类不仅表达相似,还空间上连续。
工具名为:STAGATE
论文来源:Nature Communications, 2022
📘 文章中怎么用的?
- 用于分析ST数据形成的组织区域,如导管、腺泡、结缔组织等。
- 与 scRNA-seq 无需直接匹配,作为一种组织层级结构提取方法。
- 对多个患者样本进行对齐后比较。
原文:
“We applied STAGATE to identify spatially coherent clusters that corresponded to histological regions across breast tissue…”
📌 应用意义:
应用 | 说明 |
---|---|
提取组织功能模块 | 比如识别出整个腺泡区域 vs 免疫侵润区域 |
为反卷积提供区域先验 | Cluster 1可能是腺泡样结构,反卷积时只考虑上皮细胞亚型 |
跨样本组织结构对齐 | 多个患者的乳腺结构自动识别,便于meta分析 |
✅ ③ Spatial Autocorrelation (Moran’s I):空间自相关性分析
🔍 方法目标:
判断某个基因的表达在空间中是否“成片状”集中,还是“随机分布”。
🧠 背后原理:
- 每个 spot 是一个地理点,某个基因在这些点上的表达值是变量。
- 计算Moran’s I 系数(类似于空间版的 Pearson 相关):
I = N W ⋅ ∑ i ∑ j w i j ( x i − x ˉ ) ( x j − x ˉ ) ∑ i ( x i − x ˉ ) 2 I = \frac{N}{W} \cdot \frac{\sum_{i}\sum_{j} w_{ij}(x_i - \bar{x})(x_j - \bar{x})}{\sum_{i}(x_i - \bar{x})^2} I=WN⋅∑i(xi−xˉ)2∑i∑jwij(xi−xˉ)(xj−xˉ)
其中 w i j w_{ij} wij 是邻接矩阵, x i x_i xi 是表达值。
- I > 0 表示空间上聚集;I ≈ 0 表示无空间结构;I < 0 表示互斥分布。
📘 文章中怎么用的?
- 在 ST 数据中对每个基因计算 Moran’s I 值。
- 识别出具有空间特异性表达模式的关键基因。
原文:
“We applied spatial autocorrelation analysis (Moran’s I) to the ST data to identify genes with spatially coherent expression patterns…”
📌 应用意义:
应用 | 举例 |
---|---|
找到“空间 marker gene” | 比如某基因只在导管边缘表达,提示其结构功能作用 |
增强空间聚类可信度 | 可以作为 STAGATE 的空间特征补充输入 |
构建空间表达网络 | 聚集表达的基因可能共调控或功能相关 |
🎯 三者之间的关系总结图
smFISH/CODEX定位的单细胞
↓
【1. Neighborhood Enrichment】
判断细胞类型间的空间共存关系
↓
反映微环境结构
ST表达谱
↓
[2. STAGATE 图聚类]
空间结构 + 表达模式 → 区域划分
↓
获得组织功能区域
ST表达谱
↓
[3. Moran’s I 空间自相关分析]
找到空间上富集的基因
✅ 总结对照表
方法 | 原理 | 在文中作用 | 应用意义 |
---|---|---|---|
Neighborhood Enrichment | 细胞间空间邻近频率统计 | 分析不同cell type是否共现 | 揭示细胞互动结构 |
STAGATE(图神经聚类) | GNN感知表达+空间图 | 拓扑一致的空间结构聚类 | 建立组织功能模块 |
Moran’s I | 空间统计:表达的聚集程度 | 找到空间显著表达基因 | 构建空间marker集 |
如果你希望深入分析或复现这些方法,我可以提供 Python 代码框架(如:用 scanpy
, squidpy
, torch-geometric
实现 STAGATE 和 Moran’s I),或帮助你将这些方法迁移到自己的数据集上。是否需要?
这部分内容围绕 scGPT-spatial 在细胞类型反卷积和基因表达插补任务中的应用 展开,结合技术原理与实验验证,展现其提升空间转录组数据解析能力的优势,以下是具体总结:
核心背景:空间转录组技术的天然局限
不同空间转录组技术存在互补性缺陷:
- 测序类(如 Visium):分辨率低,每个 “斑点” 常是多种细胞的混合,需计算反卷积推测细胞类型占比;
- 成像类(如 MERFISH、Xenium):分辨率高(单细胞 / 亚细胞级),但基因检测Panel 有限(仅几百个基因),对未检测基因需 “插补” 补全表达值。
scGPT-spatial 聚焦解决这些问题,通过 参考数据驱动的细胞类型反卷积 + 基因表达插补,增强空间转录组数据的分辨率与基因覆盖度。
技术流程(对应图 3A)
基于 Tangram 提出的 “检索式” 方法,核心流程分两步:
- 构建矩阵优化:用非负矩阵分解(NMF),从参考特征矩阵中优化出 “构建矩阵”,使其能重构实际特征矩阵;
- 任务适配:
- 细胞类型反卷积:构建矩阵的行向量,将单细胞测序(scRNA-seq)参考的细胞特征,映射到 Visium 斑点,推测细胞类型组成;
- 基因表达插补:同理,用行向量从参考数据中检索相关基因表达谱,补全目标数据的缺失值。
关键实验与结果
1. 细胞类型反卷积:提升混合斑点解析力(对应图 3B)
- 实验:在人类乳腺 Visium 数据集(10 张切片)上,对比 scGPT-spatial、Tangram、Cell2location;
- 指标:用 Macro F1 衡量主要细胞类型预测准确性;
- 结论:scGPT-spatial 平均 Macro F1 达 0.58,超 Tangram 约 6%;且预测的细胞类型空间分布,与真实组织模式高度吻合(Tangram 相对模糊,Cell2location 易 “过度平滑” 丢失细节 )。
2. 基因表达插补:跨技术补全基因信息(对应图 3C、3D)
场景 1:MERFISH + scRNA-seq 参考(图 3C)
- 以人类丘脑发育数据为例,对 6 个空间差异基因插补,scGPT-spatial 中位 Pearson 相关系数超 0.6;
- 如基因 MKI67,scGPT-spatial 预测的表达模式与真实高度一致,Tangram 空间结构还原度更低。
场景 2:Xenium + Visium 参考(图 3D)
- 在胎儿肺多模态数据中,对上皮标记基因 IGFBP5 插补,scGPT-spatial 整体 Pearson 相关系数更高,能精准还原气道组织基因表达,展现跨分辨率数据整合能力。
总结
scGPT-spatial 通过 检索式矩阵优化流程,有效解决空间转录组技术的 “混合细胞解析难”“基因覆盖不全” 问题:
- 反卷积任务中,提升混合斑点的细胞类型预测精度;
- 插补任务中,跨技术(测序 / 成像)、跨分辨率补全基因表达,为下游分析提供更完整数据支撑。
实验验证其在多数据集(乳腺、丘脑、胎儿肺等)中,性能优于 Tangram 等方法,凸显基础模型对空间转录组数据的增强价值。
(注:图中 A 是技术流程示意图,B - D 分别对应细胞反卷积、MERFISH 基因插补、Xenium 基因插补的实验结果可视化,用指标、热图、箱线图等对比不同方法表现 )
在细胞类型反卷积(cell - type deconvolution)任务中,ground truth(真实标签)的获取通常依赖于“金标准”数据或已知的参考信息 ,以下结合研究场景具体说明常见来源,也对应你提到的空间转录组研究里的反卷积场景:
1. 已知纯细胞类型的参考数据(“真实”细胞组成的直接来源)
单细胞测序(scRNA - seq)数据:
若研究目标是解析 Visium 等 “混合斑点” 的细胞类型,可先对同组织(或同类组织)做单细胞测序,筛选出 纯细胞类型的基因表达谱(比如纯上皮细胞、纯基质细胞的 scRNA - seq 数据 )。这些纯细胞的基因表达,就是反卷积中 “单个细胞类型应有的特征”,可作为反卷积的参考 ground truth 基础。
例如在文章里,反卷积会用 scRNA - seq 参考数据,本质是因为 scRNA - seq 能分离出纯细胞,其表达谱就是 “理想状态下该细胞类型的真实特征”,后续反卷积预测的混合斑点细胞占比,可与基于 scRNA - seq 推断的 “理论占比” 对比验证。高分辨率成像技术数据(如 MERFISH、Xenium):
这类技术能实现单细胞 / 亚细胞分辨率的空间定位,若某组织先用 MERFISH 测过,已知每个小区域的纯细胞类型(比如明确标记出 “此处是纯内皮细胞” ),这些 高分辨率下的纯细胞标注,也能作为反卷积任务的 ground truth 。比如用 MERFISH 先给组织 “精准打标签”,再拿 Visium 低分辨率数据做反卷积,用 MERFISH 的标注验证结果。
2. 人工注释或已有权威标注(间接但可靠的验证依据)
组织学染色 + 专家注释:
对研究的组织切片,补充传统组织学染色(如免疫组化、荧光标记特定细胞类型),再由领域专家手动标注 “哪些区域是哪种细胞类型主导” 。这种 人工标注的 “细胞类型分布地图”,可作为反卷积结果的 ground truth 对比依据。
比如文章里提到的人类乳腺、胎儿肺数据集,可能就结合了这类专家注释的组织学信息,辅助确定 “真实的细胞类型分布”,用于验证反卷积是否准确。公共数据库 / 已有研究的权威标注:
像人类大脑皮层、肿瘤组织等研究,已有大量公开的、经过验证的 “细胞类型空间分布” 标注(比如某脑区各层细胞类型的经典分布 )。新研究做反卷积时,可直接引用这些 领域内公认的标注 作为 ground truth ,验证算法是否能复现已知的细胞类型分布规律。
3. 多技术联合验证(“交叉印证” 出的 ground truth)
实际研究中,常 把 scRNA - seq 的纯细胞谱、高分辨率成像标注、组织学染色结果结合,交叉验证出更可靠的 ground truth 。比如:先用 scRNA - seq 确定组织里有哪些细胞类型及各自的基因特征,再用 MERFISH 看这些细胞在空间里的真实分布,最后结合组织学染色修正细节,形成一套 “多方共识” 的 ground truth ,用于反卷积模型的训练 / 验证。
简单说,反卷积的 ground truth 就是 “能精准反映‘每个空间位置实际细胞类型组成’的参考标准” ,核心靠 “纯细胞数据(scRNA - seq / 高分辨率成像) + 人工 / 领域标注 + 多技术交叉验证” 来构建,目的是给反卷积算法提供 “正确答案” ,判断其预测准不准~
如果你的研究场景里有特定数据集,想更细究,就得看对应论文 / 数据说明里的 “标注方法” 啦,不同研究可能结合自身数据特点选 ground truth 构建方式~
好的!咱们从 Tangram 核心逻辑 到 图中流程拆解 ,一步步讲清楚,保证你能看懂~
一、Tangram 是干啥的?核心目标
Tangram 是解决 “空间转录组数据解析” 的工具,主要干两件事:
- 细胞类型反卷积:把 Visium 这类 “混合斑点”(一个斑点里有多种细胞),拆成 “每种细胞占多少比例”;
- 基因表达插补:把 MERFISH/Xenium 这类 “基因少、分辨率高” 的数据,补全更多基因的表达(让低基因数数据变 “全基因” )。
核心逻辑是 “用‘参考数据’和‘目标数据’的‘矩阵匹配’,实现解析/插补” ,类似 “找参考和目标的映射关系,用参考‘补全/拆解’目标” 。
二、图里流程到底在干啥?分步拆解
图里是 scGPT - spatial 结合 Tangram 逻辑的流程 ,但核心矩阵匹配逻辑和 Tangram 一致,咱们拆解成 3 步:
步骤 1:准备 “参考特征矩阵” 和 “构建矩阵 ( M )”
参考特征矩阵(粉色):
这是 “已知的、精准的细胞/基因特征” ,比如:- 若做反卷积 → 用 scRNA - seq 测的 纯细胞基因表达谱(比如纯上皮细胞、纯免疫细胞的基因表达,每行是细胞类型,每列是基因 );
- 若做插补 → 用 Visium 测的 全基因表达谱(比如高分辨率区域的基因表达,作为参考补全低分辨率数据 )。
构建矩阵 ( M )(蓝色):
这是个 “待优化的映射关系” ,维度是 [目标斑点数 × 参考点/细胞数] 。简单说,( M ) 的每个元素 ( M_{i,j} ) ,表示 “参考里的第 ( j ) 个细胞/基因,对目标里的第 ( i ) 个斑点的‘贡献度’” 。
步骤 2:优化 ( M ),让 “参考” 和 “实际” 匹配
实际特征矩阵(黄色):
这是 “目标数据的特征” ,比如:- 若目标是 Visium 斑点 → 是这些混合斑点的基因表达谱(每个斑点是一行,基因是一列 );
- 若目标是 MERFISH 数据 → 是这些高分辨率点的(少部分)基因表达谱 。
优化过程:
让 ( M \times \text{参考特征矩阵} \approx \text{实际特征矩阵} ) ,通过数学优化(比如非负矩阵分解、最小二乘法 ),调整 ( M ) 的值,直到 “参考×M” 尽可能接近 “实际特征” 。这一步的核心是 “让 ( M ) 学到‘怎么用参考数据,去拟合目标数据的特征’” 。比如,若目标是混合斑点的基因表达,( M ) 就会学到 “哪些参考细胞类型,以什么比例混合,能生成目标斑点的表达” 。
步骤 3:用优化好的 ( M ),做反卷积/插补
反卷积(细胞类型拆解):
用 ( M \times \text{参考细胞类型矩阵} ) → 得到 “反卷积后的细胞类型比例” 。
解释:参考细胞类型矩阵里,存的是 “每个参考细胞属于哪种类型”(比如第 ( j ) 个参考细胞是上皮细胞,就标 1,其他标 0 )。乘以 ( M ) 后,就会算出 “每个目标斑点里,各种细胞类型的占比” 。基因插补(补全基因表达):
用 ( M \times \text{参考基因表达矩阵} ) → 得到 “插补后的基因表达” 。
解释:参考基因表达矩阵里,存的是 “全基因的表达谱”(比如 Visium 测的全基因数据 )。乘以 ( M ) 后,就能给目标数据(比如 MERFISH 只测了几百个基因 )补全其他基因的表达。
三、Tangram 矩阵方法的本质:“找映射,用参考补目标”
简单总结 Tangram 逻辑:
- 找一批 精准的参考数据(scRNA - seq 纯细胞、Visium 全基因等 );
- 建一个 映射矩阵 ( M ) ,学 “参考怎么组合,能匹配目标数据”;
- 用学好的 ( M ) ,反向用参考数据,解析/补全目标数据(拆细胞比例、补基因表达 )。
图里的流程,就是把这一套逻辑可视化了:蓝色 ( M ) 是映射关系,粉色是参考,黄色是目标,优化 ( M ) 后,用 ( M ) 做反卷积/插补~
四、举个生活化例子,帮你理解
假设你想 “解析一碗混合果汁的成分”(类似解析混合斑点 ):
- 参考特征矩阵:已知纯苹果汁、纯橙汁、纯梨汁的 “味道特征”(比如酸甜度、香气成分 );
- 构建矩阵 ( M ):你需要找的 “每种纯果汁放了多少”(比如苹果汁占 30%、橙汁 50%、梨汁 20% );
- 实际特征矩阵:混合果汁的实际味道(酸甜度、香气 );
- 优化过程:调整 ( M ) 里的比例,让 “参考果汁×比例” 调出的味道,尽可能接近实际混合果汁的味道;
- 反卷积/插补:学好比例后,就知道 “混合果汁里各种纯果汁的占比”(反卷积 ),甚至能根据参考果汁的其他特征,补全混合果汁的 “营养成分”(类似插补基因 )。
这样是不是就清楚啦?Tangram 本质是用 “矩阵匹配” 找参考和目标的关系,实现空间转录组数据的解析~ 核心就是 “用已知的精准参考,通过数学优化,解析未知的混合/低覆盖数据” !
你说得非常对,这种模型结构复杂的架构,确实应该**沿着“数据的流动顺序”**来讲,尤其是从 forward()
进入之后,怎么走 perceptual_forward()
和 generative_forward()
两条路径,它们又在内部如何处理,是需要结构清晰、流程式地梳理。
✅ 按照“数据流动顺序”重新完整讲解模型预训练流程(函数+结构)
我们从 forward()
函数开始,带你一步步追踪数据是怎么在模型中流动的。你会清晰知道:
- 数据从哪儿进来;
- 在哪一层做了什么处理;
- 哪些模块是共享的;
- 哪些是任务分支。
🟢 Step 0:入口函数 forward(**kwargs)
def forward(self, *args, **kwargs):
if "generative_training" not in kwargs:
return self.perceptual_forward(*args, **kwargs)
if kwargs.pop("generative_training"):
return self.generative_forward(*args, **kwargs)
else:
return self.perceptual_forward(*args, **kwargs)
✅ 作用:
根据 generative_training
参数选择模型走哪条路径:
False
→ 感知路径perceptual_forward()
:输入一段表达值,输出预测与表示;True
→ 生成路径generative_forward()
:输入一段“观测表达”,生成后续表达。
🔷 分支 1:感知路径 perceptual_forward()
输入:
src: 基因ID序列
values: 对应表达值
src_key_padding_mask: mask
batch_labels: 可选,表示样本属于哪个批次
🧩 步骤一:编码 _encode()
def _encode(self, src, values, src_key_padding_mask, batch_labels)
src
→GeneEncoder
→ gene token embeddingvalues
→ValueEncoder
→ 表达值 embedding- 两者融合(加法或乘法)→
total_embs
total_embs
送入TransformerEncoder
→transformer_output
⚠️ 如果有 batch_labels
,这个时候还没有用上,只是先保存下来。
🧩 步骤二:表达值预测 self.decoder(...)
- 默认使用
ExprDecoder
- 若设置
use_moe_dec=True
,用MoeDecoder
走专家融合路径
mlm_output = self.decoder(transformer_output)
如果设置了 explicit_zero_prob=True
,还会额外输出 zero_probs
表示稀疏概率。
🧩 步骤三:多任务模块 _extend_output(...)
def _extend_output(self, transformer_output, CLS=True, MVC=True, ECS=True, ...)
会从 transformer_output
中提取 cell_emb
(方式有 cls/avg/w-pool),用于:
分支 | 功能 |
---|---|
ClsDecoder |
分类 |
MVCDecoder |
掩码值重建 |
AdversarialDiscriminator |
批次对抗 |
ECS Module |
相似度正则 loss |
MVCDecoder_Impute |
结合空间KNN进行表达补全(如果开启MVC_impute) |
所有这些模块的执行都取决于对应的布尔参数,如 CLS=True
才会执行分类任务。
🔷 分支 2:生成路径 generative_forward()
适用于生成式预训练:给出部分表达 → 生成另一部分表达。
输入:
pcpt_genes: 观测段 基因ID
pcpt_values: 观测段 表达值
pcpt_key_padding_mask: 观测段 mask
gen_genes: 生成段 基因ID
gen_key_padding_mask: 生成段 mask
🧩 步骤一:transformer_generate()
def transformer_generate(self, pcpt_genes, pcpt_values, gen_genes, ...)
观测部分:
pcpt_genes
→ GeneEncoderpcpt_values
→ ValueEncoder- 相加后 →
pcpt_total_embs
生成部分:
gen_genes
→ GeneEncoder- 加上
FlagEncoder(1)
表示“这是生成段” →gen_total_embs
拼接两个部分 → 输入 Transformer(共享结构)→
pcpt_output
,gen_output
🧩 步骤二:合并输出 → transformer_output
transformer_output = cat([pcpt_output, gen_output])
🧩 步骤三:表达值预测(观测段 + 生成段)
decoder_output = self.decoder(transformer_output)
输出:
output["pcpt_preds"] = decoder_output[:pcpt_len]
output["gen_preds"] = decoder_output[pcpt_len:]
🧩 步骤四:多任务 _extend_output(...)
同感知路径
跟 perceptual_forward()
一样,会调用:
ClsDecoder
→ 分类MVCDecoder
→ 重建AdversarialDiscriminator
→ 批次ECS Module
→ 相似度约束MVCDecoder_Impute
→ 空间插值(使用 coordinates)
🔶 总结整体数据流(简洁图解)
forward()
├─ if generative_training:
│ └── generative_forward()
│ ├─ transformer_generate()
│ ├─ decoder (pcpt + gen)
│ └─ _extend_output() → 多任务
└── perceptual_forward()
├─ _encode()
├─ decoder
└─ _extend_output() → 多任务
✅ 回到你的问题核心
我想知道数据在 forward 中是怎么一步步走的、在哪里被处理的。
答案总结如下:
步骤 | 哪个函数 | 做了什么 |
---|---|---|
入口 | forward |
判断走哪条路径(感知 or 生成) |
感知 | perceptual_forward → _encode |
将 src、values 编码成 total_embs,送入 Transformer |
生成 | generative_forward → transformer_generate |
编码观测和生成段,加上 flag 融合,送入 Transformer |
解码 | self.decoder() |
输出表达值(支持稀疏) |
多任务 | _extend_output() |
提取 cell_emb,调用分类、重建、对抗、ECS、空间插值等模块 |
如果你现在想:
- 查看每一步所在
.py
文件行号; - 输出完整流程图;
- 理解 loss 是怎么计算的(包括 ECS/CLS/MVC);
我可以继续按你的节奏讲。现在是否需要把这段流程画成一张流程图?
你问的这句代码:
if input_cell_emb is not None:
pcpt_total_embs[:, 0, :] = input_cell_emb
在 transformer_generate()
函数中的作用是非常关键和特殊的,它强行覆盖了观测段序列中的第一个 token 的 embedding 表达。下面我从多个维度解释它的用意。
✅ 所在背景回顾
在 transformer_generate()
中:
pcpt_total_embs
是“观测段”输入部分,它由:pcpt_token_embs + pcpt_values
构成,是 Transformer 的第一个输入。
input_cell_emb
是一个可选参数(Optional[Tensor]
),形状为:(batch, embsize) or (batch, seq_len, embsize)
✅ 这句代码的本质行为:
pcpt_total_embs[:, 0, :] = input_cell_emb
用外部提供的 cell embedding(input_cell_emb)替换掉观测段序列中的第一个 token 的 embedding。
也就是说:
- 原本
pcpt_total_embs[:, 0, :]
是代表第一个 token(通常是 special token,比如<cls>
)的 embedding; - 现在,它被外部传入的某个细胞表示向量强行替换。
🔍 这有什么意义?为什么要这么做?
🧠 背后核心思想是:
用一个先验的 cell embedding 来“引导”Transformer在生成阶段如何编码上下文。
具体解释如下:
用意 | 描述 |
---|---|
① 引导生成 | 这相当于注入一个“高层语义表示”(整个细胞的embedding)给Transformer,以影响后续 token 的生成结果。 |
② 实现条件生成 | 如果你想“让这个模型模拟某个特定细胞”,就可以把那个细胞的 embedding 塞进去。 |
③ 控制潜在空间 | 这是常见于 CVAE / Diffusion / GPT-Conditional 生成中的一种做法:将先验表示注入模型。 |
④ 替换 [CLS] 位 |
该模型一般默认 token 0 是 [CLS] ,所以替换这一位就是替换整个序列的代表性 token。 |
🧪 举个实际使用场景
假设你已经有一个训练好的模型,并得到了某个细胞的 cell_emb
表示。现在你想:
🔁 “基于这个细胞的语义表达,生成一段新的表达谱(即 gen_genes 的表达)。”
那么你就可以:
model.generate(
cell_emb=某个细胞的 cell_emb,
src=some_genes,
...
)
此时传入的 input_cell_emb
会用作 Transformer 的第一个 token 表示,用于调制 Transformer 的解码过程,从而实现 个性化、条件化的生成任务。
✅ 小结这句代码的作用:
代码片段 | 作用 |
---|---|
pcpt_total_embs[:, 0, :] = input_cell_emb |
将整个输入序列的第一个位置(通常是 [CLS] token)替换为外部提供的 cell_emb ,用于条件控制或特定表达引导。 |
如你愿意,我可以帮你:
- 模拟一个“用 cell_emb 控制表达生成”的例子;
- 把这段行为画成图;
- 或将这个机制写进论文方法部分。
是否继续深入讲讲这种“条件注入机制”与 Transformer 控制生成的技术背景?
你的理解非常准确,而且已经抓住了核心逻辑。你说的这段:
✅ “这段代码负责生成一个 CLS token 的矩阵,有了这个细胞特征矩阵,接下来做其他任务就可以使用关于这个细胞的预训练信息了。”
完全正确。
下面我来帮你系统性地确认你的理解,并补充一些细节,帮你把整个细胞 embedding 的使用闭环构建完整。
✅ 你的理解核心是正确的:
这段代码的功能可以总结为:
📌 get_batch_cell_embeddings(...)
的作用:
将原始表达矩阵 AnnData(或类似 count_matrix)通过模型编码器处理,抽取每个细胞的
cell_emb
(即 Transformer 的[CLS]
输出向量),作为细胞的预训练表示。
✅ 在这段代码中,关键过程是:
🔹 1. 构建 Dataset
- 每一行是一个细胞;
- 非零表达值用 gene ID + expression 表达;
genes = np.insert(..., 0, <cls>)
→ 在最前加<CLS>
token;values = np.insert(..., 0, pad_value)
→ 对应地为<CLS>
位置填一个无用值(稍后不参与预测)。
🔹 2. _encode()
模型编码函数调用
embeddings = model._encode(
input_gene_ids,
input_expr,
src_key_padding_mask,
batch_labels,
)
这一步走的路径是:
- GeneID →
GeneEncoder
- Expr →
ValueEncoder
- 两者融合后 →
TransformerEncoder
- 输出整个序列的
hidden_states
你只取了:
embeddings = embeddings[:, 0, :] # 只取第一个 token,即 <CLS> 的位置
这就是 细胞的全局表示 cell embedding。
🔹 3. 返回矩阵 cell_embeddings
每一行代表一个细胞的全局向量(长度为 embsize
),比如 (num_cells, 512)
,你还做了 L2 归一化。
✅ 所以你说的结论完全正确:
得到这个细胞表示矩阵之后,你可以在下游任务中使用它作为细胞的语义特征。
✅ 那接下来它能做什么用?(你可以怎么用它)
这是重点补充!
✅ 1. 用于生成任务的“条件注入”
你前面看到:
if input_cell_emb is not None:
pcpt_total_embs[:, 0, :] = input_cell_emb
这句话就是:
把你这个 cell embedding 塞进 Transformer 的输入序列首位,让模型以这个“预设细胞语义”来生成后续表达值。
这种做法被称为 “prompt injection” / “semantic priming”。
✅ 2. 用于下游分类/聚类任务
你也可以直接拿这些 cell_embeddings
去做:
- 聚类(t-SNE / UMAP / KMeans)
- 分类(细胞类型识别)
- 对抗训练(批次校正:
AdversarialDiscriminator
)
✅ 3. 用于 KNN 相似性查找
你还可以:
- 构建基于 cell_emb 的空间或图结构(如 cell graph);
- 在空间预测任务中,查找最近邻,进行表达填补(MVC Impute);
- 用于构建 Nearest Neighbor Attention、Graph Transformer 等结构。
🔍 附加建议(你可以拓展的点)
用法 | 描述 |
---|---|
💡 降维可视化 | 对 cell_embeddings 做 UMAP / PCA 可视化 |
📊 和标签对齐 | 用已有的 cell type 标签训练分类器 |
🔁 生成实验 | 将 cell_emb 作为 prompt 做表达生成、perturbation simulation |
🎯 多模态融合 | 用其他模态(ATAC / 图像)训练模型,把它对齐到同一个 cell_emb 空间 |
✅ 最后总结一下你这段代码的定位:
你这段 get_batch_cell_embeddings()
是整个预训练模型的重要桥梁模块:
它将 稀疏的原始表达矩阵 → 通过 Transformer 提取 → 成为稠密的语义表示向量(CLS),进而作为各种下游任务的基础。
如你需要,我可以:
- 帮你画出这段 embedding 提取流程图;
- 把它写成方法小节、结果小节;
- 教你如何用这些 cell_emb 在 downstream 任务中快速构建 pipeline。
是否接下来你想看看“如何将这些 cell_emb 用在一个分类或生成任务中”?我可以写出完整调用示例。