RFOptimization 实用指南:蛋白质设计优化、环境搭建与结果检查
设计出的蛋白质看起来合理,仍可能无法通过结构预测指标筛选。RFOptimization(RFO)从已有分子复合物出发,寻找能够改善预测性质的序列变化。本文介绍它的优化流程、如何搭建小规模试跑环境,以及怎样用 Python 检查循环是否完整执行。
资料核对日期为 2026 年 10 月 8 日。方法来自 Zhang 等人的 RFOptimization 预印本,最初于 2026 年 9 月发布。下文安装和模型命令已对照公开源码检查,本文没有运行 GPU 优化,也没有复现论文基准。独立记录检查脚本及其合成示例已在本地测试。
1. RFOptimization 修改什么
RFO 是一种无需额外训练的优化框架:使用预训练模型,不重新拟合一套模型权重。序列优化过程仍然可以使用梯度。预印本将梯度引导的突变搜索、结构预测和 MPNN 序列重设计结合起来,并以 AlphaFold3 作为单独的最终评估工具。文中报告的提升针对计算筛选,不能据此认定每个通过筛选的设计都已获得实验结合证据。参见原始摘要。
公开实现在每轮循环中选择两个分支之一:
| 阶段 | 作用 |
|---|---|
| RF3 分支 | 用 RoseTTAFold3 引导序列优化 |
| Boltz 分支 | 用 Boltz-2 为当前序列预测结构 |
| 外部 MPNN | 重新设计 A 链中未固定的残基,将复合物传入下一轮 |
| 单独评估 | 优化结束后,对选出的设计进行独立检查 |
backprop_fraction: 0.5 表示每轮选择 RF3 的概率。它不保证严格交替执行,也不保证短任务中两个分支各占一半。设为 1 或 0,分别只使用 RF3 或 Boltz 分支;两个分支都保留 MPNN 步骤。
与 FlashPPI 的相互作用筛选不同,这个流程会修改输入设计。保留初始复合物,才能用相同评估流程比较起始序列、每轮生成的序列和最终候选。
2. 准备输入和模型环境
使用配备 NVIDIA GPU 的 Linux 机器,并准备可用的 Conda。驱动程序与 RF3、MPNN、Boltz 分别使用独立环境。以下命令应在同一个 shell 中执行,让导出的路径保持有效。CUDA 兼容性和模型资源要求以安装说明为准。
待设计的蛋白质必须是 A 链,包含标准氨基酸,以及完整的 N、CA、C、O 主链原子。在双蛋白示例中,B 链是结合伙伴。启动前检查链 ID 和残基完整性;RF3 分支通过与 B 链的接触关系确定 MPNN 固定残基。运行 YAML 中的路径相对于当前工作目录解析。参见循环输入约定。
新建工作目录,并固定到本文检查的 Foundry 源码版本:
mkdir rfo-tutorial
cd rfo-tutorial
export RFO_WORK="$PWD"
git clone https://github.com/RosettaCommons/foundry.git
cd foundry
git checkout 94c78ab125c6ef2cc7d1226de86d1bd578bf8bee
conda create -n rfo-driver python=3.12 -y
conda activate rfo-driver
python -m pip install -e '.[rf3,rfo]'
foundry install rf3
export RF3_CKPT="$HOME/.foundry/checkpoints/rf3_foundry_01_24_latest_remapped.ckpt"
rfo --help
RF3 权重需要支持置信度预测,并包含训练配置。安装说明指出,历史研究配置使用过其他权重。这里提供的是软件试跑流程,不代表复现论文实验。模型相关资源请查看 RF3 配置文档。
安装上游 LigandMPNN 仓库。它提供 RFO 调用的 run.py 接口,支持 ProteinMPNN 和 LigandMPNN:
cd "$RFO_WORK"
git clone https://github.com/dauparas/LigandMPNN.git
cd LigandMPNN
conda create -n rfo-mpnn python=3.11 -y
conda activate rfo-mpnn
python -m pip install -r requirements.txt
bash get_model_params.sh ./model_params
export MPNN_REPO="$PWD"
export MPNN_PYTHON="$CONDA_PREFIX/bin/python"
export MPNN_MODEL_TYPE=protein_mpnn
"$MPNN_PYTHON" "$MPNN_REPO/run.py" --help
git rev-parse HEAD > "$RFO_WORK/mpnn-commit.txt"
python -m pip freeze > "$RFO_WORK/mpnn-packages.txt"
根据机器情况处理上游 CUDA/PyTorch 依赖。RFO 的适配器不使用 Foundry 自带的 mpnn 命令。将 Boltz 安装到独立环境,再切回驱动程序环境:
conda create -n rfo-boltz python=3.12 -y
conda activate rfo-boltz
python -m pip install 'boltz[cuda]'
export BOLTZ_EXECUTABLE="$CONDA_PREFIX/bin/boltz"
export BOLTZ_CACHE="$HOME/.cache/boltz"
"$BOLTZ_EXECUTABLE" predict --help
python -m pip freeze > "$RFO_WORK/boltz-packages.txt"
conda activate rfo-driver
cd "$RFO_WORK/foundry/models/rfo"
python -m pip freeze > "$RFO_WORK/driver-packages.txt"
这些命令记录外部 MPNN 的提交版本和已安装包版本,但没有锁定完整依赖图。还应保留权重文件名与校验和、输入结构以及实际运行配置。Boltz 首次使用时可能下载模型资源,应将下载耗时与优化耗时分开记录。
3. 先检查两个分支,再运行混合循环
在 foundry/models/rfo 目录下,使用仓库提供的示例复合物,分别执行两个分支:
rfo --config src/rfo/cycling/configs/example.yaml \
--backprop-fraction 1 --total-cycles 1 \
--out-dir outputs/smoke-rf3
rfo --config src/rfo/cycling/configs/example.yaml \
--backprop-fraction 0 --total-cycles 1 \
--out-dir outputs/smoke-boltz
每次试跑使用新的输出目录。驱动程序实现会在启动时初始化记录文件;复用目录可能覆盖记录,也可能让旧产物与新产物混在一起。
两次单轮任务成功后,在同一目录将以下内容保存为 tutorial.yaml:
input_structure: ./src/rfo/cycling/examples/example_complex.cif
out_dir: ./outputs/tutorial-mixed
backprop_fraction: 0.5
total_cycles: 3
mpnn_num_seqs: 1
mpnn_temperature: 0.1
seed: 42
运行并查看记录:
rfo --config tutorial.yaml
python -m json.tool outputs/tutorial-mixed/example_complex_records.json
命令行接口允许命令行参数覆盖 YAML 设置;显式填写的 assets: 设置会覆盖环境变量。这个示例使用前面导出的路径,没有添加目标专用 MSA 或模板。没有 MSA 时,Boltz 使用单序列模式;加入目标 MSA 会改变实验条件,需要记录。
这是一个三轮集成试跑,不是适用于所有蛋白质的优化轮数建议,也不构成基准结果。
4. 分清输出对应哪个阶段
对于仓库示例,在 outputs/tutorial-mixed/ 中检查:
| 产物 | 检查内容 |
|---|---|
example_complex_records.json |
已完成循环、分支名称、分数、序列和耗时 |
recycle_1/mpnn/mpnn_spec.json |
第一轮 MPNN 固定了哪些残基 |
recycle_1/mpnn/mpnn_result.json |
MPNN 序列与传递给下一轮的信息 |
inputs/example_complex_1.pdb |
第一轮结束后传入下一轮的重设计复合物 |
recycle_1/rf3_config.yaml |
选择 RF3 分支时生成的本轮配置 |
记录中的循环编号从 0 开始,文件夹从 recycle_1 开始。记录中的分数来自本轮 MPNN 重设计之前的结构预测或优化分支;mpnn_sequence 则是之后生成的序列。不能把这些分数直接当作新序列经过独立重新折叠后的评分。这个执行顺序可以在主循环源码中核对。
还有两个容易误读的细节。增加 mpnn_num_seqs 会保存更多样本,但程序仍然将第一个样本传入下一轮,没有对样本排序。另外,Boltz 分支中的 AF3_Status 是沿用的字段名称,不表示运行了 AlphaFold3。应结合 method 字段和实际模型输出判断。独立 AF3 筛选不属于这个流水线。
5. 用 Python 检查已完成循环
下面的脚本只依赖 Python 标准库。它检查循环数量、连续编号、分支名称、标准氨基酸序列、链长度一致性,以及耗时是否为有限非负数。脚本不检查坐标,也不解释置信度评分。
下载 check_rfo_records.py,或保存下面的完整代码:
curl -fL https://www.bobobk.com/downloads/rfoptimization/check_rfo_records.py \
-o check_rfo_records.py
python3 check_rfo_records.py --help
#!/usr/bin/env python3
"""Audit completed RFO cycles; this does not evaluate molecular quality."""
import argparse
from collections import Counter
import json
import math
from pathlib import Path
def audit(records, expected):
if expected < 1:
raise ValueError("expected cycle count must be positive")
if not isinstance(records, list) or not records:
raise ValueError("records must be a nonempty JSON list")
if len(records) != expected:
raise ValueError(f"expected {expected} cycles, found {len(records)}")
methods = Counter()
sequences = []
seconds = 0.0
for index, row in enumerate(records):
if not isinstance(row, dict):
raise ValueError(f"record {index}: expected an object")
cycle = row.get("cycle")
if type(cycle) is not int or cycle != index:
raise ValueError(f"record {index}: expected zero-based cycle {index}")
method = row.get("method")
if method not in ("RF3", "Boltz"):
raise ValueError(f"cycle {index}: unknown method")
sequence = row.get("mpnn_sequence")
if not isinstance(sequence, str) or not sequence:
raise ValueError(f"cycle {index}: missing MPNN sequence")
if set(sequence) - set("ACDEFGHIKLMNPQRSTVWY"):
raise ValueError(f"cycle {index}: nonstandard amino acid")
if sequences and len(sequence) != len(sequences[0]):
raise ValueError(f"cycle {index}: chain-A length changed")
elapsed = row.get("wall_time_sec")
if (type(elapsed) not in (int, float)
or not math.isfinite(elapsed) or elapsed < 0):
raise ValueError(f"cycle {index}: invalid wall_time_sec")
methods[method] += 1
sequences.append(sequence)
seconds += elapsed
return {
"completed_cycles": len(records),
"methods": dict(sorted(methods.items())),
"chain_a_length": len(sequences[0]),
"unique_handoff_sequences": len(set(sequences)),
"recorded_cycle_seconds": round(seconds, 2),
"quality_evaluated": False,
}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("records", type=Path)
parser.add_argument("--expected-cycles", required=True, type=int)
args = parser.parse_args()
try:
records = json.loads(args.records.read_text(encoding="utf-8"))
result = audit(records, args.expected_cycles)
except (OSError, UnicodeError, ValueError) as exc:
parser.exit(1, f"ERROR: {exc}\n")
print(json.dumps(result, indent=2, allow_nan=False))
if __name__ == "__main__":
main()
先用这个合成样例试跑。序列和耗时均为演示检查器而编造,不是 RFO 预测结果或性能测量。
python3 - <<'PY'
import json
from pathlib import Path
records = [
{"cycle": 0, "method": "RF3", "mpnn_sequence": "ACDEFG",
"wall_time_sec": 12.5},
{"cycle": 1, "method": "Boltz", "mpnn_sequence": "ACDEYG",
"wall_time_sec": 20.0},
]
Path("synthetic_records.json").write_text(json.dumps(records))
PY
python3 check_rfo_records.py synthetic_records.json --expected-cycles 2
预期输出:
{
"completed_cycles": 2,
"methods": {
"Boltz": 1,
"RF3": 1
},
"chain_a_length": 6,
"unique_handoff_sequences": 2,
"recorded_cycle_seconds": 32.5,
"quality_evaluated": false
}
检查真实三轮任务时,将脚本保存在 foundry/models/rfo,并从该目录执行:
python3 check_rfo_records.py \
outputs/tutorial-mixed/example_complex_records.json --expected-cycles 3
非零退出码表示记录没有通过这些检查。检查成功只说明记录满足一致性要求。recorded_cycle_seconds 汇总已保存的完整循环耗时,不包含未形成记录的失败尝试,也不是整个任务的总耗时。脚本统计重复序列但不拒绝它们,因为传入下一轮的序列保持不变也可能是有效结果。
6. 排错与结果评估
| 现象 | 处理方式 |
|---|---|
| 找不到 MPNN 程序或权重 | 检查 MPNN_REPO/run.py、MPNN_PYTHON 的绝对路径,以及上游 model_params 目录 |
| RF3 权重被拒绝 | 将 RF3_CKPT 指向支持置信度预测且包含训练配置的权重 |
| 找不到输入文件 | 从 foundry/models/rfo 运行,或把输入路径改为绝对路径 |
| 记录数少于请求轮数 | 查看失败模型的日志;创建了目录不代表任务完成 |
| 有多个 MPNN 样本,下一轮却只有一个输入 | 单独检查保存的样本;当前程序只传递第一个样本 |
| 分数变好,但新序列尚未评估 | 用实际保存的序列和预定伙伴进行单独重新折叠评估 |
比较不同任务之前,先确定评估规则。保留初始候选,明确允许从哪些循环选择结果,并对初始设计和优化设计使用相同评估器与输入条件。统计通过率时,不要把失败或缺失评估悄悄移出分母。计算置信度可以用于排序;结合、特异性、稳定性和活性仍需相应测量。
如果研究环肽,还要单独检查实现:cyclic: true 会传给 Boltz,标记 A 链为环状,但此版本的 RF3 优化器没有添加显式成环键约束。循环文档说明了这个限制。上述蛋白复合物试跑不能验证环肽行为。
7. 总结
先检查输入复合物,分别验证两个模型分支,再保留每轮传递的实际序列。用记录检查脚本发现未完成任务,然后独立评估优化后的序列。RFOptimization 提供的是带有可追踪优化过程的候选设计,实验是否成功仍需另行确认。
- 原文作者:春江暮客
- 原文链接:https://www.bobobk.com/rfoptimization-protein-design-guide.html
- 版权声明:本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。