保姆级教程:用ESM-2模型为你的蛋白质序列生成向量表示(Python实战)
保姆级教程:用ESM-2模型为你的蛋白质序列生成向量表示(Python实战)
蛋白质序列的数值化表示是生物信息学中机器学习应用的关键第一步。ESM-2(Evolutionary Scale Modeling)作为Meta AI团队开发的蛋白质语言模型,能够将任意长度的氨基酸序列转化为固定维度的特征向量,为下游任务如功能预测、结构分析和相互作用研究提供强大的特征输入。本教程将手把手带你完成从环境配置到实际应用的完整流程。
1. 环境准备与模型选择
在开始之前,确保你的Python环境满足以下要求:
- Python ≥ 3.8
- PyTorch ≥ 1.11
- CUDA ≥ 11.3(如需GPU加速)
安装ESM库非常简单:
pip install fair-esmESM-2提供了多个预训练模型变体,主要区别在于参数规模和嵌入维度:
| 模型名称 | 参数数量 | 嵌入维度 | 适用场景 |
|---|---|---|---|
| esm2_t12_35M_UR50D | 35M | 480 | 快速原型开发 |
| esm2_t33_650M_UR50D | 650M | 1280 | 平衡性能与资源(推荐) |
| esm2_t36_3B_UR50D | 3B | 2560 | 最高精度需求 |
对于大多数科研场景,esm2_t33_650M_UR50D在精度和计算成本之间提供了最佳平衡。如果你的数据集较小(<1,000条序列)或硬件有限,可以考虑使用更小的模型。
2. 单条序列处理:Python API详解
让我们从最基本的单条序列处理开始。以下代码展示了如何加载模型并生成单个蛋白质的嵌入表示:
import torch import esm # 加载模型和字母表 model, alphabet = esm.pretrained.esm2_t33_650M_UR50D() batch_converter = alphabet.get_batch_converter() model.eval() # 禁用dropout以获得确定性结果 # 准备示例数据 data = [("my_protein", "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG")] # 转换为模型输入格式 batch_labels, batch_strs, batch_tokens = batch_converter(data) # 生成嵌入表示 with torch.no_grad(): results = model(batch_tokens, repr_layers=[33], return_contacts=False) # 提取第33层的残基级表示 token_representations = results["representations"][33] # 计算序列级表示(平均池化) sequence_representation = token_representations[0, 1:len(batch_strs[0])+1].mean(0)关键参数说明:
repr_layers=[33]:指定从第33层(最后一层)提取表示return_contacts=False:不计算接触图以节省内存token_representations形状为[batch_size, seq_len, embed_dim]
3. 批量处理FASTA文件:命令行高效方案
当需要处理大量蛋白质序列时,使用Python API可能效率较低。ESM提供了命令行工具esm-extract进行批量处理:
esm-extract esm2_t33_650M_UR50D \ input_proteins.fasta \ output_directory \ --repr_layers 33 \ --include mean per_tok \ --toks_per_batch 4096这个命令会:
- 自动下载并加载指定模型
- 处理
input_proteins.fasta中的所有序列 - 在
output_directory生成两种表示:mean:整个序列的平均表示(形状[num_seqs, embed_dim])per_tok:每个残基的表示(形状[num_seqs, max_len, embed_dim])
提示:对于大型FASTA文件(>10,000条序列),建议添加
--truncation_seq_length 1024参数以限制处理的最大序列长度,避免内存溢出。
4. 嵌入向量的保存与加载
生成的嵌入向量可以保存为多种格式供后续使用:
PyTorch tensor格式(.pt):
torch.save(sequence_representations, "embeddings.pt")NumPy数组格式(.npy):
import numpy as np np.save("embeddings.npy", sequence_representations.numpy())CSV格式(适合小规模数据):
import pandas as pd df = pd.DataFrame(sequence_representations.numpy()) df.to_csv("embeddings.csv", index=False)加载保存的嵌入:
# 从.pt文件加载 embeddings = torch.load("embeddings.pt") # 从.npy文件加载 embeddings = torch.from_numpy(np.load("embeddings.npy"))5. 实战案例:蛋白质功能分类
让我们用一个完整的示例展示如何将ESM-2嵌入用于实际机器学习任务。假设我们有一个包含1,000条蛋白质序列的数据集,需要根据其功能进行分类。
from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 假设我们已经有了嵌入和标签 X = torch.load("protein_embeddings.pt") # 形状 [1000, 1280] y = torch.load("protein_labels.pt") # 形状 [1000] # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # 训练SVM分类器 clf = SVC(kernel="rbf", C=1.0, gamma="scale") clf.fit(X_train, y_train) # 评估模型 y_pred = clf.predict(X_test) print(f"Accuracy: {accuracy_score(y_test, y_pred):.2f}")常见性能优化技巧:
- 对嵌入进行标准化:
from sklearn.preprocessing import StandardScaler - 尝试不同的分类器:随机森林、XGBoost等
- 使用PCA降维以减少特征维度
6. 高级技巧与问题排查
处理长序列: ESM-2的最大上下文长度为1024个token。对于更长的序列:
# 分段处理长序列 def process_long_sequence(sequence, chunk_size=1020): chunks = [sequence[i:i+chunk_size] for i in range(0, len(sequence), chunk_size)] chunk_embeddings = [] for chunk in chunks: # 对每个chunk生成嵌入 ... return torch.mean(torch.stack(chunk_embeddings), dim=0)内存不足问题:
- 减小
toks_per_batch参数值 - 使用
torch.cuda.empty_cache()清理GPU缓存 - 考虑使用CPU模式(虽然速度较慢)
嵌入可视化:
from sklearn.manifold import TSNE import matplotlib.pyplot as plt # 降维到2D tsne = TSNE(n_components=2) X_2d = tsne.fit_transform(X[:100]) # 只可视化前100个样本 plt.scatter(X_2d[:, 0], X_2d[:, 1], c=y[:100]) plt.title("t-SNE visualization of protein embeddings") plt.show()在实际项目中,我发现对于相似度较高的蛋白质家族,ESM-2生成的嵌入在t-SNE图上通常会形成清晰的聚类,这验证了其在捕获序列进化信息方面的有效性。
