lnp_ml/docs/colab_selfiested_quickstart.md

8.6 KiB
Raw Permalink Blame History

LNP-ML + SELFIES-TED 快速上手指南

适用于:拿到代码包、从未运行过任何代码的新组员。

论文IBM, "A Large Encoder-Decoder Family of Foundation Models for Chemical Language" (2024-2025) 模型ibm/materials.selfies-ted358M 参数BART 架构,无需手动下载,训练时自动从 HuggingFace 拉取)


⚠️ 与前几个模型的三个关键区别

  1. 必须用 GPU 运行时(模型 358MCPU 会非常慢)。开始前先确认硬件加速器选了 GPU。
  2. 需要额外安装 selfies 库(用于 SMILES → SELFIES 转换)。
  3. hidden size 是 1024(前几个模型是 768 或 300这已经在 encoder 代码里处理好了。

前提条件(开始前确认)

  • Google Drive 的 MyDrive/lnp_project_selfiested/ 下已有:
    • lnp_ml/:项目代码(从 BioT5 版本复制来的,已修改)
    • SELFIES-TED 权重无需提前下载,训练时自动拉取

如果文件夹不存在,先看文末的【从零开始】章节。


第一步:确认 GPU

菜单栏 → 代码执行程序 → 更改运行时类型 → 硬件加速器选 GPU → 保存。

然后运行:

import torch
print(f"GPU 可用: {torch.cuda.is_available()}")

显示 True 再继续。如果是 False,按上面的步骤切换 GPU。


每次重新打开 Colab 都需要运行

Cell 1挂载 Drive

from google.colab import drive
drive.mount('/content/drive')

弹出授权页面时,确认选择有 lnp_project_selfiested 的 Google 账号。


Cell 2安装依赖注意多了 selfies

!pip install rdkit loguru transformers sentencepiece optuna selfies -q

Cell 3配置路径

import os, sys

LNP_PATH = "/content/drive/MyDrive/lnp_project_selfiested/lnp_ml"

sys.path.insert(0, LNP_PATH)
os.chdir(LNP_PATH)

import torch
print(f"路径配置完成 ✓ | GPU 可用: {torch.cuda.is_available()}")

Cell 4确认文件完整

checks = [
    f"{LNP_PATH}/lnp_ml/modeling/models.py",
    f"{LNP_PATH}/lnp_ml/modeling/encoders/selfiested_encoder.py",
    f"{LNP_PATH}/lnp_ml/modeling/encoders/__init__.py",
    f"{LNP_PATH}/data/processed/train.parquet",
    f"{LNP_PATH}/data/processed/val.parquet",
    f"{LNP_PATH}/data/processed/test.parquet",
    f"{LNP_PATH}/data/processed/train_pretrain.parquet",
    f"{LNP_PATH}/data/processed/val_pretrain.parquet",
]
for f in checks:
    print(f"{'✓' if os.path.exists(f) else '✗ 缺失'} {f}")

所有文件都显示 ✓ 再继续。


正式流程

Cell 5验证 SELFIES-TED 模块

!PYTHONPATH={LNP_PATH} \
 python {LNP_PATH}/verify_llm_encoder.py \
    --model_path "ibm/materials.selfies-ted" \
    --lnp_repo_path "{LNP_PATH}"

正常输出:

TEST 1 PASSED ✓
TEST 2 PASSED ✓
TEST 3 PASSED ✓
TEST 4 PASSED ✓
ALL TESTS PASSED ✓

Cell 6预训练约 10 分钟)

!PYTHONPATH={LNP_PATH} \
 python -m lnp_ml.modeling.pretrain main \
    --train-path data/processed/train_pretrain.parquet \
    --val-path   data/processed/val_pretrain.parquet \
    --epochs 50 \
    --lr 1e-4 \
    --device cuda

完成后确认权重存在:

print("✓ 预训练权重存在" if os.path.exists(f"{LNP_PATH}/models/pretrain_delivery.pt")
      else "✗ 预训练权重未生成")

参考结果:Best val_loss: 0.5659


Cell 7正式训练约 25-30 分钟,比前几个模型略慢)

!PYTHONPATH={LNP_PATH} \
 python lnp_ml/modeling/final_train_optuna_cv.py \
    --init-from-pretrain models/pretrain_delivery.pt \
    --use-llm \
    --llm-model-path "ibm/materials.selfies-ted" \
    --llm-device cuda \
    --n-trials 20 \
    --epochs-per-trial 30 \
    --seed 42 \
    --device cuda \
    --output-dir models/final

完成后确认:

print("✓ 模型权重存在" if os.path.exists(f"{LNP_PATH}/models/final/model.pt")
      else "✗ 模型未生成")

Cell 8测试评估

!PYTHONPATH={LNP_PATH} \
 python lnp_ml/modeling/predict.py test \
    --test-path  data/processed/test.parquet \
    --model-path models/final/model.pt \
    --output-path models/final/test_results.json

import json
with open(f'{LNP_PATH}/models/final/test_results.json') as f:
    results = json.load(f)

print("=== 分类任务 ===")
for task in ['pdi', 'ee', 'toxic']:
    m = results['detailed_metrics'][task]
    print(f"  {task}: acc={m['accuracy']:.4f}, f1={m['f1']:.4f}")

print("\n=== 回归任务 ===")
for task in ['size', 'delivery']:
    m = results['detailed_metrics'][task]
    print(f"  {task}: R²={m['r2']:.4f}, RMSE={m['rmse']:.4f}")

print("\n=== 分布任务 ===")
m = results['detailed_metrics']['biodist']
print(f"  biodist: KL={m['kl_divergence']:.4f}, JS={m['js_divergence']:.4f}")

参考指标:

任务 指标 参考值
delivery ~0.62
size ~0.38
pdi acc ~0.66
ee acc ~0.68
toxic acc ~0.94
biodist KL ~0.64

Cell 9备份模型

!cp -r {LNP_PATH}/models/final \
        {LNP_PATH}/models/final_backup
print("备份完成 ✓")

如果已有训练好的模型,直接从 Cell 8 开始

只需运行 Cell 1 → Cell 2 → Cell 3 → Cell 8跳过 Cell 4-7。


常见问题

报错 原因 解决方法
Device: cpu 或训练极慢 没选 GPU 运行时 菜单 → 更改运行时类型 → 选 GPU
No module named 'selfies' selfies 库未装 重新运行 Cell 2
No module named 'rdkit' 依赖未安装 重新运行 Cell 2
No module named 'lnp_ml' 路径未配置 重新运行 Cell 3
'NoneType' has no attribute 'Study' optuna 未安装 重新运行 Cell 2
Mountpoint must not already contain files Drive 缓存混乱 菜单 → 运行时 → 重新启动运行时,再从 Cell 1 开始
Colab 断开后重连 环境变量丢失 从 Cell 1 重跑Cell 6/7 已有权重可跳过

【从零开始】如果 lnp_project_selfiested 不存在

Step A从 BioT5 版本复制代码

import os
os.makedirs("/content/drive/MyDrive/lnp_project_selfiested", exist_ok=True)

!cp -r "/content/drive/MyDrive/lnp_project_biot5-plus/lnp_ml" \
        "/content/drive/MyDrive/lnp_project_selfiested/lnp_ml"
print("代码复制完成 ✓")

Step B上传 selfiested_encoder.py

from google.colab import files
import shutil

uploaded = files.upload()  # 选择 selfiested_encoder.py

shutil.copy(
    'selfiested_encoder.py',
    '/content/drive/MyDrive/lnp_project_selfiested/lnp_ml/lnp_ml/modeling/encoders/selfiested_encoder.py'
)
print("上传完成 ✓")

Step C修改代码文件

# Step C-1更新 __init__.py
path = "/content/drive/MyDrive/lnp_project_selfiested/lnp_ml/lnp_ml/modeling/encoders/__init__.py"
with open(path, 'w') as f:
    f.write("""from lnp_ml.modeling.encoders.rdkit_encoder import CachedRDKitEncoder
from lnp_ml.modeling.encoders.mpnn_encoder import CachedMPNNEncoder
from .llm_encoder import LLMEncoder
from .selfiested_encoder import SELFIESTEDEncoder

__all__ = ["CachedRDKitEncoder", "CachedMPNNEncoder", "LLMEncoder", "SELFIESTEDEncoder"]
""")
print("__init__.py ✓")
# Step C-2更新 models.py
path = "/content/drive/MyDrive/lnp_project_selfiested/lnp_ml/lnp_ml/modeling/models.py"
with open(path, 'r') as f:
    content = f.read()
content = content.replace(
    "from lnp_ml.modeling.encoders import CachedRDKitEncoder, CachedMPNNEncoder, LLMEncoder",
    "from lnp_ml.modeling.encoders import CachedRDKitEncoder, CachedMPNNEncoder, LLMEncoder, SELFIESTEDEncoder"
)
content = content.replace(
    "self.llm_encoder = LLMEncoder(",
    "self.llm_encoder = SELFIESTEDEncoder("
)
with open(path, 'w') as f:
    f.write(content)
print("models.py ✓")
# Step C-3修复 verify 脚本(属性名是 _model
path = "/content/drive/MyDrive/lnp_project_selfiested/lnp_ml/verify_llm_encoder.py"
with open(path, 'r') as f:
    content = f.read()
content = content.replace(
    "from lnp_ml.modeling.encoders.llm_encoder import LLMEncoder",
    "from lnp_ml.modeling.encoders.selfiested_encoder import SELFIESTEDEncoder as LLMEncoder"
)
content = content.replace(
    "encoder._llm.named_parameters()",
    "encoder._model.named_parameters()"
)
content = content.replace(
    "model.llm_encoder._llm.parameters()",
    "model.llm_encoder._model.parameters()"
)
with open(path, 'w') as f:
    f.write(content)
print("verify_llm_encoder.py ✓")

完成后从【第一步:确认 GPU】开始正常运行。