| |
| |
|
|
| |
|
|
|
|
| |
| |
| import os |
| import sys |
| import json |
| import yaml |
| import numpy as np |
| import copy |
| import math |
| import time |
| import random |
| from tqdm.auto import tqdm |
| import webdataset as wds |
| import matplotlib.pyplot as plt |
|
|
| import torch |
| import torch.nn as nn |
| from torchvision import transforms |
| import utils |
| from mae_utils.flat_models import * |
| import h5py |
| from mae_utils import flat_models |
| import pandas as pd |
| from sklearn.preprocessing import StandardScaler |
| from typing import List, Dict, Any, Tuple |
| import argparse |
|
|
| |
| torch.backends.cuda.matmul.allow_tf32 = True |
| |
| torch.backends.cudnn.benchmark = True |
|
|
|
|
|
|
|
|
| |
|
|
|
|
| |
| if utils.is_interactive(): |
| model_name_suffix = "testing" |
| print("model_name_suffix:", model_name_suffix) |
| |
| |
| jupyter_args = f"--found_model_name=HCPflat_large_gsrFalse_ --epoch_checkpoint epoch99.pth \ |
| --hcp_flat_path=/weka/proj-medarc/shared/HCP-Flat \ |
| --target=sex \ |
| --model_suffix={model_name_suffix} \ |
| --batch_size={batch_size} \ |
| --max_lr=3e-4 --num_epochs=20 --no-save_ckpt --no-wandb_log --num_workers=10 \ |
| --weight_decay=1e-5 \ |
| --global_pool" |
| |
|
|
| print(jupyter_args) |
| jupyter_args = jupyter_args.split() |
| |
| from IPython.display import clear_output |
| get_ipython().run_line_magic('load_ext', 'autoreload') |
| |
| get_ipython().run_line_magic('autoreload', '2') |
|
|
|
|
| |
|
|
|
|
| parser = argparse.ArgumentParser(description="Model Training Configuration") |
| parser.add_argument( |
| "--found_model_name", type=str, default="Testing_flat", |
| help="name of model, used for ckpt saving and wandb logging (if enabled)", |
| ) |
| parser.add_argument( |
| "--epoch_checkpoint", type=str, default="epoch99.pth", |
| help="the epoch number of the found_model_name checkpoint", |
| ) |
| parser.add_argument( |
| "--model_suffix", type=str, default="Testing_flat", |
| help="name of model, used for ckpt saving and wandb logging (if enabled)", |
| ) |
| parser.add_argument( |
| "--hcp_flat_path", type=str, default=os.getcwd(), |
| help="Path to where NSD data is stored / where to download it to", |
| ) |
| parser.add_argument( |
| "--batch_size", type=int, default=128, |
| help="Batch size can be increased by 10x if only training retreival submodule and not diffusion prior", |
| ) |
| parser.add_argument( |
| "--wandb_log",action=argparse.BooleanOptionalAction,default=False, |
| help="whether to log to wandb", |
| ) |
| parser.add_argument( |
| "--num_epochs",type=int,default=150, |
| help="number of epochs of training", |
| ) |
| parser.add_argument( |
| "--lr_scheduler_type",type=str,default='cycle',choices=['cycle','linear'], |
| ) |
| parser.add_argument( |
| "--save_ckpt",action=argparse.BooleanOptionalAction,default=True, |
| ) |
| parser.add_argument( |
| "--seed",type=int,default=42, |
| ) |
| parser.add_argument( |
| "--max_lr",type=float,default=3e-4, |
| ) |
| parser.add_argument( |
| "--target",type=str,default='trial_type',choices=['trial_type','sex','age'], |
| ) |
| parser.add_argument( |
| "--num_workers",type=int,default=10, |
| ) |
| parser.add_argument( |
| "--weight_decay",type=float,default=1e-5, |
| ) |
| parser.add_argument( |
| "--global_pool",action=argparse.BooleanOptionalAction,default=False, |
| help="not implemented yet", |
| ) |
|
|
| if utils.is_interactive(): |
| args = parser.parse_args(jupyter_args) |
| else: |
| args = parser.parse_args() |
|
|
| print(f"------ ARGS ------- \n {args}") |
|
|
| |
| for attribute_name in vars(args).keys(): |
| globals()[attribute_name] = getattr(args, attribute_name) |
| |
| |
| utils.seed_everything(seed) |
|
|
|
|
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| |
|
|
|
|
| |
| outdir = os.path.abspath(f'checkpoints/{found_model_name}') |
|
|
| print("outdir", outdir) |
| |
| if os.path.exists(f"{outdir}/config.yaml"): |
| config = yaml.load(open(f"{outdir}/config.yaml", 'r'), Loader=yaml.FullLoader) |
| print(f"Loaded config.yaml from ckpt folder {outdir}") |
| |
| print("\n__CONFIG__") |
| for attribute_name in config.keys(): |
| print(f"{attribute_name} = {config[attribute_name]}") |
| globals()[attribute_name] = config[f'{attribute_name}'] |
| print("\n") |
|
|
| world_size = os.getenv('WORLD_SIZE') |
| if world_size is None: |
| world_size = 1 |
| else: |
| world_size = int(world_size) |
| print(f"WORLD_SIZE={world_size}") |
|
|
| if utils.is_interactive(): |
| |
| |
| get_ipython().run_line_magic('load_ext', 'autoreload') |
| get_ipython().run_line_magic('autoreload', '2') |
|
|
| |
| |
|
|
| data_type = torch.float32 |
| global_batch_size = batch_size * world_size |
|
|
| device = torch.device('cuda') |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| print("PID of this process =",os.getpid()) |
| utils.seed_everything(seed) |
|
|
|
|
| |
|
|
|
|
| |
| |
| |
| |
| print(f"global_pool = {global_pool}") |
|
|
| try: |
| gsr |
| except: |
| gsr = True |
| print("set gsr to True") |
| print(f"gsr = {gsr}") |
|
|
| for attribute_name in vars(args).keys(): |
| globals()[attribute_name] = getattr(args, attribute_name) |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
|
|
|
|
| |
|
|
| |
|
|
|
|
| from sklearn.preprocessing import LabelEncoder |
| if target == "trial_type": |
| |
| INCLUDE_CONDS = { |
| "fear", |
| "neut", |
| "math", |
| "story", |
| "lf", |
| "lh", |
| "rf", |
| "rh", |
| "t", |
| "match", |
| "relation", |
| "mental", |
| "rnd", |
| "0bk_body", |
| "2bk_body", |
| "0bk_faces", |
| "2bk_faces", |
| "0bk_places", |
| "2bk_places", |
| "0bk_tools", |
| "2bk_tools", |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| label_encoder = LabelEncoder() |
| label_encoder.fit(sorted(INCLUDE_CONDS)) |
| |
| num_classes = len(label_encoder.classes_) |
| print(f"Number of classes: {num_classes}") |
|
|
|
|
| |
|
|
|
|
| f_train = h5py.File('/weka/proj-fmri/ckadirt/fMRI-foundation-model/src/train_hcp.hdf5', 'r') |
| flatmaps_train = f_train['flatmaps'] |
|
|
| f_test = h5py.File('/weka/proj-fmri/ckadirt/fMRI-foundation-model/src/test_hcp.hdf5', 'r') |
| flatmaps_test = f_test['flatmaps'] |
|
|
| metadata_train = np.load('/weka/proj-fmri/ckadirt/fMRI-foundation-model/src/metadata_train_HCP.npy', allow_pickle=True) |
| metadata_test = np.load('/weka/proj-fmri/ckadirt/fMRI-foundation-model/src/metadata_test_HCP.npy', allow_pickle=True) |
|
|
|
|
| |
|
|
|
|
| from torch.utils.data import Dataset, DataLoader |
|
|
| class HCPFlatDataset(Dataset): |
| def __init__(self, flatmaps, metadata): |
| self.flatmaps = flatmaps |
| self.metadata = metadata |
|
|
| def __len__(self): |
| return len(self.metadata) |
|
|
| def __getitem__(self, idx): |
| return self.flatmaps[idx], json.loads(self.metadata[idx]) |
| print("Creating datasets") |
| |
| train_dataset = HCPFlatDataset(flatmaps_train, metadata_train) |
| train_dl = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) |
|
|
| test_dataset = HCPFlatDataset(flatmaps_test, metadata_test) |
| test_dl = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=0) |
| print("Datasets ready") |
|
|
|
|
| |
|
|
|
|
| |
| if target == "age" or target == "sex": |
| subject_information_HCP_path = os.path.join(hcp_flat_path, "subjects_data_restricted.csv") |
| try: |
| subject_information_HCP = pd.read_csv(subject_information_HCP_path) |
| except: |
| try: |
| subject_information_HCP = pd.read_csv('./unrestricted_clane9_4_23_2024_13_28_14.csv') |
| except: |
| assert False, "Subject information file not found" |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| gender_related_columns = [ |
| 'Gender' |
| ] |
|
|
| age_related_columns = [ |
| 'Age_in_Yrs', |
| 'Menstrual_AgeBegan', |
| 'Menstrual_AgeIrreg', |
| 'Menstrual_AgeStop', |
| 'SSAGA_Alc_Age_1st_Use', |
| 'SSAGA_TB_Age_1st_Cig', |
| 'SSAGA_Mj_Age_1st_Use', |
| 'Endurance_AgeAdj', |
| 'Dexterity_AgeAdj', |
| 'Strength_AgeAdj', |
| 'PicSeq_AgeAdj', |
| 'CardSort_AgeAdj', |
| 'Flanker_AgeAdj', |
| 'ReadEng_AgeAdj', |
| 'PicVocab_AgeAdj', |
| 'ProcSpeed_AgeAdj', |
| 'Odor_AgeAdj', |
| 'Taste_AgeAdj' |
| ] |
|
|
| |
| |
|
|
| |
| mean_age = subject_information_HCP['Age_in_Yrs'].mean() |
| |
| |
| scaler = StandardScaler() |
| |
| |
| subject_information_HCP['Age_in_Yrs_z'] = scaler.fit_transform(subject_information_HCP[['Age_in_Yrs']]) |
|
|
|
|
| |
| def get_label_unrestricted(subject_id: List[str], target: str, method_for_age: str = 'mean') -> List: |
| """ |
| Get the label for the given subject id and target. |
| |
| For sex 0 is F and 1 is M |
| """ |
|
|
| |
| subject_id = [int(x) for x in subject_id] |
|
|
| if target == "age": |
| age_array = [] |
| for subject in subject_id: |
| c_age = subject_information_HCP[subject_information_HCP['Subject'] == subject]['Age'].values |
| |
| if len(c_age) == 0: |
| assert False, f"Subject {subject} not found in subject information file" |
| if len(c_age) > 1: |
| print(f"Warning: Multiple entries for subject {subject}") |
|
|
| c_age = c_age[0].split('-') |
| if len(c_age) < 2: |
| c_age = c_age[0].split('+') |
| age_array.append(int(c_age[0])) |
| else: |
| if method_for_age == 'mean': |
| age_array.append(np.mean([int(x) for x in c_age])) |
| elif method_for_age == 'min': |
| age_array.append(np.min([int(x) for x in c_age])) |
| elif method_for_age == 'max': |
| age_array.append(np.max([int(x) for x in c_age])) |
| else: |
| assert False, f"Method {method_for_age} not recognized" |
|
|
| return np.array(age_array) |
| |
| elif target == 'sex': |
| sex_array = [] |
| for subject in subject_id: |
| c_sex = subject_information_HCP[subject_information_HCP['Subject'] == subject]['Gender'].values |
| |
| if len(c_sex) == 0: |
| assert False, f"Subject {subject} not found in subject information file" |
| if len(c_sex) > 1: |
| print(f"Warning: Multiple entries for subject {subject}") |
| sex_array.append(int(c_sex[0] == 'M')) |
| return sex_array |
|
|
| def get_label_restricted(subject_id: List[str], target: str, normalized: bool = True) -> List: |
| """ |
| Get the label for the given subject id and target. |
| |
| For sex 0 is F and 1 is M |
| """ |
|
|
| |
| subject_id = [int(x) for x in subject_id] |
|
|
| if target == "age": |
| age_array = [] |
| for subject in subject_id: |
| c_age = subject_information_HCP[subject_information_HCP['Subject'] == subject]['Age_in_Yrs' if not normalized else 'Age_in_Yrs_z'].values |
| |
| if len(c_age) == 0: |
| assert False, f"Subject {subject} not found in subject information file" |
| if len(c_age) > 1: |
| print(f"Warning: Multiple entries for subject {subject}") |
|
|
| age_array.append(np.int8(c_age[0])) |
|
|
| return np.array(age_array) |
| |
| elif target == 'sex': |
| sex_array = [] |
| for subject in subject_id: |
| c_sex = subject_information_HCP[subject_information_HCP['Subject'] == subject]['Gender'].values |
| |
| if len(c_sex) == 0: |
| assert False, f"Subject {subject} not found in subject information file" |
| if len(c_sex) > 1: |
| print(f"Warning: Multiple entries for subject {subject}") |
| sex_array.append(int(c_sex[0] == 'M')) |
| return sex_array |
|
|
|
|
| |
|
|
| |
|
|
|
|
| from mae_utils.flat import load_hcp_flat_mask |
| from mae_utils.flat import create_hcp_flat |
| from mae_utils.flat import batch_unmask |
| import mae_utils.visualize as vis |
|
|
| flat_mask = load_hcp_flat_mask(hcp_flat_path) |
|
|
| mae_model = flat_models.mae_vit_large_fmri( |
| patch_size=patch_size, |
| decoder_embed_dim=decoder_embed_dim, |
| t_patch_size=t_patch_size, |
| pred_t_dim=pred_t_dim, |
| decoder_depth=4, |
| cls_embed=cls_embed, |
| norm_pix_loss=norm_pix_loss, |
| no_qkv_bias=no_qkv_bias, |
| sep_pos_embed=sep_pos_embed, |
| trunc_init=trunc_init, |
| pct_masks_to_decode=pct_masks_to_decode, |
| img_mask=flat_mask, |
| ) |
|
|
|
|
| |
|
|
|
|
| checkpoint_files = [f for f in os.listdir(outdir) if f.endswith('.pth')] |
|
|
| if utils.is_interactive(): |
| latest_checkpoint = "epoch99.pth" |
| else: |
| latest_checkpoint = epoch_checkpoint |
| |
| print(f"latest_checkpoint: {latest_checkpoint}") |
|
|
| |
| checkpoint_path = os.path.join(outdir, latest_checkpoint) |
|
|
| state = torch.load(checkpoint_path) |
| mae_model.load_state_dict(state["model_state_dict"], strict=False) |
| mae_model.to(device) |
|
|
| print(f"\nLoaded checkpoint {latest_checkpoint} from {outdir}\n") |
|
|
|
|
| |
|
|
|
|
| class LinearClassifier(nn.Module): |
| def __init__(self, input_dim, num_classes): |
| super(LinearClassifier, self).__init__() |
| self.linear = nn.Linear(input_dim, num_classes) |
| |
| def forward(self, x): |
| |
| x = x.view(x.size(0), -1) |
| out = self.linear(x) |
| return out |
|
|
| |
| |
| input_dim = np.prod(mae_model(torch.randn(1,1,16,144,320).to(device),global_pool=global_pool, forward_features = True).shape[1:]) |
| print(f"Input dimension: {input_dim}") |
|
|
|
|
| |
|
|
|
|
| class FullModel(nn.Module): |
| def __init__(self, lc_model, mae_model): |
| super(FullModel, self).__init__() |
| self.lc_model = lc_model |
| self.mae_model = mae_model |
| |
| |
| def forward(self, x, gsr): |
| x = self.mae_model(x, global_pool=global_pool, forward_features = True) |
| x = self.lc_model(x) |
| return x |
|
|
|
|
| |
|
|
|
|
| |
|
|
| if target == "trial_type": |
| lc_model = LinearClassifier(input_dim=input_dim, num_classes=num_classes) |
| criterion = nn.CrossEntropyLoss() |
|
|
| elif target == "age": |
| lc_model = LinearClassifier(input_dim=input_dim, num_classes=1) |
| criterion = nn.MSELoss() |
|
|
| elif target == "sex": |
| lc_model = LinearClassifier(input_dim=input_dim, num_classes=1) |
| criterion = nn.BCEWithLogitsLoss() |
|
|
|
|
| |
|
|
| model = FullModel(lc_model, mae_model) |
|
|
| |
| model.to(device) |
|
|
| |
| |
| |
|
|
| optimizer = torch.optim.AdamW(model.parameters(), lr=max_lr, weight_decay=weight_decay) |
|
|
| num_iterations_per_epoch = math.ceil(flatmaps_train.shape[0]/batch_size) |
|
|
| if lr_scheduler_type == 'linear': |
| lr_scheduler = torch.optim.lr_scheduler.LinearLR( |
| optimizer, |
| total_iters=int(np.floor(num_epochs*num_iterations_per_epoch)), |
| last_epoch=-1 |
| ) |
| elif lr_scheduler_type == 'cycle': |
| total_steps=int(np.floor(num_epochs*num_iterations_per_epoch)) |
| print("total_steps", total_steps) |
| lr_scheduler = torch.optim.lr_scheduler.OneCycleLR( |
| optimizer, |
| max_lr=max_lr, |
| total_steps=total_steps, |
| final_div_factor=1000, |
| last_epoch=-1, pct_start=2/num_epochs |
| ) |
|
|
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
| |
|
|
|
|
| import uuid |
|
|
| myuuid = uuid.uuid4() |
| str(myuuid) |
|
|
|
|
| |
|
|
|
|
| import wandb |
|
|
| if utils.is_interactive(): |
| print("Running in interactive notebook. Disabling W&B and ckpt saving.") |
| wandb_log = False |
| save_ckpt = False |
|
|
| if wandb_log: |
| wandb_project = 'fMRI-foundation-model' |
| wandb_config = { |
| "model_name": f'{found_model_name}_HCP_FT_{target}', |
| "batch_size": batch_size, |
| "weight_decay": weight_decay, |
| "num_epochs": num_epochs, |
| "seed": seed, |
| "lr_scheduler_type": lr_scheduler_type, |
| "save_ckpt": save_ckpt, |
| "seed": seed, |
| "max_lr": max_lr, |
| "target": target, |
| "num_workers": num_workers, |
| "weight_decay": weight_decay |
| } |
| print("wandb_config:\n", wandb_config) |
| random_id = random.randint(0, 100000) |
| wandb_id = f"{found_model_name}_{model_suffix}_{target}_HCPFT_{myuuid}" |
| print("wandb_id:", wandb_id) |
| wandb.init( |
| id=wandb_id, |
| project=wandb_project, |
| name=f"{found_model_name}_{model_suffix}_{target}_HCPFT", |
| config=wandb_config, |
| resume="allow", |
| ) |
|
|
|
|
| |
|
|
|
|
| for epoch in range(num_epochs): |
| running_train_loss = 0.0 |
| correct_train = 0 |
| mse_age_train = 0.0 |
| total_train = 0 |
| step = 0 |
|
|
| |
| |
| model.train() |
| for batch in tqdm(train_dl, desc=f"Epoch {epoch+1}/{num_epochs} - Training"): |
| optimizer.zero_grad() |
| images = batch[0].to(device).float() |
| |
| |
| if target == "trial_type": |
| labels = batch[1]['trial_type'] |
| labels = label_encoder.transform(labels) |
| labels = torch.tensor(labels, dtype=torch.long).to(device) |
| elif target == "age": |
| labels = get_label_restricted(batch[1]['sub'], 'age') |
| labels = torch.tensor(labels, dtype=torch.float).to(device) |
| elif target == "sex": |
| labels = get_label_restricted(batch[1]['sub'], 'sex') |
| labels = torch.tensor(labels, dtype=torch.float).to(device) |
| |
| |
| |
| outputs = model(images, gsr=gsr) |
| |
| |
| if target in ["trial_type", "sex"]: |
| |
| loss = criterion(outputs.squeeze(), labels.squeeze()) |
| elif target == "age": |
| |
| loss = criterion(outputs.squeeze(), labels.squeeze()) |
| |
| |
| loss.backward() |
| optimizer.step() |
| |
| |
| running_train_loss += loss.item() * images.size(0) |
|
|
| |
| |
| if target == "trial_type": |
| _, predicted = torch.max(outputs, 1) |
| correct_train += (predicted == labels).sum().item() |
| elif target == "age": |
| mse_age_train += (torch.sum((outputs.squeeze() - labels) ** 2).item()) / outputs.shape[0] |
| elif target == "sex": |
| threshold = 0.5 |
| predicted = (torch.sigmoid(outputs) > threshold).float() |
| correct_train += (predicted == labels).sum().item() |
|
|
| total_train += labels.size(0) |
| step += 1 |
|
|
| |
| if step % 100 == 0: |
| if target in ["trial_type", "sex"]: |
| current_accuracy = 100 * correct_train / total_train if total_train > 0 else 0.0 |
| print(f"Step [{step}/{len(train_dl)}] - Training Loss: {loss.item():.4f} - Training Accuracy: {current_accuracy:.2f}%") |
| elif target == "age": |
| current_mse = mse_age_train / total_train if total_train > 0 else 0.0 |
| print(f"Step [{step}/{len(train_dl)}] - Training Loss: {loss.item():.4f} - Training MSE: {current_mse:.4f}") |
|
|
| if lr_scheduler_type is not None: |
| lr_scheduler.step() |
|
|
| |
| epoch_train_loss = running_train_loss / total_train if total_train > 0 else 0.0 |
|
|
| if target in ["trial_type", "sex"]: |
| train_accuracy = 100 * correct_train / total_train if total_train > 0 else 0.0 |
| elif target == "age": |
| train_mse = mse_age_train / total_train if total_train > 0 else 0.0 |
| |
| |
| model.eval() |
| running_val_loss = 0.0 |
| correct_val = 0 |
| mse_age_val = 0.0 |
| total_val = 0 |
| |
| with torch.no_grad(): |
| for batch in tqdm(test_dl, desc=f"Epoch {epoch+1}/{num_epochs} - Validation"): |
| |
| images = batch[0].to(device).float() |
| labels = batch[1]['trial_type'] |
| |
| |
| if target == "trial_type": |
| labels = batch[1]['trial_type'] |
| labels = label_encoder.transform(labels) |
| labels = torch.tensor(labels, dtype=torch.long).to(device) |
| elif target == "age": |
| labels = get_label_restricted(batch[1]['sub'], 'age') |
| labels = torch.tensor(labels, dtype=torch.float).to(device) |
| elif target == "sex": |
| labels = get_label_restricted(batch[1]['sub'], 'sex') |
| labels = torch.tensor(labels, dtype=torch.float).to(device) |
|
|
| |
| |
| outputs = model(images, gsr=gsr) |
| |
| |
| if target in ["trial_type", "sex"]: |
| loss = criterion(outputs.squeeze(), labels.squeeze()) |
| elif target == "age": |
| loss = criterion(outputs.squeeze(), labels.squeeze()) |
|
|
| |
| running_val_loss += loss.item() * images.size(0) |
|
|
| |
| if target == "trial_type": |
| _, predicted = torch.max(outputs, 1) |
| correct_val += (predicted == labels).sum().item() |
| elif target == "age": |
| mse_age_val += (torch.sum((outputs.squeeze() - labels) ** 2).item()) / outputs.shape[0] |
| elif target == "sex": |
| threshold = 0.5 |
| predicted = (torch.sigmoid(outputs) > threshold).float() |
| correct_val += (predicted == labels).sum().item() |
|
|
| total_val += labels.size(0) |
|
|
| |
| epoch_val_loss = running_val_loss / total_val if total_val > 0 else 0.0 |
|
|
| if target in ["trial_type", "sex"]: |
| val_accuracy = 100 * correct_val / total_val if total_val > 0 else 0.0 |
| elif target == "age": |
| val_mse = mse_age_val / total_val if total_val > 0 else 0.0 |
|
|
| |
| if target in ["trial_type", "sex"]: |
| print(f"Epoch [{epoch+1}/{num_epochs}] " |
| f"- Training Loss: {epoch_train_loss:.4f}, Training Accuracy: {train_accuracy:.2f}% " |
| f"- Validation Loss: {epoch_val_loss:.4f}, Validation Accuracy: {val_accuracy:.2f}%") |
| elif target == "age": |
| print(f"Epoch [{epoch+1}/{num_epochs}] " |
| f"- Training Loss: {epoch_train_loss:.4f}, Training MSE: {train_mse:.4f} " |
| f"- Validation Loss: {epoch_val_loss:.4f}, Validation MSE: {val_mse:.4f}") |
|
|
| |
| if wandb_log: |
| log_dict = { |
| "epoch_train_loss": epoch_train_loss, |
| "epoch_val_loss": epoch_val_loss, |
| } |
| if target in ["trial_type", "sex"]: |
| log_dict.update({ |
| f"train_accuracy_{target}": train_accuracy, |
| f"val_accuracy_{target}": val_accuracy, |
| }) |
| elif target == "age": |
| log_dict.update({ |
| f"train_mse_{target}": train_mse, |
| f"val_mse_{target}": val_mse, |
| }) |
| wandb.log(log_dict) |
| |
| if save_ckpt: |
| outdir = os.path.abspath(f'checkpoints/{f"{found_model_name}_{model_suffix}_{target}_HCPFT"}') |
| os.makedirs(outdir, exist_ok=True) |
| print("outdir", outdir) |
| |
| torch.save(model.state_dict(), f"{outdir}/model.pth") |
| with open(f"{outdir}/config.yaml", 'w') as f: |
| yaml.dump(wandb_config, f) |
| print(f"Saved model and config to {outdir}") |
| |
|
|
|
|