蛋白质语言模型与抗体:如何选模型、做好评估
抗体语言模型能把序列转成有用的特征。更难的问题是,这些特征能否帮助你完成具体任务:补全缺失残基、预测表达量,或估计对某个抗原的结合能力。
本文接着前一篇 ESM-2 向量教程,介绍如何选择抗体模型、设计评估,并用一段 Python 检查训练前容易忽略的数据泄漏。只需基础 Python;示例无需下载模型,也不需要 GPU。
1. 先确定输出,再选择模型
先写清楚要预测的量。可以按下面的方式区分任务:
| 目标 | 使用的模型输出 | 需要收集的证据 |
|---|---|---|
| 寻找相似序列 | 向量及明确的距离定义 | 在留出样本上的检索效果 |
| 补全缺失残基 | 残基概率 | 对人为遮盖的已知残基的恢复效果 |
| 预测表达量 | 用向量和表达量标签训练的预测器 | 在相关实验留出测量值上的误差 |
| 预测特定靶点的结合 | 明确靶点范围的任务预测器 | 独立的结合实验测量 |
这些是评估设计建议,不是统一的基准。向量是一种数值表示;两个向量相似,并不自动意味着两种抗体识别相同靶点的概率高。补回一个缺失氨基酸,检验的是序列恢复能力,不能直接证明实验中的结合能力。
2. 比较通用模型、抗体专用模型和配对模型
ESM-2 提供通用蛋白质表征,可以作为基线。与抗体专用模型比较时,应使用相同的下游标签和数据划分。
AbLang 分别提供重链和轻链模型,支持残基编码、序列编码和序列补全。它展示了语言建模如何适配抗体数据。AbLang-2 是另一个模型:作者专门研究对胚系残基的偏好,并使用配对与非配对序列训练。使用时要分清名称和模型权重。AbLang-2 项目仓库
对常规抗体而言,重链与轻链的可变域共同参与构成结合位点。IgBert 和 IgT5 使用配对链训练。论文用监督回归评估向量:配对模型在其中的结合能基准上领先,而通用蛋白质模型 ProtT5 在表达量基准上领先。这支持按任务比较模型,不能据此认定某个模型适合所有抗体数据集。
我的起步建议是:比较一个简单基线、一个通用蛋白质模型,以及一个适配输入格式的抗体模型。如果有真实的重链与轻链配对,再加入配对模型。遵循各模型文档中的链顺序和分隔符要求;把任意字符串拼在一起,不会产生真实配对信息。
3. 区分序列分数与性质预测
掩码语言模型根据序列上下文估计残基。序列合理性分数概括了序列与模型所学模式的吻合程度,其含义取决于掩码和计分方式。它不是实测解离常数,也不是经过校准的结合概率。
当模型只接收抗体序列时,这一区别尤其关键。如果没有靶点信息,也没有另行定义针对特定靶点的训练任务,单靠这个分数无法区分你关心的抗原与其他抗原。某个分数仍可能在特定数据集中与实测性质相关,但用于候选排序之前,应先用留出数据检验这种关系。
AbLang-2 研究的胚系偏好,就是需要检查分数偏好什么的一个理由。常见的序列模式与具体任务需要的表现,不一定得到相同的排名。
4. 提取向量之前,先设计评估
下面是用于自行比较模型的实用流程建议:
- 每个观测到的重链与轻链配对保留一条记录,记录实验、靶点、序列来源及重复测量标识。单域抗体要明确标注其格式。
- 定义泛化目标。预测已知谱系的新变体、新谱系和新抗原,需要不同的留出方案。
- 把相关记录分在一起。有可靠谱系标签时使用谱系;否则定义并记录序列聚类方法。不要把任意样本编号当成谱系标签。
- 提取特征时记录模型权重版本、分词器、链表示和池化规则。残基池化应排除填充位置和特殊 token。
- 先拟合一个简单的监督学习基线。标准化、特征选择和超参数调整只使用训练数据及其内部验证集。
- 在同一个未参与调参的测试集上比较模型。回归任务检查绝对误差与排序相关性;结合阳性很少时,检查实用筛选阈值下的精确率和召回率。
如果目标是预测新抗原,还需要按抗原留出。仅按谱系划分,无法检验这一能力。另行检查与模型预训练数据的潜在重叠;自己的数据表划分干净,并不能排除预训练污染。
5. 运行一个小型泄漏检查
示例使用虚构的配对编号和谱系标签,只演示一项记录检查。它不会运行语言模型、推断生物学谱系,也不会测量模型性能。
创建目录并确认 Python 3 可用:
mkdir antibody-evaluation-demo
cd antibody-evaluation-demo
python3 --version
保存为 check_split.py。代码只使用 Python 标准库:
import argparse
def check_split(train, test):
for field in ("pair_id", "lineage"):
overlap = {row[field] for row in train} & {row[field] for row in test}
if overlap:
raise ValueError(f"{field} overlap: {', '.join(sorted(overlap))}")
def main():
parser = argparse.ArgumentParser(description="Check a synthetic antibody split")
parser.add_argument("--show-leak", action="store_true")
args = parser.parse_args()
# Invented metadata only: no sequences, measurements, or model predictions.
rows = [
{"pair_id": "p1", "lineage": "family_a"},
{"pair_id": "p2", "lineage": "family_a"},
{"pair_id": "p3", "lineage": "family_b"},
{"pair_id": "p4", "lineage": "family_b"},
{"pair_id": "p5", "lineage": "family_c"},
{"pair_id": "p6", "lineage": "family_c"},
]
if args.show_leak:
train, test = rows[::2], rows[1::2]
else:
train = [r for r in rows if r["lineage"] != "family_c"]
test = [r for r in rows if r["lineage"] == "family_c"]
try:
check_split(train, test)
except ValueError as error:
parser.exit(1, f"FAIL: {error}\n")
print(f"PASS: train={len(train)}, test={len(test)}; no pair or lineage overlap")
if __name__ == "__main__":
main()
先运行按组划分,再运行故意引入泄漏的划分:
python3 check_split.py --help
python3 check_split.py
python3 check_split.py --show-leak
第二条命令输出:
PASS: train=4, test=2; no pair or lineage overlap
最后一条命令以状态码 1 退出,并输出:
FAIL: lineage overlap: family_a, family_b, family_c
泄漏划分中的每个配对编号都唯一,但每个谱系都同时出现在两边。这就是示例要捕捉的问题。用于真实记录时,先确定有意义的分组,并让同一配对的重复测量保留相同的配对编号。
检查通过只说明这两个字段没有重叠。它无法发现不同编号下的相同序列、不同谱系标签间的近似重复序列、实验批次效应或预训练污染。这些需要另外检查。
6. 常见问题
| 现象 | 检查或修正方式 |
|---|---|
python3: command not found |
安装 Python 3,确认 python3 --version 可执行后再运行脚本。 |
FAIL: lineage overlap |
把整个谱系放入同一个分区,然后重新检查。 |
| 模型不接受配对输入 | 使用该权重版本文档规定的链顺序、分词方式和分隔符。 |
| 随机划分结果很好,新谱系结果很差 | 检查随机划分两侧的相关序列与重复测量,报告符合实际用途的划分结果。 |
| 序列分数很高,实测结合很差 | 核对靶点、实验及分数定义,用实测标签评估预测器。 |
根据可检验的性质和泛化目标选择模型。保留链配对信息,在训练预测器之前检查相关记录,并始终区分序列合理性与实验测量的行为。
论文和项目文档核对日期:2026 年 9 月 21 日。封面为概念插画,并非实验测得的分子结构。
- 原文作者:春江暮客
- 原文链接:https://www.bobobk.com/protein-language-models-antibody-evaluation.html
- 版权声明:本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。