无监督聚类不应“偷看答案”:Spatial-MGCN等方法用 ARI 做早停与模型选择的标签泄露问题(以空间转录组为例)
摘要
在无监督任务中,用 ARI(Adjusted Rand Index)等外部指标评估聚类与已知标签的一致性是常规做法。但如果在训练阶段用 ARI 选择“最佳 epoch”或早停,就把监督信息引入了本应无监督的流程,造成标签泄露与对标签的过拟合。本文以空间转录组典型代表方法 Spatial-MGCN (https://github.com/cs-wangbo/Spatial-MGCN/blob/master/Spatial-MGCN/DLPFC_test.py)的训练脚本为例,指出这一问题,并给出不依赖标签的早停和模型选择策略。
背景:ARI 的定位与正确用法
- ARI 属于外部评估指标,前提是有“ground truth”标签。
- 正确用法:训练完成后作为基准评估;不应参与训练决策(早停/模型选择)。
- 无监督设定下,训练过程不应接触真实标签。
问题:用 ARI 驱动早停/模型选择的后果
典型错误流程:每个 epoch 先算嵌入,再 KMeans 聚类,与真实标签算 ARI,ARI 变好就保存该 epoch。后果:
- 标签泄露:训练过程直接“偷看答案”。
- 对标签过拟合:模型选择被训练集标签驱动,泛化与可信度下降。
- 评价偏乐观:最终报告的 ARI 被同一批标签指导过,性能被夸大。
空间转录组场景下的风险
空间组学的“ground truth”常不完备或含噪。若在训练阶段用这些标签做选择:
- 结构发现不再纯粹数据驱动;
- 对含噪标签过拟合,削弱生物学解读的可靠性;
- 公平比较与复现性受损。
更合理的无监督模型选择方案
-
基于训练损失的早停
- 监控总无监督损失(如 ZINB 重构 + 一致性 + 正则)。
- 设定 patience,长期无改进则早停。
-
内部聚类指标(无需标签)
- 对嵌入使用 Silhouette、Calinski–Harabasz、Davies–Bouldin 等内部指标。
- 以这些指标最佳的 epoch 作为模型选择依据。
-
固定训练步数
- 预设足够轮次到收敛,不用标签驱动中途决策。
-
无标签验证拆分
- 若目标含重构,可保留一部分样本/特征做验证损失,而非用标签。
-
外部指标仅用于训练后报告
- ARI/AMI/NMI 只在训练结束后计算,用于结果报告,不反向影响模型选择。
概念性重构:用无监督损失保存快照
- 每个 epoch 记录总损失,若创下新低则保存模型参数与当前嵌入(detach + cpu,emb/mean 做 NaN 处理)。
- 训练结束后,再用保存的嵌入做一次聚类。
- 若有真实标签,仅在此时计算 ARI 作为报告,不参与选择。
代码实现的细节坑点
- 邻接矩阵一致性:前向传播与预处理的 nsadj/nfadj 保持一致。
- 保存状态:保存前 detach 并转 CPU,避免显存泄漏。
- 随机性控制:同时固定 NumPy、PyTorch、CUDA 种子。
- 数值稳定:聚类前对嵌入做 NaN 替换或标准化。
如果确实需要监督
- 明确声明为半监督/监督;训练-验证拆分;在独立测试集报告指标,避免乐观偏差。
自查清单
- 训练或早停是否用了真实标签派生的指标?
- 内部评估是否完全不依赖标签?
- 外部指标是否只在训练后计算?
- 选用的嵌入/聚类是否来自无标签的模型选择?
- 随机性与复现实验是否完整记录?
最小伪代码(无标签早停)
best_loss = float("inf")
best_state = None
patience = P
no_improve = 0
for epoch in range(E):
emb, mean, losses = train_one_epoch() # losses['total'] 含重构/一致性/正则
total = losses["total"]
if total < best_loss:
best_loss = total
no_improve = 0
best_state = {
"model": {k: v.detach().cpu() for k, v in model.state_dict().items()},
"emb": np.nan_to_num(emb),
"mean": np.nan_to_num(mean),
}
else:
no_improve += 1
if no_improve >= patience:
break
# 训练完成后再做聚类与外部评估
model.load_state_dict(best_state["model"])
emb_final = best_state["emb"]
labels = KMeans(n_clusters=K).fit(emb_final).labels_
ari = adjusted_rand_score(true_labels, labels) # 仅报告,不参与训练决策
print(f"ARI (report only): {ari:.3f}")
结论
无监督聚类的训练阶段不应“偷看”真实标签。用损失或内部聚类指标替代 ARI 驱动的早停/模型选择,能避免标签泄露与过拟合,提升空间转录组等场景下的严谨性与可信度。
CC BY-NC-SA 4.0
版权声明
本文由 Xiang CHEN 陈向 创作,采用 CC BY-NC-SA 4.0 协议,首发于 https://chenxofhit.xyz 个人网站。
您可以自由地:
- 分享 — 在任何媒介以任何形式复制、发行本作品
- 演绎 — 修改、转换或以本作品为基础进行创作
惟须遵守下列条件:
- 署名 — 您必须给出适当的署名,提供指向本许可协议的链接,同时标明是否(对原始作品)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示许可人为您或您的使用背书。
- 非商业性使用 — 您不得将本作品用于商业目的。
- 相同方式共享 — 如果您再混合、转换或者基于本作品进行创作,您必须基于与原先许可协议相同的许可协议分发您贡献的作品。
商业使用请联系:[email protected]