跳到主要内容

09 单细胞 ML — scVI 整合 + scANVI 自动注释

scVI(single-cell Variational Inference)是单细胞 ML 的代表方法。它结合了 08 章的 Autoencoder 思想 + 单细胞特有的 noise model(zero-inflated negative binomial,ZINB)+ batch effect 显式建模 + 概率分布输出,是单细胞整合的 SOTA 之一。

单细胞为什么需要专用方法

bulk RNA-seq 用 vst + PCA + LR / RF 就能解决大部分问题。单细胞 RNA-seq 不行,原因:

  1. count 数据极稀疏:每个 cell 测 1000-5000 reads,大部分基因 0 表达 — 不是 zero-inflated 是真的 zero
  2. droplet 噪声:doublet / ambient RNA / dying cells,ZINB 模型显式建噪声
  3. batch effects 极强:不同 lab / 不同试剂盒,即便同一 cell type 也会按 batch 分簇
  4. 样本量大:动辄 10K - 100K cells,普通 ML 包内存爆掉

scVI 用变分自编码器 + ZINB 似然 + batch covariate 一次性解决这 4 个问题。

scVI vs Seurat / Harmony 对比

方法数学本质解决的问题单细胞场景偏好
PCA线性降维baseline,弱整合
Seurat IntegrateData(CCA)典型相关整合标准做法,样本数中等(<10K)
Harmony软聚类 + linear correction整合快,样本量大也行
scVIVAE + ZINB整合 + 概率输出 + 跨 lab 迁移大样本(> 1K) + 多 batch
scANVIscVI + label loss整合 + label transfer有 reference 标签时

实务约定:

  • 样本 < 5K, 1-2 batches:Seurat IntegrateData 即可
  • 样本 5K-50K, 3+ batches:Harmony 或 scVI
  • 样本 > 50K 或 跨 lab 整合:scVI
  • 有 reference 标签想迁移到新数据:scANVI

在 PBMC 3k 上跑 scVI

PBMC 3k 是教学经典 — 2700 cells 单 batch,严格说不需要 scVI(Seurat 就够),但本章用它跑 demo 看 scVI 流程。

配套脚本 ml09_scvi.py(W4 在产):

python scripts/machine-learning/ml09_scvi.py
import scvi
import scanpy as sc

adata = sc.read_h5ad("~/biof3-data/pbmc3k/pbmc3k.h5ad")

# 1. scVI setup(配置 batch / covariate)
scvi.model.SCVI.setup_anndata(adata, batch_key=None) # PBMC 3k 单 batch

# 2. 训 scVI (CPU 5-10 min, GPU < 1 min)
model = scvi.model.SCVI(adata, n_latent=16, n_layers=2)
model.train(max_epochs=200, plan_kwargs={"lr": 1e-3})

# 3. 取 latent
adata.obsm["X_scVI"] = model.get_latent_representation()

# 4. UMAP + 聚类
sc.pp.neighbors(adata, use_rep="X_scVI")
sc.tl.umap(adata)
sc.tl.leiden(adata, resolution=0.5)

输出 ml09_figs/:

  • UMAP by Leiden cluster
  • UMAP by scVI latent 主轴(看是否捕捉到 cell type)
  • ELBO loss 曲线(scVI 训练健康度)
  • 重构后表达 vs 真实表达对比

scANVI — 自动注释新数据

实际单细胞研究里,有 reference 数据集已经手工标好 cell type,新数据想沿用同样的标签 — 这就是 scANVI 的场景。

# 1. 在 reference adata(已标注)上训 scVI 再训 scANVI
scvi.model.SCANVI.setup_anndata(ref_adata, batch_key="batch",
labels_key="cell_type",
unlabeled_category="Unknown")
scanvi_model = scvi.model.SCANVI.from_scvi_model(scvi_model_ref)
scanvi_model.train(max_epochs=20)

# 2. 把新数据(无 cell type 标注)与 reference 一起重新 setup
new_adata.obs["cell_type"] = "Unknown"
combined = ad.concat([ref_adata, new_adata])
# (此处省略 setup 重做)

# 3. 预测新数据的 cell type
predictions = scanvi_model.predict(new_adata)
new_adata.obs["scanvi_pred"] = predictions

scANVI 给的不只是单一标签,而是概率分布(每个 cell 在每个 type 上的概率)。这比 KNN-based label transfer 更鲁棒。

在线一键复现

ml-scvi-annotate 工具(W4 上线)— 上传 h5ad,自动跑 scVI + UMAP + Leiden,支持上传 reference 做 scANVI label transfer

ELBO loss 诊断

scVI 训练 loss 是 ELBO(Evidence Lower BOund)= reconstruction loss + KL divergence。看曲线:

ELBO 形态诊断
平稳下降到 plateau✓ 健康
一直降不收敛✗ epochs 不够,加到 400
KL 占比过大✗ latent 没学到信息,加 capacity 或调 KL weight

scvi-tools 自带 model.history 取 loss 各分量,plot 一下即可。

性能 — CPU 还是 GPU

数据规模CPUGPU
PBMC 3k(2700 cells × 32K genes)5-10 min30 sec
50K cells × 30K genes1-2 hours3-5 min
500K cells × 30K genes不实际30-60 min

BioF3 py-server 装齐 PyTorch + CUDA,单细胞场景实测 GPU 加速明显。

何时 scVI 是过度

样本 < 1000 — scVI 数据量需求高,< 1000 不如 Seurat IntegrateData

单一 batch 单一 lab — 没 batch 要校,scVI 的优势点没用上

目标只是 UMAP 可视化 — Seurat 标准流程 PCA → UMAP 已经够,scVI 没明显优势

跨 lab / 跨技术(10x v2 vs v3) 整合 — scVI 显式建 batch 是核心优势

有 reference 想自动注释 — scANVI 是首选

常见坑

batch_key 错传 None — 多 batch 数据没传 batch 参数,scVI 无法去除批次

不 normalize 直接喂 raw counts — scVI 要 raw counts(它内部建 ZINB),Seurat 标准化数据反而不对

min_cells 太严删基因 — scVI 内部会处理低表达基因,过度筛选反而丢信息

用 X_scVI 之外的 latent UMAP — 一定 use_rep="X_scVI",默认用 X 是 raw counts,UMAP 没意义

scANVI 把 unlabeled 写成 NA — 必须用 unlabeled_category="Unknown" 显式标识,否则报错

reference adata 与 new adata gene 不对齐 — 必须先 intersect(ref_adata.var_names, new_adata.var_names) 取交集再训

Methods 段写法模板

We performed integration and label transfer using scVI/scANVI (scvi-tools
v1.4.2) on the PBMC 3k dataset (n=2700 cells, n_genes=32K). Raw counts
served as input. The scVI model was trained for 200 epochs (n_latent=16,
n_layers=2, lr=1e-3) with the batch covariate set to {batch_key} (or None
for single batch). For automated annotation, scANVI was initialized from
the trained scVI model and trained for 20 epochs with reference labels
from {reference_dataset}. Cell type predictions were generated for the
target dataset and visualized via UMAP on the scVI latent representation.

在线工具

(W4 完成后)ml-scvi-annotate 工具 — 上传 h5ad,自动 scVI + Leiden + UMAP,可选 reference 做 scANVI 注释。

本章状态

✅ Wave 4 正文完成(2026-05-27)。配套 ml09_scvi.py + ml-scvi-annotate 工具在产(W4-B)。

AI 陪学

让 AI 陪我学这一篇

AI 会读这篇文章后给你 3-5 步学习计划, 逐步陪你学完,最后出 1-3 道题验证你掌握得怎么样。 登录后 AI 才能记住你的进度。

静态文件

离线资料下载

手册 HTML / PDF 已在后台预生成,点击后直接下载网站静态资源。