作者按

本章节主要讲解了基于transformer的迁移注释方法TOSICA,该算法在迁移注释上达到了SOTA的水平,在注释这么卷的赛道愣是杀出了一条血路。本教程首发于单细胞最好的中文教程,未经授权许可,禁止转载。

全文字数|预计阅读时间: 3000|3min

——Starlitnightly(星夜)

1. 背景

迁移注释实际上是自动注释的一类,与我们在3-4中介绍的自动注释不同,迁移注释需要我们有一个已经注释好的单细胞测序数据文件,而不是训练好的模型或者marker。我们需要使用这个已经注释好的单细胞测序数据文件来训练一个新的模型,例如Cell-Blast或者是Tosica等。

此外,对于多个样本的单细胞测序文件,我们可以先主动注释好一个样本,然后使用迁移注释的方式,把剩下的样本也一起注释了。在这里,我们将介绍迁移注释的SOTA算法,TOSICA。TOSICA 实现了快速、准确的一站式注释和对批量不敏感的整合,同时为理解发育和疾病进展过程中的细胞行为提供了可解释的生物学见解。

import omicverse as ov
print(f'omicverse version: {ov.__version__}')
import scanpy as sc
print(f'scanpy version: {sc.__version__}')
ov.ov_plot_set()

omicverse version: 1.5.1
scanpy version: 1.9.1

2. 加载数据

需要注意的是,参考单细胞测序数据与要注释的单细胞测序数据要保持一致的归一化方法。归一化方法通常受sc.pp.normalize_totaltarget_sum参数的影响,在scanpy中,默认值为自适应,这会导致我们在迁移注释时出错,为了避免这种情况的出现,我们需要将其统一,不能留空。网上的教程包括seurat会将target_sum设置为1e4

而如果你是使用omicverse的preprocess函数进行的归一化,那么默认target_sum50*1e4。而在本教程中,我们将统一使用原始counts,然后使用omicverse的preprocess函数进行预处理与归一化

2.1 参考注释数据集

一个高质量的参考注释数据集对我们注释结果的影响是至关重要的,在这里,我们介绍Cell Blast参考注释数据集,Cell Blast收集了100+个高质量的单细胞注释数据集,我们从中下载了Zheng来注释我们的骨髓数据集。

需要注意的是,我们用来训练的参考数据集不能少于30,000个细胞,否则训练出来的TOSICA模型效果一般,如果参考数据集大于100,000个细胞,我们也可以随机选择30,000个细胞进行训练,效果是一样的。

!wget https://cblast.gao-lab.org/Zheng/Zheng.h5ad

--2023-08-31 19:21:26--  https://cblast.gao-lab.org/Zheng/Zheng.h5ad
Resolving cblast.gao-lab.org (cblast.gao-lab.org)... 159.138.49.219
Connecting to cblast.gao-lab.org (cblast.gao-lab.org)|159.138.49.219|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 500776712 (478M) [application/octet-stream]
Saving to: ‘Zheng.h5ad’ Zheng.h5ad 100%[===================>] 477.58M 3.85MB/s in 1m 56s 2023-08-31 19:23:23 (4.12 MB/s) - ‘Zheng.h5ad’ saved [500776712/500776712]

ref_adata = ov.utils.read('Zheng.h5ad')
ref_adata
AnnData object with n_obs × n_vars = 91789 × 32643
obs: 'cell_type1', 'lifestage', 'organism', 'dataset_name', 'platform', 'organ', 'data_type', 'cell_ontology_class', 'cell_ontology_id', 'n_genes', 'n_counts', '__libsize__'
var: 'variable_genes'
uns: 'cell_ontology_class_colors', 'cell_type1_colors', 'data_quality', 'known_markers', 'neighbors', 'umap'
obsm: 'X_umap', 'latent'
obsp: 'connectivities', 'distances'

随机选取30,000个细胞的方法,我们使用random.sample进行无放回采样

import random
cell_idx=list(random.sample(ref_adata.obs.index.tolist(),30000))
ref_adata=ref_adata[cell_idx]
ref_adata

View of AnnData object with n_obs × n_vars = 3000 × 2398
obs: 'cell_type1', 'lifestage', 'organism', 'dataset_name', 'platform', 'organ', 'data_type', 'cell_ontology_class', 'cell_ontology_id', 'n_genes', 'n_counts', '__libsize__'
var: 'variable_genes', 'n_cells', 'percent_cells', 'robust', 'mean', 'var', 'residual_variances', 'highly_variable_rank', 'highly_variable_features'
uns: 'cell_ontology_class_colors', 'cell_type1_colors', 'data_quality', 'known_markers', 'neighbors', 'umap', 'log1p', 'hvg'
obsm: 'X_umap', 'latent'
layers: 'counts'
obsp: 'connectivities', 'distances'

ref_adata.obs['cell_ontology_class'].cat.categories

Index(['B cell', 'T-helper 2 cell', 'cytotoxic T cell', 'dendritic cell',
'hematopoietic precursor cell', 'memory T cell', 'monocyte',
'naive thymus-derived CD4-positive, alpha-beta T cell',
'naive thymus-derived CD8-positive, alpha-beta T cell',
'natural killer cell', 'regulatory T cell'],
dtype='object')

我们检查其归一化程度

ref_adata.X.max()

这是一个较大的整数,表明其并未进行归一化,是原始counts,我们对其进行预处理(包括归一化与高可变基因的计算)。

ref_adata=ov.pp.preprocess(ref_adata,mode='shiftlog|pearson',n_HVGs=3000)

Begin robust gene identification
After filtration, 21666/32643 genes are kept. Among 21666 genes, 13971 genes are robust.
End of robust gene identification.
Begin size normalization: shiftlog and HVGs selection pearson
normalizing counts per cell The following highly-expressed genes are not considered during normalization factor computation:
['IGLL5']
finished (0:00:00)
extracting highly variable genes
--> added
'highly_variable', boolean vector (adata.var)
'highly_variable_rank', float vector (adata.var)
'highly_variable_nbatches', int vector (adata.var)
'highly_variable_intersection', boolean vector (adata.var)
'means', float vector (adata.var)
'variances', float vector (adata.var)
'residual_variances', float vector (adata.var)
End of size normalization: shiftlog and HVGs selection pearson

2.2 待注释数据集

我们还是使用之前的骨髓数据集,为了保持我们分析的一致性,但是我们需要从中先提取原始counts,因为我们在2-2的章节中对数据进行了归一化与高可变基因的筛选

adata = ov.utils.read('data/s4d8_manual_annotation.h5ad')
adata=adata.raw.to_adata()
ov.utils.retrieve_layers(adata,layers='counts')
print('raw count adata:',adata.X.max())

......The X of adata have been stored in raw
......The layers counts of adata have been retreved
raw count adata: 889.0

adata=ov.pp.preprocess(adata,mode='shiftlog|pearson',n_HVGs=3000)

Begin robust gene identification
After filtration, 20171/20171 genes are kept. Among 20171 genes, 20171 genes are robust.
End of robust gene identification.
Begin size normalization: shiftlog and HVGs selection pearson
normalizing counts per cell The following highly-expressed genes are not considered during normalization factor computation:
[]
finished (0:00:00)
WARNING: adata.X seems to be already log-transformed.
extracting highly variable genes
--> added
'highly_variable', boolean vector (adata.var)
'highly_variable_rank', float vector (adata.var)
'highly_variable_nbatches', int vector (adata.var)
'highly_variable_intersection', boolean vector (adata.var)
'means', float vector (adata.var)
'variances', float vector (adata.var)
'residual_variances', float vector (adata.var)
End of size normalization: shiftlog and HVGs selection pearson

2.3 高可变基因一致化

我们对ref_adataadata都提取了3000个高可变基因,但是这两个单细胞测序数据的高可变基因不一致,所以我们需要提取相同的高可变基因来进行分析。

#提取高可变基因
ref_adata = ref_adata[:, ref_adata.var.highly_variable_features] #提取共同高可变基因
ref_adata.var_names_make_unique()
adata.var_names_make_unique()
ret_gene=list(set(adata.var_names) & set(ref_adata.var_names))
len(ret_gene)

我们发现参考数据集的高可变基因与目标数据集的共同基因只有2132个,我们可以将前面3000个高可变基因调高来保证取到的高可变基因重复率较高

adata=adata[:,ret_gene]
ref_adata=ref_adata[:,ret_gene]

我们此时再看ref_adata与adata的最大值,发现其都在np.log1p(50*1e4)内,表明二者具有相同的归一化值。

print(f"The max of ref_adata is {ref_adata.X.max()}, query_data is {adata.X.max()}",)

The max of ref_adata is 11.416531562805176, query_data is 10.87752914428711

3. 下载通路注释集

TOSICA作为一个transformer模型,具有多头注意力机制,这意味我们除了注释以外,还可以分析细胞的注意力主要位于什么通路上,所以我们可以将通路数据作为输入给予TOSICA模型。

你可以使用ov.utils.download_tosica_gmt()来自动下载,也可以通过下面的链接手动下载:

当然对于国内的用户,也可以使用百度网盘手动下载

链接:

ov.utils.download_tosica_gmt()

4. 初始化 TOSICA 模型

我们首先需要在 He_Calvarial_Bone 数据集上训练 TOSICA 模型,omicverse 提供了一个简单的 pyTOSICA 类,所有后续操作都可以使用 pyTOSICA 完成。我们需要设置模型初始化的参数。

  • adata:参考 adata 对象
  • gmt_path:默认的预先准备的掩码,或者 .gmt 文件的路径。您可以使用 ov.utils.download_tosica_gmt() 来获取基因集。
  • depth:Transformer 模型的深度,设置为 2 时可能会发生内存泄漏。
  • label_name:在 adata.obs 中表示细胞类型的参考键。
  • project_path:TOSICA 模型的保存路径。
  • batch_size:表示在单次传递中传递给程序进行训练的细胞数量。
tosica_obj=ov.single.pyTOSICA(adata=ref_adata,
gmt_path='genesets/GO_bp.gmt', depth=1,
label_name='cell_ontology_class',
project_path='hGOBP_demo',
batch_size=8)
cuda:0
Mask loaded!

5. 训练 TOSICA 模型

训练 TOSICA 模型时需要设置 4 个参数。

  • pre_weights: 预训练权重的路径。
  • lr: 学习率。
  • epochs:epochs 的个数。
  • lrf: 最后一层的学习率。
tosica_obj.train(epochs=5)

Model builded!

[train epoch 0] loss: 1.300, acc: 0.485: 100%|██████████| 11504/11504 [01:54<00:00, 100.70it/s]
[valid epoch 0] loss: 0.429, acc: 0.817: 100%|██████████| 4930/4930 [00:14<00:00, 330.10it/s]
[train epoch 1] loss: 0.470, acc: 0.807: 100%|██████████| 11504/11504 [01:55<00:00, 100.01it/s]
[valid epoch 1] loss: 0.371, acc: 0.843: 100%|██████████| 4930/4930 [00:14<00:00, 330.79it/s]
[train epoch 2] loss: 0.390, acc: 0.842: 100%|██████████| 11504/11504 [01:54<00:00, 100.11it/s]
[valid epoch 2] loss: 0.338, acc: 0.864: 100%|██████████| 4930/4930 [00:14<00:00, 330.17it/s]
[train epoch 3] loss: 0.332, acc: 0.866: 100%|██████████| 11504/11504 [01:54<00:00, 100.22it/s]
[valid epoch 3] loss: 0.291, acc: 0.881: 100%|██████████| 4930/4930 [00:14<00:00, 330.55it/s]
[train epoch 4] loss: 0.284, acc: 0.888: 100%|██████████| 11504/11504 [01:54<00:00, 100.36it/s]
[valid epoch 4] loss: 0.273, acc: 0.891: 100%|██████████| 4930/4930 [00:14<00:00, 330.70it/s] Training finished!

我们可以使用 .save 来保存 TOSICA模型到 project_path

tosica_obj.save()
tosica_obj.load()

6. 细胞类型预测

在训练好TOSICA模型后,我们将其注释结果迁移到目标数据上

new_adata=tosica_obj.predicted(pre_adata=adata)
0
10000
14814
new_adata.obsm=adata[new_adata.obs.index].obsm.copy()
new_adata.obsp=adata[new_adata.obs.index].obsp.copy()
new_adata
AnnData object with n_obs × n_vars = 14814 × 299
obs: 'Prediction', 'Probability', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'pct_counts_in_top_20_genes', 'total_counts_mt', 'log1p_total_counts_mt', 'pct_counts_mt', 'total_counts_ribo', 'log1p_total_counts_ribo', 'pct_counts_ribo', 'total_counts_hb', 'log1p_total_counts_hb', 'pct_counts_hb', 'outlier', 'mt_outlier', 'scDblFinder_score', 'scDblFinder_class', 'leiden_res1', 'major_celltype', 'manual_celltype', 'minor_celltype'
obsm: 'X_mde', 'scaled|original|X_pca'
obsp: 'connectivities', 'distances'
ov.utils.embedding(
new_adata,
basis="X_mde",
color=['major_celltype', 'Prediction'],
frameon='small',
#ncols=1,
wspace=0.5,
#palette=ov.utils.pyomic_palette()[11:],
show=False,
)

我们可以看见,其注释效果一般,这是由于我们是用PBMC外周血的细胞类型进行迁移,而不是使用骨髓数据进行迁移。所以参考数据集的选取对于注释准确率的影响非常大,一般我们手动注释一个样本然后进行迁移的准确率是最高的。

7. 注意力机制

transformer作为一个注意力模型,我们可以找到每一类细胞注意力集中的通路,这听起来有点类似通路富集。我们首先将预测细胞类型数量小于5的细胞给过滤掉。

cell_idx=new_adata.obs['Prediction'].value_counts()[new_adata.obs['Prediction'].value_counts()<5].index
new_adata=new_adata[~new_adata.obs['Prediction'].isin(cell_idx)]

然后,我们使用 sc.tl.rank_genes_groups 计算出各细胞类型中注意力最高的差异通路。这种差异通路来源于之前计算所用的 gmt 基因组。

sc.tl.rank_genes_groups(new_adata, 'Prediction', method='wilcoxon')

ranking genes
finished: added to `.uns['rank_genes_groups']`
'names', sorted np.recarray to be indexed by group ids
'scores', sorted np.recarray to be indexed by group ids
'logfoldchanges', sorted np.recarray to be indexed by group ids
'pvals', sorted np.recarray to be indexed by group ids
'pvals_adj', sorted np.recarray to be indexed by group ids (0:00:00)

sc.pl.rank_genes_groups_dotplot(new_adata,
n_genes=3,standard_scale='var',)

如果想获取特定细胞的通路,可以使用 sc.get.rank_genes_groups_df 来获取。

例如,我们想获得细胞类型 B细胞 注意力最高的通路

degs = sc.get.rank_genes_groups_df(new_adata, group='B cell', key='rank_genes_groups',pval_cutoff=0.05)
degs.head()

我们发现注意力最高的通路是GOBP_REGULATION_OF_PROTEIN_BINDING,我们在umap图上观察通路的注意力情况,发现其确实位于B细胞区域

ov.utils.embedding(
new_adata,
basis="X_mde",
color=['Prediction','GOBP_REGULATION_OF_PROTEIN_BINDING'],
frameon='small',
#ncols=1,
wspace=0.5,
#palette=ov.utils.pyomic_palette()[11:],
show=False,
)

单细胞测序最好的教程(十):细胞类型注释迁移|万能的Transformer的更多相关文章

  1. 基于单细胞测序数据构建细胞状态转换轨迹(cell trajectory)方法总结

    细胞状态转换轨迹构建示意图(Trapnell et al. Nature Biotechnology, 2014) 在各种生物系统中,细胞都会展现出一系列的不同状态(如基因表达的动态变化等),这些状态 ...

  2. 单细胞测序技术(single cell sequencing)

    单细胞测序技术(single cell sequencing) 2018-03-02 11:02   来源: 一呼百诺  点击次数:6587关键词:   前言 单细胞生物学最近几年是非常热门的研究方向 ...

  3. 单细胞测序|单细胞基因组|单细胞转录组|Gene editing|

    单细胞测序 单细胞基因组学 测量理由是单细胞的时间空间特异性. Gene expression&co-expression 比较正常cell与疾病cell,正常organ与疾病organ,看出 ...

  4. 无废话ExtJs 入门教程十九[API的使用]

    无废话ExtJs 入门教程十九[API的使用] extjs技术交流,欢迎加群(201926085) 首先解释什么是 API 来自百度百科的官方解释:API(Application Programmin ...

  5. Unity3D脚本中文系列教程(十六)

    Unity3D脚本中文系列教程(十五) ◆ function OnPostprocessAudio (clip:AudioClip):void 描述:◆  function OnPostprocess ...

  6. Unity3D脚本中文系列教程(十五)

    http://dong2008hong.blog.163.com/blog/static/4696882720140322449780/ Unity3D脚本中文系列教程(十四) ◆ LightRend ...

  7. [转]PostgreSQL教程(十六):系统视图详解

    这篇文章主要介绍了PostgreSQL教程(十六):系统视图详解,本文讲解了pg_tables.pg_indexes.pg_views.pg_user.pg_roles.pg_rules.pg_set ...

  8. RabbitMQ入门教程(十四):RabbitMQ单机集群搭建

    原文:RabbitMQ入门教程(十四):RabbitMQ单机集群搭建 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...

  9. 答读者问(1):非模式物种找marker;如何根据marker定义细胞类型

    下午花了两个小时回答读者的疑问,觉得可以记录下来,也许能帮到一部分人. 第一位读者做的是非模式物种的单细胞. 一开始以为是想问我非模式物种的marker基因在哪儿找,读者朋友也提到了blast 研究的 ...

  10. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

随机推荐

  1. django设置中文和上海时间

    在settings.py配置文件中进行配置: # 设置为中文 LANGUAGE_CODE = 'zh-hans' # 设置 "亚洲/上海" 时区 TIME_ZONE = 'Asia ...

  2. tkinter小例子

    from tkinter import * def on_click(): label['text'] = text.get() root = Tk(className='hello') root.m ...

  3. OC的引用计数

    一.引用计数 引用计数是Objetive-C语言的内存管理机制,用于管理OC对象(通常指包含isa指针的结构体)的内存. 一个对象的引用计数为大于0的计数,表示这个对象被持有,不能被释放,当引用计数为 ...

  4. 记一例UIView突然不显示的排查过程

    一.现象 今日在开发中遇到一个诡异问题,一个自定义的AlertView在显示之后瞬间在屏幕上消失,但是其对象在内存中依然存在 二.排查 通过lldb命令查询到view.superview.superv ...

  5. GK2023游记

    不会有人高考之后二十多天才更博客吧...(写的很烂,单纯想补个坑) 大概就是写一下纯 whk 的高三生活,是不是流水账无所谓,就算当个记录了 高三生活开头就不太平,高三的班主任和高二一样(姑且叫他 田 ...

  6. 面试官:说说Netty对象池的实现原理?

    Netty 作为一个高性能的网络通讯框架,它内置了很多恰夺天工的设计,目的都是为了将网络通讯的性能做到极致,其中「对象池技术」也是实现这一目标的重要技术. 1.什么是对象池技术? 对象池技术是一种重用 ...

  7. 快速生成树协议(RSTP)基本知识及实验(使用eNSP)

    关于生成树协议的知识可参考我的另一个博客:https://www.cnblogs.com/mrlayfolk/p/12242627.html 这篇博文主要介绍快速生成树协议(RSTP)的基本知识.-- ...

  8. 用 Easysearch 帮助大型车企降本增效

    最近某头部汽车集团需要针对当前 ES 集群进行优化,背景如下: ES 用于支撑包括核心营销系统.管理支持系统.财务类.IT 基础设施类.研发.自动驾驶等多个重要应用,合计超 50 余套集群,累计数据超 ...

  9. sql去重常用的基本方法

    1.存在两条完全相同的纪录 select distinct * from table(表名) where (条件)   2.存在部分字段相同的纪录(有主键id即唯一键) 如果是这种情况的话用disti ...

  10. 启动 bert-as-service

    S1:启动bert-as-service时,执行命令 bert-serving-start -model_dir /downloads/uncased_L-12_H-768_A-12/ -num_wo ...