春江暮客

春江暮客的个人学习分享网站

蛋白质语言模型与抗体:如何选模型、做好评估

2026-09-21 技术
蛋白质语言模型与抗体:如何选模型、做好评估

抗体语言模型能把序列转成有用的特征。更难的问题是,这些特征能否帮助你完成具体任务:补全缺失残基、预测表达量,或估计对某个抗原的结合能力。

本文接着前一篇 ESM-2 向量教程,介绍如何选择抗体模型、设计评估,并用一段 Python 检查训练前容易忽略的数据泄漏。只需基础 Python;示例无需下载模型,也不需要 GPU。

1. 先确定输出,再选择模型

先写清楚要预测的量。可以按下面的方式区分任务:

目标 使用的模型输出 需要收集的证据
寻找相似序列 向量及明确的距离定义 在留出样本上的检索效果
补全缺失残基 残基概率 对人为遮盖的已知残基的恢复效果
预测表达量 用向量和表达量标签训练的预测器 在相关实验留出测量值上的误差
预测特定靶点的结合 明确靶点范围的任务预测器 独立的结合实验测量

这些是评估设计建议,不是统一的基准。向量是一种数值表示;两个向量相似,并不自动意味着两种抗体识别相同靶点的概率高。补回一个缺失氨基酸,检验的是序列恢复能力,不能直接证明实验中的结合能力。

2. 比较通用模型、抗体专用模型和配对模型

ESM-2 提供通用蛋白质表征,可以作为基线。与抗体专用模型比较时,应使用相同的下游标签和数据划分。

AbLang 分别提供重链和轻链模型,支持残基编码、序列编码和序列补全。它展示了语言建模如何适配抗体数据。AbLang-2 是另一个模型:作者专门研究对胚系残基的偏好,并使用配对与非配对序列训练。使用时要分清名称和模型权重。AbLang-2 项目仓库

对常规抗体而言,重链与轻链的可变域共同参与构成结合位点。IgBert 和 IgT5 使用配对链训练。论文用监督回归评估向量:配对模型在其中的结合能基准上领先,而通用蛋白质模型 ProtT5 在表达量基准上领先。这支持按任务比较模型,不能据此认定某个模型适合所有抗体数据集。

我的起步建议是:比较一个简单基线、一个通用蛋白质模型,以及一个适配输入格式的抗体模型。如果有真实的重链与轻链配对,再加入配对模型。遵循各模型文档中的链顺序和分隔符要求;把任意字符串拼在一起,不会产生真实配对信息。

3. 区分序列分数与性质预测

掩码语言模型根据序列上下文估计残基。序列合理性分数概括了序列与模型所学模式的吻合程度,其含义取决于掩码和计分方式。它不是实测解离常数,也不是经过校准的结合概率。

当模型只接收抗体序列时,这一区别尤其关键。如果没有靶点信息,也没有另行定义针对特定靶点的训练任务,单靠这个分数无法区分你关心的抗原与其他抗原。某个分数仍可能在特定数据集中与实测性质相关,但用于候选排序之前,应先用留出数据检验这种关系。

AbLang-2 研究的胚系偏好,就是需要检查分数偏好什么的一个理由。常见的序列模式与具体任务需要的表现,不一定得到相同的排名。

4. 提取向量之前,先设计评估

下面是用于自行比较模型的实用流程建议:

  1. 每个观测到的重链与轻链配对保留一条记录,记录实验、靶点、序列来源及重复测量标识。单域抗体要明确标注其格式。
  2. 定义泛化目标。预测已知谱系的新变体、新谱系和新抗原,需要不同的留出方案。
  3. 把相关记录分在一起。有可靠谱系标签时使用谱系;否则定义并记录序列聚类方法。不要把任意样本编号当成谱系标签。
  4. 提取特征时记录模型权重版本、分词器、链表示和池化规则。残基池化应排除填充位置和特殊 token。
  5. 先拟合一个简单的监督学习基线。标准化、特征选择和超参数调整只使用训练数据及其内部验证集。
  6. 在同一个未参与调参的测试集上比较模型。回归任务检查绝对误差与排序相关性;结合阳性很少时,检查实用筛选阈值下的精确率和召回率。

如果目标是预测新抗原,还需要按抗原留出。仅按谱系划分,无法检验这一能力。另行检查与模型预训练数据的潜在重叠;自己的数据表划分干净,并不能排除预训练污染。

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 日。封面为概念插画,并非实验测得的分子结构。

友情链接

其它