Chem-World / scripts /run_model.py
TianyouBai's picture
Upload 16 files
fc8da88 verified
Raw
History Blame Contribute Delete
6.27 kB
import argparse
import os
import torch
import sys
import copy
import traceback
from torch.utils.data import DataLoader
from torch.utils.data import Subset
from omegaconf import OmegaConf
if "src" not in sys.path:
sys.path.insert(0, "src")
VERBOSE = False
def debug(message: str) -> None:
if VERBOSE:
print(f"[run_model] {message}", flush=True)
def load_runtime():
debug("Importing mixhub.data.dataset")
from mixhub.data.dataset import MixtureTask
debug("Importing mixhub.data.data")
from mixhub.data.data import DATA_CATALOG
debug("Importing mixhub.data.featurization_types")
from mixhub.data.featurization_types import FEATURIZATION_TYPE
debug("Importing mixhub.data.collate")
from mixhub.data.collate import custom_collate
debug("Importing mixhub.data.splits")
from mixhub.data.splits import SplitLoader
debug("Importing mixhub.model.train")
from mixhub.model.train import train
debug("Importing mixhub.model.model_builder")
from mixhub.model.model_builder import build_mixture_model
return {
"MixtureTask": MixtureTask,
"DATA_CATALOG": DATA_CATALOG,
"FEATURIZATION_TYPE": FEATURIZATION_TYPE,
"custom_collate": custom_collate,
"SplitLoader": SplitLoader,
"train": train,
"build_mixture_model": build_mixture_model,
}
def main(
config,
experiment_name,
wandb_logger=None,
):
config = copy.deepcopy(config)
runtime = load_runtime()
MixtureTask = runtime["MixtureTask"]
DATA_CATALOG = runtime["DATA_CATALOG"]
FEATURIZATION_TYPE = runtime["FEATURIZATION_TYPE"]
custom_collate = runtime["custom_collate"]
SplitLoader = runtime["SplitLoader"]
train = runtime["train"]
build_mixture_model = runtime["build_mixture_model"]
torch.manual_seed(config.seed)
device = torch.device(config.device)
print(f"Running on: {device}", flush=True)
root_dir = config.root_dir
os.makedirs(root_dir, exist_ok=True)
featurization = config.dataset.featurization
if FEATURIZATION_TYPE[featurization] == "graphs" and config.mixture_model.mol_encoder.type != "gnn":
raise ValueError(f"featurization is:{FEATURIZATION_TYPE[featurization]} but molecule encoder is: {config.mol_encoder.type}")
if FEATURIZATION_TYPE[featurization] == "tensors" and config.mixture_model.mol_encoder.type == "gnn":
raise ValueError(f"featurization is:{FEATURIZATION_TYPE[featurization]} but molecule encoder is: {config.mol_encoder.type}")
# Dataset
debug(f"Loading dataset: {config.dataset.name}")
dataset = DATA_CATALOG[config.dataset.name]()
property = config.dataset.property
debug(
"Building MixtureTask "
f"(property={property}, featurization={featurization})"
)
mixture_task = MixtureTask(
property=property,
dataset=dataset,
featurization=featurization,
)
debug(f"MixtureTask ready with {len(mixture_task)} samples")
# Split Loader
split_loader = SplitLoader(split_type="kfold")
debug("Loading split 0 indices")
train_indices, val_indices, _ = split_loader(
property=mixture_task.property,
cache_dir=mixture_task.dataset.data_dir,
split_num=0,
)
debug(f"Split 0 sizes: train={len(train_indices)}, val={len(val_indices)}")
# Data Loader
debug("Creating DataLoaders")
train_dataset = Subset(mixture_task, train_indices.tolist())
val_dataset = Subset(mixture_task, val_indices.tolist())
train_loader = DataLoader(
train_dataset,
batch_size=config.batch_size,
shuffle=True,
collate_fn=custom_collate,
num_workers=config.num_workers,
pin_memory=True,
)
val_loader = DataLoader(
val_dataset,
batch_size=config.batch_size,
collate_fn=custom_collate,
num_workers=config.num_workers,
)
debug("Building model")
model = build_mixture_model(config=config.mixture_model)
debug(f"Moving model to {device}")
model = model.to(device)
# Save hyper parameters
OmegaConf.save(config, f"{root_dir}/hparams_{experiment_name}.yaml")
# Training
debug("Starting training")
train(
root_dir=root_dir,
model=model,
train_loader=train_loader,
val_loader=val_loader,
loss_type=config.loss_type,
lr_mol_encoder=config.lr_mol_encoder,
lr_other=config.lr_other,
device=device,
weight_decay=config.weight_decay,
max_epochs=config.max_epochs,
patience=config.patience,
experiment_name=experiment_name,
wandb_logger=wandb_logger,
)
debug("Finished training")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Run model training and evaluation on a random split")
parser.add_argument("config", type=str, help="Path to the YAML configuration file")
parser.add_argument("--experiment_name", type=str, default="test_run", help="Name of the experiment")
parser.add_argument("--wandb_project", type=str, default=None, help="Name of the wandb project (optional)")
parser.add_argument("--verbose", action="store_true", help="Print detailed diagnostic logs")
args = parser.parse_args()
VERBOSE = args.verbose
if VERBOSE:
os.environ["CHEMIXHUB_VERBOSE"] = "1"
try:
debug(f"Loading config from {args.config}")
config = OmegaConf.load(args.config)
experiment_name = args.experiment_name
if args.wandb_project is not None:
try:
from torchtune.training.metric_logging import WandBLogger
except ImportError as exc:
raise ImportError(
"torchtune is required for WandB logging. Install torchtune/torchao or run without --wandb_project."
) from exc
wandb_logger = WandBLogger(project=args.wandb_project)
else:
wandb_logger = None
main(
config=config,
experiment_name=experiment_name,
wandb_logger=wandb_logger,
)
except Exception as exc:
print(f"Execution failed: {exc}", flush=True)
traceback.print_exc()
raise