| |
| |
|
|
| |
|
|
|
|
| |
| |
| 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 matplotlib.pyplot as plt |
|
|
| import torch |
| import torch.nn as nn |
| from torchvision import transforms |
| import h5py |
| import utils |
| import pandas as pd |
| |
|
|
| from sklearn.linear_model import Ridge |
| import argparse |
|
|
| |
| torch.backends.cuda.matmul.allow_tf32 = True |
| |
| torch.backends.cudnn.benchmark = True |
|
|
|
|
|
|
| |
|
|
|
|
| all_features = ['features[0]', 'features[2]', 'features[5]', 'features[7]', 'features[10]', 'features[12]', 'features[14]', 'features[16]', 'features[19]', 'features[21]', 'features[23]', 'features[25]', 'features[28]', 'features[30]', 'features[32]', 'features[34]', 'classifier[0]', 'classifier[3]', 'classifier[6]'] |
|
|
| parser = argparse.ArgumentParser(description='Decoding features from a model') |
|
|
| parser.add_argument('--run_name', type=str, default='subj1_40_test', help='Name of the run') |
| parser.add_argument('--current_features', type=str, default='features[28]', help='Feature layer to decode') |
| parser.add_argument('--num_sessions', type=float, default=20, help='Number of sessions to use') |
| parser.add_argument('--subj', type=int, default=1, help='Subject number', choices=[1,2,5,7]) |
|
|
| if utils.is_interactive(): |
| current_features = 'features[28]' |
| num_sessions = 20 |
| subj = 2 |
| run_name = 'subj1_40_test' |
|
|
|
|
| else: |
| args = parser.parse_args() |
| for attribute_name in vars(args).keys(): |
| globals()[attribute_name] = getattr(args, attribute_name) |
|
|
| print(f"Configured run_name = {run_name}") |
| print(f"Configured current_features = {current_features}") |
| print(f"Configured num_sessions = {num_sessions}") |
| print(f"Configured subj = {subj}") |
|
|
|
|
| if utils.is_interactive(): |
| |
| |
| get_ipython().run_line_magic('load_ext', 'autoreload') |
| get_ipython().run_line_magic('autoreload', '2') |
|
|
|
|
| save_ckpt = False |
|
|
|
|
| print("PID of this process =",os.getpid()) |
| seed = 42 |
| utils.seed_everything(seed) |
| data_type = torch.float32 |
| device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
|
|
| |
| data_path = '/weka/proj-medarc/shared/mindeyev2_dataset/' |
|
|
|
|
|
|
| outdir = os.path.abspath(f'./decoded_features/{run_name}') |
| os.makedirs(outdir, exist_ok=True) |
|
|
|
|
| |
|
|
|
|
| |
|
|
| from bdpy.dl.torch.models import VGG19, layer_map, model_factory |
| from bdpy.recon.torch.modules import build_encoder, build_generator, TargetNormalizedMSE |
| from bdpy.dl.torch.domain import Domain, image_domain, ComposedDomain |
|
|
|
|
|
|
| feature_network = VGG19() |
|
|
| feature_network.load_state_dict(torch.load('/weka/proj-fmri/ckadirt/spurious_reconstruction/analysis/VGG_ILSVRC_19_layers/VGG_ILSVRC_19_layers.pt')) |
| encoder = feature_network.to(device) |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
| |
| |
|
|
| if current_features == 'all': |
| layer_names = all_features |
| else: |
| layer_names = [current_features] |
|
|
|
|
| encoder = build_encoder(feature_network, layer_names, |
| domain= ComposedDomain([image_domain.BdPyVGGDomain(device=device,dtype=data_type), |
| image_domain.FixedResolutionDomain((224, 224))]), |
| ) |
|
|
|
|
| |
|
|
|
|
| print("loading_betas") |
| betas = utils.create_snr_betas(subject=subj, data_type=torch.float16, data_path=data_path, threshold=-1.0) |
| print("betas_ loaded") |
|
|
| x_train, valid_nsd_ids_train, x_test, test_nsd_ids = utils.load_nsd(subject=subj, betas=betas, data_path=data_path) |
|
|
|
|
| |
|
|
|
|
| stim_descriptions = pd.read_csv( |
| os.path.join(data_path, "nsd_stim_info_merged.csv"), index_col=0 |
| ) |
| stim_descriptions.head() |
|
|
| rep_columns = [f"subject{subj}_rep{j}" for j in range(3)] |
|
|
| indexes_shared_1000 = torch.Tensor(stim_descriptions[ |
| (stim_descriptions[f'subject{subj}'] == 1) & (stim_descriptions['shared1000'] == 1) |
| ][rep_columns].values.flatten()) - 1 |
|
|
| nsd_ids = stim_descriptions[ |
| (stim_descriptions[f'subject{subj}'] == 1) |
| ][rep_columns + ['nsdId']].values |
|
|
| valid_nsd_ids_full = torch.zeros(len(betas), dtype=torch.long) |
|
|
| for i, nsd_id in enumerate(nsd_ids): |
| rep1, rep2, rep3, current_nsd_id = nsd_id |
| valid_nsd_ids_full[rep1-1] = current_nsd_id |
| valid_nsd_ids_full[rep2-1] = current_nsd_id |
| valid_nsd_ids_full[rep3-1] = current_nsd_id |
|
|
| |
| print("Number of zeros in valid_nsd_ids_full", torch.sum(valid_nsd_ids_full == 0)) |
|
|
|
|
| session_size = 750 |
| num_examples_train = math.ceil(num_sessions * session_size) |
|
|
| x_train_subset = betas[:num_examples_train] |
| valid_nsd_ids_train_subset = valid_nsd_ids_full[:num_examples_train] |
|
|
| |
| indexes_shared_1000_clap = indexes_shared_1000[indexes_shared_1000 < num_examples_train].to(torch.long) |
| mask = torch.ones(x_train_subset.size(0), dtype=torch.bool) |
| mask[indexes_shared_1000_clap] = False |
| |
| x_train_subset = x_train_subset[mask] |
| valid_nsd_ids_train_subset = valid_nsd_ids_train_subset[mask] |
|
|
|
|
| |
|
|
|
|
| x_train = x_train_subset |
| valid_nsd_ids_train = valid_nsd_ids_train_subset |
|
|
|
|
| |
|
|
|
|
| print('Num train examples', x_train.shape) |
|
|
|
|
| |
|
|
|
|
| f_images = h5py.File(f'{data_path}/coco_images_224_float16.hdf5', 'r') |
| images = f_images['images'] |
|
|
|
|
| images = torch.Tensor(images[:]) |
| print("Loaded all 73k possible NSD images to cpu!", images.shape) |
|
|
|
|
| |
|
|
|
|
| from torch.utils.data import Dataset, DataLoader |
|
|
| class RRDataset(Dataset): |
| def __init__(self, x, valid_nsd_ids): |
| self.x = x |
| self.valid_nsd_ids = valid_nsd_ids |
|
|
| def __len__(self): |
| return len(self.x) |
|
|
| def __getitem__(self, idx): |
| betas = self.x[idx] |
| nsd_id = self.valid_nsd_ids[idx] |
| c_image = images[nsd_id] |
| return betas, c_image, nsd_id |
| |
| batch_size = 128 |
|
|
| train_dataset = RRDataset(x_train, valid_nsd_ids_train) |
| train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=4) |
|
|
| test_dataset = RRDataset(x_test, test_nsd_ids) |
| test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=4) |
|
|
|
|
| |
|
|
|
|
| |
| splits_per_layer = { |
| 'features[0]': 32, |
| 'features[2]': 32, |
| 'features[5]': 16, |
| 'features[7]': 16, |
| 'features[10]': 8, |
| 'features[12]': 8, |
| 'features[14]': 8, |
| 'features[16]': 8, |
| 'features[19]': 4, |
| 'features[21]': 4, |
| 'features[23]': 4, |
| 'features[25]': 4, |
| 'features[28]': 2, |
| 'features[30]': 2, |
| 'features[32]': 2, |
| 'features[34]': 2, |
| 'classifier[0]': 1, |
| 'classifier[3]': 1, |
| 'classifier[6]': 1, |
| } |
|
|
| layer_sizes = { |
| 'features[0]': 64, |
| 'features[2]': 64, |
| 'features[5]': 128, |
| 'features[7]': 128, |
| 'features[10]': 256, |
| 'features[12]': 256, |
| 'features[14]': 256, |
| 'features[16]': 256, |
| 'features[19]': 512, |
| 'features[21]': 512, |
| 'features[23]': 512, |
| 'features[25]': 512, |
| 'features[28]': 512, |
| 'features[30]': 512, |
| 'features[32]': 512, |
| 'features[34]': 512, |
| 'classifier[0]': 4096, |
| 'classifier[3]': 4096, |
| 'classifier[6]': 1000, |
| } |
|
|
| features_shapes = { |
| 'features[0]': (64, 224, 224), |
| 'features[2]': (64, 224, 224), |
| 'features[5]': (128, 112, 112), |
| 'features[7]': (128, 112, 112), |
| 'features[10]': (256, 56, 56), |
| 'features[12]': (256, 56, 56), |
| 'features[14]': (256, 56, 56), |
| 'features[16]': (256, 56, 56), |
| 'features[19]': (512, 28, 28), |
| 'features[21]': (512, 28, 28), |
| 'features[23]': (512, 28, 28), |
| 'features[25]': (512, 28, 28), |
| 'features[28]': (512, 14, 14), |
| 'features[30]': (512, 14, 14), |
| 'features[32]': (512, 14, 14), |
| 'features[34]': (512, 14, 14), |
| 'classifier[0]': (4096,), |
| 'classifier[3]': (4096,), |
| 'classifier[6]': (1000,), |
| } |
|
|
| alpha_per_layer = { |
| 'features[0]': 30000, |
| 'features[2]': 30000, |
| 'features[5]': 30000, |
| 'features[7]': 30000, |
| 'features[10]': 30000, |
| 'features[12]': 30000, |
| 'features[14]': 30000, |
| 'features[16]': 25000, |
| 'features[19]': 25000, |
| 'features[21]': 25000, |
| 'features[23]': 25000, |
| 'features[25]': 25000, |
| 'features[28]': 25000, |
| 'features[30]': 25000, |
| 'features[32]': 25000, |
| 'features[34]': 25000, |
| 'classifier[0]': 20000, |
| 'classifier[3]': 20000, |
| 'classifier[6]': 20000, |
| } |
|
|
|
|
| |
|
|
|
|
| def get_numpy_subset_of_features(train_loader, test_loader, encoder, current_features, current_split): |
| |
| assert current_split <= splits_per_layer[current_features], "num_split is greater than splits_per_layer" |
| |
| size_of_features_for_split = math.ceil(layer_sizes[current_features] / splits_per_layer[current_features]) |
| start_feature_index = size_of_features_for_split * (current_split - 1) |
| end_feature_index = size_of_features_for_split * current_split |
| print(f"start_feature_index: {start_feature_index}, end_feature_index: {end_feature_index}") |
| with torch.no_grad(): |
| if current_features in ['classifier[0]', 'classifier[3]', 'classifier[6]']: |
| train_features = np.zeros(tuple([len(train_loader.dataset)] + [size_of_features_for_split])).astype(np.float32) |
| test_features = np.zeros(tuple([len(test_loader.dataset)] + [size_of_features_for_split])).astype(np.float32) |
| else: |
| train_features = np.zeros(tuple([len(train_loader.dataset)] + [size_of_features_for_split] + list(features_shapes[current_features][1:]))).astype(np.float32) |
| test_features = np.zeros(tuple([len(test_loader.dataset)] + [size_of_features_for_split] + list(features_shapes[current_features][1:]))).astype(np.float32) |
|
|
| for i, (betas, c_image, nsd_id) in enumerate(tqdm(train_loader)): |
| c_image = c_image.to(device) |
| features = encoder(c_image) |
| train_features[i * batch_size:features[current_features].shape[0] + i * batch_size] = features[current_features][:, start_feature_index:end_feature_index].cpu().numpy() |
|
|
| for i, (betas, c_image, nsd_id) in enumerate(tqdm(test_loader)): |
| c_image = c_image.to(device) |
| features = encoder(c_image) |
| test_features[i * batch_size:features[current_features].shape[0] + i * batch_size] = features[current_features][:, start_feature_index:end_feature_index].cpu().numpy() |
|
|
|
|
| return train_features, test_features |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| imagery_data_path = '/weka/proj-medarc/shared/umn-imagery' |
| |
| voxels_vision, all_images_vision = utils.load_nsd_mental_imagery(subject=subj, mode='vision', stimtype="all", average=False, nest=True, data_root=imagery_data_path) |
| voxels_imagery, all_images_imagery = utils.load_nsd_mental_imagery(subject=subj, mode='imagery', stimtype="all", average=False, nest=True, data_root=imagery_data_path) |
|
|
|
|
| |
|
|
|
|
| def compute_mean_keepdims(train_features, feature_axis=1): |
| axes_to_average = tuple(i for i in range(train_features.ndim) if i != feature_axis) |
| y_mean = np.mean(train_features, axis=axes_to_average) |
| return y_mean |
|
|
|
|
| |
|
|
|
|
| outdir_for_feature = os.path.join(outdir, current_features) |
| os.makedirs(outdir_for_feature, exist_ok=True) |
|
|
| |
| for calc_rn_split in tqdm(range(1,splits_per_layer[current_features]+1)): |
| print(f"Calculating split {calc_rn_split} of {splits_per_layer[current_features]}") |
| train_features, test_features = get_numpy_subset_of_features(train_loader, test_loader, encoder, current_features, calc_rn_split) |
| size_of_features_for_split = math.ceil(layer_sizes[current_features] / splits_per_layer[current_features]) |
| |
| print(f"Starting ridge regression for split {calc_rn_split} with alpha {alpha_per_layer[current_features]}") |
| ridge = Ridge(alpha=alpha_per_layer[current_features]) |
| ridge.fit(x_train.reshape(x_train.shape[0], -1), train_features.reshape(train_features.shape[0], -1)) |
| print(f"Finished, now scoring") |
| train_score = ridge.score(x_train.reshape(x_train.shape[0], -1), train_features.reshape(train_features.shape[0], -1)) |
| test_score = ridge.score(x_test.reshape(x_test.shape[0], -1), test_features.reshape(test_features.shape[0], -1)) |
| print(f"train_score: {train_score}, test_score: {test_score}") |
|
|
| if current_features in ['classifier[0]', 'classifier[3]', 'classifier[6]']: |
| target_feature_shape = (size_of_features_for_split,) |
| else: |
| target_feature_shape = (size_of_features_for_split,) + tuple(features_shapes[current_features][1:]) |
|
|
| y_mean = compute_mean_keepdims(train_features) |
| |
| np.save(f'{outdir_for_feature}/ridge_y_mean_{current_features}_{calc_rn_split}.npy', y_mean.astype(np.float16)) |
|
|
| |
| with open(f'{outdir_for_feature}/ridge_scores_{current_features}_{calc_rn_split}.json', 'w') as f: |
| json.dump({'train_score': train_score, 'test_score': test_score}, f) |
| |
| if save_ckpt: |
| np.save(f'{outdir_for_feature}/ridge_weights_{current_features}_{calc_rn_split}.npy', ridge.coef_.astype(np.float16)) |
| |
| if save_ckpt: |
| np.save(f'{outdir_for_feature}/ridge_intercept_{current_features}_{calc_rn_split}.npy', ridge.intercept_.astype(np.float16)) |
|
|
| |
| test_predictions = ridge.predict(x_test.reshape(x_test.shape[0], -1)) |
| np.save(f'{outdir_for_feature}/ridge_test_predictions_{current_features}_{calc_rn_split}.npy', test_predictions.reshape(tuple([test_predictions.shape[0]] + list(target_feature_shape))).astype(np.float16)) |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
|
|
| |
| vision_averaged_voxels = np.mean(np.array(voxels_vision), axis=1) |
| vision_averaged_preds = ridge.predict(vision_averaged_voxels) |
| np.save(f'{outdir_for_feature}/ridge_vision_averaged_preds_{current_features}_{calc_rn_split}.npy', vision_averaged_preds.reshape(tuple([vision_averaged_preds.shape[0]] + list(target_feature_shape))).astype(np.float16)) |
|
|
| |
| imagery_averaged_voxels = np.mean(np.array(voxels_imagery), axis=1) |
| imagery_averaged_preds = ridge.predict(imagery_averaged_voxels) |
| np.save(f'{outdir_for_feature}/ridge_imagery_averaged_preds_{current_features}_{calc_rn_split}.npy', imagery_averaged_preds.reshape(tuple([imagery_averaged_preds.shape[0]] + list(target_feature_shape))).astype(np.float16)) |
|
|
|
|
| |
|
|
|
|
| |
| |
|
|
|
|
| |
|
|
|
|
| |
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| |
|
|
|
|
| |
| |
|
|
|
|