From e3f9d9e9db015b4ea5a6155f37f1762911b3c88d Mon Sep 17 00:00:00 2001 From: RYDE-WORK Date: Sat, 28 Feb 2026 17:08:22 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E5=8F=82=E6=95=B0=E7=BB=9F=E8=AE=A1=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lnp_ml/modeling/benchmark.py | 4 +++- lnp_ml/modeling/pretrain.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lnp_ml/modeling/benchmark.py b/lnp_ml/modeling/benchmark.py index 2c6be78..3ad7ac9 100644 --- a/lnp_ml/modeling/benchmark.py +++ b/lnp_ml/modeling/benchmark.py @@ -416,7 +416,9 @@ def main( model.rdkit_encoder._cache = rdkit_cache logger.info(f"Reusing RDKit cache with {len(rdkit_cache)} entries") - logger.info(f"Model parameters: {sum(p.numel() for p in model.parameters()):,}") + n_params_total = sum(p.numel() for p in model.parameters()) + n_params_trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) + logger.info(f"Model parameters: {n_params_total:,} total, {n_params_trainable:,} trainable") # 训练 result = train_fold( diff --git a/lnp_ml/modeling/pretrain.py b/lnp_ml/modeling/pretrain.py index abb702d..b7d9d66 100644 --- a/lnp_ml/modeling/pretrain.py +++ b/lnp_ml/modeling/pretrain.py @@ -303,8 +303,9 @@ def main( dropout=dropout, ) - n_params = sum(p.numel() for p in model.parameters() if p.requires_grad) - logger.info(f"Model parameters: {n_params:,}") + n_params_total = sum(p.numel() for p in model.parameters()) + n_params_trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) + logger.info(f"Model parameters: {n_params_total:,} total, {n_params_trainable:,} trainable") # 预热 RDKit 缓存(避免训练时阻塞) all_smiles = train_df["smiles"].tolist() + val_df["smiles"].tolist() From a7db8ffc151d018d8dd9266587b9dff0995a6f65 Mon Sep 17 00:00:00 2001 From: RYDE-WORK Date: Sat, 28 Feb 2026 17:32:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E7=BC=A9=E5=B0=8Fd=5Fmodel/num=5Fheads/n?= =?UTF-8?q?=5Fattn=5Flayers/hidden=5Fdim=E6=88=96=E8=80=85=E5=A2=9E?= =?UTF-8?q?=E5=A4=A7=E6=AD=A3=E5=88=99=E5=8C=96=E5=90=8E,=E6=AC=A0?= =?UTF-8?q?=E6=8B=9F=E5=90=88,=E6=81=A2=E5=A4=8D=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lnp_ml/modeling/benchmark.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lnp_ml/modeling/benchmark.py b/lnp_ml/modeling/benchmark.py index 3ad7ac9..6ac6b20 100644 --- a/lnp_ml/modeling/benchmark.py +++ b/lnp_ml/modeling/benchmark.py @@ -284,11 +284,11 @@ def main( data_dir: Path = PROCESSED_DATA_DIR / "benchmark", output_dir: Path = MODELS_DIR / "benchmark", # 模型参数 - d_model: int = 128, - num_heads: int = 4, - n_attn_layers: int = 2, + d_model: int = 256, + num_heads: int = 8, + n_attn_layers: int = 4, fusion_strategy: str = "attention", - head_hidden_dim: int = 64, + head_hidden_dim: int = 128, dropout: float = 0.1, # MPNN 参数 use_mpnn: bool = False, From 74fd012f1361123c991780cb53511e0a3115ee5e Mon Sep 17 00:00:00 2001 From: RYDE-WORK Date: Sat, 28 Feb 2026 17:51:40 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=AD=A6=E4=B9=A0=E7=8E=87=E7=AD=96=E7=95=A5=E4=B8=BA=E7=BA=BF?= =?UTF-8?q?=E6=80=A7=E9=A2=84=E7=83=AD+=E4=BD=99=E5=BC=A6=E9=80=80?= =?UTF-8?q?=E7=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lnp_ml/modeling/benchmark.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lnp_ml/modeling/benchmark.py b/lnp_ml/modeling/benchmark.py index 6ac6b20..42f2ff5 100644 --- a/lnp_ml/modeling/benchmark.py +++ b/lnp_ml/modeling/benchmark.py @@ -1,6 +1,7 @@ """Benchmark 脚本:在 baseline 论文公开的 CV 划分上评估模型(仅 delivery 任务)""" import json +import math from pathlib import Path from typing import Dict, List, Optional @@ -9,6 +10,7 @@ import pandas as pd import torch import torch.nn as nn from torch.utils.data import DataLoader +from torch.optim.lr_scheduler import LambdaLR, CosineAnnealingLR, SequentialLR from loguru import logger from tqdm import tqdm from sklearn.metrics import mean_squared_error, r2_score @@ -158,6 +160,7 @@ def train_fold( weight_decay: float = 1e-5, epochs: int = 50, patience: int = 10, + warmup_epochs: int = 3, config: Optional[Dict] = None, ) -> Dict: """训练单个 fold""" @@ -166,9 +169,19 @@ def train_fold( logger.info(f"{'='*60}") optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=weight_decay) - scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( - optimizer, mode="min", factor=0.5, patience=5 + + warmup_scheduler = LambdaLR( + optimizer, lr_lambda=lambda epoch: (epoch + 1) / warmup_epochs ) + cosine_scheduler = CosineAnnealingLR( + optimizer, T_max=epochs - warmup_epochs + ) + scheduler = SequentialLR( + optimizer, + schedulers=[warmup_scheduler, cosine_scheduler], + milestones=[warmup_epochs], + ) + early_stopping = EarlyStopping(patience=patience) best_val_loss = float("inf") @@ -198,7 +211,7 @@ def train_fold( "lr": current_lr, }) - scheduler.step(val_metrics["loss"]) + scheduler.step() if val_metrics["loss"] < best_val_loss: best_val_loss = val_metrics["loss"]