OSCR

A deep representation learning model to predict response to vagus nerve stimulation.

Code ↔ Paper

3 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 3 matches
  1. [1] § Results › Latent representations support accurate prediction and spatial interpretation of VNS outcome ↔ evaluation/eval_svm.py, lines 333–386 · score 0.65 · dot product, Grad CAM, SHAP, activations, zeros, Gradients
  2. [2] § Results › Self-supervised representation learning captures anatomical patterns associated with VNS outcome ↔ demo/utils/loss_functions.py, lines 83–135 · score 0.58 · spectral loss, loss function, perceptual loss, VQ VAE, reconstructions, predict
  3. [3] § Results › Self-supervised representation learning captures anatomical patterns associated with VNS outcome ↔ utils/loss_functions.py, lines 83–135 · score 0.58 · spectral loss, loss function, perceptual loss, VQ VAE, reconstructions, predict

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 631 lines · 26 KB · no license · 1 match

  1. ##### This script will evaluate the perforamnce of the SVM and then grad cam and other stuff
  2. #### Hrishikesh Suresh
  3. #### Ibrahim Lab 2025
  4. # Import necessary libraries
  5. import sys
  6. import os
  7. if not os.path.isdir('/hpf/projects/'):
  8. sys.path.insert(0, '../')
  9. import torch
  10. import lightning.pytorch as pl
  11. from torch.utils.data import DataLoader
  12. from torchvision import transforms
  13. from sklearn.model_selection import train_test_split
  14. import pandas as pd
  15. import numpy as np
  16. import matplotlib.pyplot as plt
  17. import seaborn as sns
  18. import nibabel as nib
  19. from tqdm.auto import tqdm
  20. from datasets.t1_datamodule import ImagingDataModule
  21. from sklearn.model_selection import train_test_split
  22. from models.vqvae import BrainVQVAE
  23. from models.classifiers import TransformerEncoderClassifier
  24. import wandb
  25. from lightning.pytorch.callbacks import EarlyStopping, ModelCheckpoint
  26. from lightning.pytorch.loggers import WandbLogger, TensorBoardLogger
  27. import shutil
  28. from monai.networks.nets.patchgan_discriminator import PatchDiscriminator
  29. from utils.loss_functions import Recon_Loss, Recon_Loss_GradMod, gradnorm
  30. import yaml
  31. import argparse
  32. torch.set_float32_matmul_precision('high')
  33. import pickle
  34. import warnings
  35. import shap
  36. from sklearn.metrics import roc_curve, confusion_matrix, roc_auc_score
  37. from utils.misc_functions import save_model_space_image
  38. warnings.filterwarnings(
  39. "ignore",
  40. message=".*`torch.cuda.amp.autocast*",
  41. category=FutureWarning
  42. )
  43. if os.environ.get('DEBUGGING') == '1':
  44. DEBUGGING = True
  45. else:
  46. DEBUGGING = False
  47. #Plot it all nicely
  48. def plot_curve_and_matrix(preds, probas, labels, dataset_name, intermediates_dir):
  49. #Adjust samplew weight to account for the imbalance
  50. non_responder_count = np.sum(labels == 0)
  51. responder_count = np.sum(labels == 1)
  52. pos_weight = non_responder_count / responder_count
  53. sample_weight = np.ones_like(labels)
  54. sample_weight[labels == 1] = pos_weight
  55. fpr, tpr, thresholds = roc_curve(labels, probas, sample_weight=sample_weight)
  56. fig, ax = plt.subplots(1, 2, figsize=(12, 6))
  57. sns.heatmap(confusion_matrix(labels, preds), annot=True, fmt='d', ax=ax[0], cmap='Blues')
  58. ax[0].set_title(f'{dataset_name} Confusion Matrix')
  59. ax[0].set_xlabel('Predicted')
  60. ax[0].set_ylabel('True')
  61. auc = roc_auc_score(labels, probas, sample_weight=sample_weight)
  62. ax[1].plot(fpr, tpr, label=f'AUC: {auc:.4f}')
  63. ax[1].plot([0, 1], [0, 1], linestyle='--', label='Random Classifier')
  64. ax[1].set_title(f'{dataset_name} ROC Curve')
  65. ax[1].set_xlabel('False Positive Rate')
  66. ax[1].set_ylabel('True Positive Rate')
  67. #add legend for random classifier and the model
  68. ax[1].legend(loc='lower right')
  69. plt.savefig(os.path.join(intermediates_dir, f'{dataset_name}_roc_curve.png'))
  70. plt.show()
  71. #Print the optimal threshold
  72. optimal_idx = np.argmax(tpr - fpr)
  73. optimal_threshold = thresholds[optimal_idx]
  74. return auc, optimal_threshold
  75. def eval(config):
  76. images_dir = str(config['images_dir'])
  77. metadata_csv = str(config['metadata_csv'])
  78. intermediates_dir= str(config['intermediates_dir'])
  79. outcome_col = str(config['outcome_col'])
  80. if os.path.exists(intermediates_dir):
  81. shutil.rmtree(intermediates_dir)
  82. os.makedirs(intermediates_dir)
  83. # Load the metadata
  84. df = pd.read_csv(metadata_csv)
  85. if not outcome_col in df.columns:
  86. raise ValueError('The metadata file must contain an outcome column. Since this is a classification task')
  87. if len(np.unique(df[outcome_col])) != 2:
  88. if 'binarization_threshold' in config:
  89. df['raw_outcome'] = df[outcome_col].copy()
  90. df[outcome_col] = df[outcome_col].apply(lambda x: 1 if x > float(config['binarization_threshold']) else 0)
  91. else:
  92. raise ValueError('The outcome column must be binary. Please binarize the outcome columnor provide a binarization threshold in the config file')
  93. # Define universal params
  94. batch_size = int(config['batch_size'])
  95. num_workers = int(config['num_workers'])
  96. #Set up the data module
  97. use_clinical = bool(config['use_clinical'])
  98. use_train_transform = bool(config['use_train_transform'])
  99. preload = bool(config['preload'])
  100. image_dim = tuple(map(int, config['image_dim']))
  101. #Check if the debugger is on, if so make num_workers = 1
  102. if DEBUGGING:
  103. num_workers = 1
  104. #Load the checkpoint
  105. vqvae = BrainVQVAE.load_from_checkpoint(config['vqvae_checkpoint_path'])
  106. vqvae.intermediates_dir = intermediates_dir
  107. #Load the SVM classifier
  108. classifier = pickle.load(open(config['svm_path'], 'rb'))
  109. features_to_keep = np.load(config['svm_feature_indices'])
  110. data_module = ImagingDataModule(images_dir = images_dir,
  111. metadata_df = df,
  112. train_ids = [],
  113. val_ids = [],
  114. test_ids = df['study_id'].values,
  115. batch_size = batch_size,
  116. num_workers = num_workers,
  117. use_clinical = use_clinical,
  118. use_train_transform = use_train_transform,
  119. preload = preload,
  120. crop_or_pad_dim=image_dim,
  121. outcome_col=outcome_col)
  122. data_module.setup()
  123. test_loader = data_module.test_dataloader()
  124. vqvae.eval()
  125. predictions = []
  126. probabilities = []
  127. labels = []
  128. with torch.no_grad():
  129. for batch in tqdm(test_loader, desc='Generating predictions', total=len(test_loader)):
  130. x, label = batch
  131. x = x.to(vqvae.device)
  132. label = label.to(vqvae.device)
  133. latents = vqvae.encode(x)
  134. quantized_latents = vqvae.quantize(latents)[0]
  135. mean_latent = torch.mean(quantized_latents, dim=[2,3,4])
  136. detached_latent = mean_latent.detach().cpu().numpy()[:, features_to_keep].reshape(1, -1)
  137. outcome_pred = classifier.predict(detached_latent)
  138. outcome_prob = classifier.predict_proba(detached_latent)[:,1]
  139. predictions.append(outcome_pred)
  140. probabilities.append(outcome_prob)
  141. labels.append(label.cpu().detach().numpy())
  142. #Save the predictions and labels
  143. predictions = np.array(predictions)
  144. probabilities = np.array(probabilities)
  145. labels = np.array(labels)
  146. np.save(os.path.join(intermediates_dir, 'predictions.npy'), predictions)
  147. np.save(os.path.join(intermediates_dir, 'probabilities.npy'), probabilities)
  148. np.save(os.path.join(intermediates_dir, 'labels.npy'), labels)
  149. #Plot the confusion matrix and ROC curve
  150. auc, optimal_threshold = plot_curve_and_matrix(predictions, probabilities, labels, 'test', intermediates_dir)
  151. print(f'Optimal threshold: {optimal_threshold}')
  152. print(f'AUC: {auc}')
  153. def run_gradcam_analysis(config):
  154. images_dir = str(config['images_dir'])
  155. intermediates_dir= str(config['intermediates_dir'])
  156. if not os.path.exists(intermediates_dir):
  157. os.makedirs(intermediates_dir)
  158. train_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'train_df.csv'))
  159. val_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'val_df.csv'))
  160. test_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'test_df.csv'))
  161. train_df['split'] = 'train'
  162. val_df['split'] = 'val'
  163. test_df['split'] = 'test'
  164. df = pd.concat([train_df, val_df, test_df], axis=0)
  165. if not 'outcome' in df.columns:
  166. raise ValueError('The metadata file must contain an outcome column. Since this is a classification task')
  167. # Define universal params
  168. batch_size = int(config['batch_size'])
  169. num_workers = int(config['num_workers'])
  170. #Set up the data module
  171. use_clinical = bool(config['use_clinical'])
  172. use_train_transform = bool(config['use_train_transform'])
  173. preload = bool(config['preload'])
  174. image_dim = tuple(map(int, config['image_dim']))
  175. outcome_col = str(config['outcome_col'])
  176. #Check if the debugger is on, if so make num_workers = 1
  177. if DEBUGGING:
  178. num_workers = 1
  179. data_module = ImagingDataModule(images_dir = images_dir,
  180. metadata_df = df,
  181. train_ids = [],
  182. val_ids = df[df['split'] == 'train']['study_id'].values,
  183. test_ids = df['study_id'].values,
  184. batch_size = 1,
  185. num_workers = num_workers,
  186. use_clinical = use_clinical,
  187. use_train_transform = use_train_transform,
  188. preload = preload,
  189. crop_or_pad_dim=image_dim,
  190. outcome_col=outcome_col)
  191. #Load the checkpoint
  192. vqvae = BrainVQVAE.load_from_checkpoint(config['vqvae_checkpoint_path'])
  193. vqvae.intermediates_dir = intermediates_dir
  194. #Load the SVM classifier
  195. classifer = pickle.load(open(config['svm_path'], 'rb'))
  196. features_to_keep = np.load(config['svm_feature_indices'])
  197. #Target layer for gradcam
  198. target_layer = vqvae.model.encoder.blocks[16].conv
  199. #Get the dataloaders
  200. data_module.setup()
  201. test_loader = data_module.test_dataloader()
  202. train_loader = data_module.val_dataloader()
  203. vqvae.eval()
  204. train_predictions = []
  205. full_quantized_latents = []
  206. grad_cam_dir = os.path.join(intermediates_dir, 'gradcam_v2')
  207. if not os.path.exists(grad_cam_dir):
  208. os.makedirs(grad_cam_dir)
  209. with torch.no_grad():
  210. #First run all the training data (in the validation data loader) to get the median of each feature
  211. for batch in tqdm(train_loader, desc='Generating predictions for training data', total=len(train_loader)):
  212. x, label = batch
  213. x = x.to(vqvae.device)
  214. label = label.to(vqvae.device)
  215. latents = vqvae.encode(x)
  216. quantized_latents = vqvae.quantize(latents)[0]
  217. mean_latent = torch.mean(quantized_latents, dim=[2,3,4])
  218. mean_latent = mean_latent.view(1, 32, -1)
  219. detached_latent = mean_latent.detach().cpu().numpy().reshape(-1)[features_to_keep]
  220. train_predictions.append(detached_latent)
  221. full_quantized_latents.append(quantized_latents.detach().cpu().numpy())
  222. #Make it a numpy array
  223. train_predictions = np.array(train_predictions)
  224. full_quantized_latents = np.array(full_quantized_latents).squeeze()
  225. #Get the median of each feature
  226. median_latent = np.median(train_predictions, axis=0).reshape(1, -1)
  227. #Make the explainer
  228. def get_pred(x):
  229. return classifer.predict_proba(x)[:,1]
  230. explainer = shap.Explainer(get_pred, median_latent)
  231. activations = []
  232. gradients = []
  233. def forward_hook(module, input, output):
  234. activations.append(output)
  235. def backward_hook(module, grad_input, grad_output):
  236. gradients.append(grad_output[0])
  237. target_layer.register_forward_hook(forward_hook)
  238. target_layer.register_full_backward_hook(backward_hook)
  239. latent_heatmaps = []
  240. heatmaps = []
  241. images = []
  242. labels = []
  243. preds = []
  244. for batch in tqdm(test_loader, desc='Generating gradient maps', total=len(test_loader)):
  245. activations.clear()
  246. gradients.clear()
  247. x, label = batch
  248. x = x.to(vqvae.device)
  249. label = label.to(vqvae.device)
  250. latents = vqvae.encode(x)
  251. quantized_latents = vqvae.quantize(latents)[0]
  252. mean_latent = torch.mean(quantized_latents, dim=[2,3,4])
  253. mean_latent = torch.abs(mean_latent) # Take the absolute value of the mean latent
  254. mean_latent = mean_latent.view(1, 32, -1)
  255. detached_latent = mean_latent.detach().cpu().numpy()[:, features_to_keep, :].reshape(1, -1)
  256. output = classifer.predict_proba(detached_latent)[:,1]
  257. shap_values = explainer(detached_latent)
  258. shap_values = np.array(shap_values.values).reshape(1, -1)
  259. # Clone the mean latent
  260. shap_weight_latent = mean_latent.clone()
  261. shap_weight_latent[:, :, :] = 0 # Zero out all values
  262. shap_weight_latent[:, features_to_keep, :] = torch.tensor(shap_values.reshape(1, -1, 1), device=shap_weight_latent.device, dtype=shap_weight_latent.dtype) # Set SHAP values
  263. dot_product = torch.dot(mean_latent.view(-1), shap_weight_latent.view(-1))
  264. vqvae.zero_grad()
  265. dot_product.backward()
  266. import numpy as np
  267. weights = torch.mean(gradients[0], dim=[2,3,4]).view(1,32,1,1,1)
  268. heatmap = torch.sum(weights * activations[0], dim=1).squeeze()
  269. heatmap = heatmap.cpu().detach().numpy()
  270. heatmap /= np.max(np.abs(heatmap))
  271. upsampled_heamap = torch.nn.Upsample(size=(x.shape[2], x.shape[3], x.shape[4]), mode='trilinear')(torch.tensor(heatmap).unsqueeze(0).unsqueeze(0)).squeeze()
  272. squeezed_img = x.squeeze().cpu().detach().numpy()
  273. latent_heatmaps.append(heatmap)
  274. heatmaps.append(upsampled_heamap)
  275. images.append(squeezed_img)
  276. preds.append(output)
  277. labels.append(label.cpu().detach().numpy())
  278. #Save the heatmaps and images
  279. latent_heatmaps = np.array(latent_heatmaps)
  280. heatmaps = np.array(heatmaps)
  281. images = np.array(images)
  282. preds = np.array(preds)
  283. labels = np.array(labels)
  284. latent_heatmaps_dir = os.path.join(grad_cam_dir, 'latent_heatmaps')
  285. heatmaps_dir = os.path.join(grad_cam_dir, 'heatmaps')
  286. images_dir = os.path.join(grad_cam_dir, 'images')
  287. if not os.path.exists(latent_heatmaps_dir):
  288. os.makedirs(latent_heatmaps_dir)
  289. if not os.path.exists(heatmaps_dir):
  290. os.makedirs(heatmaps_dir)
  291. if not os.path.exists(images_dir):
  292. os.makedirs(images_dir)
  293. for idx in tqdm(range(len(heatmaps)), desc='Saving Heatmaps and Images'):
  294. save_model_space_image(heatmaps[idx], os.path.join(heatmaps_dir, f'heatmap_{idx}.nii.gz'))
  295. save_model_space_image(images[idx], os.path.join(images_dir, f'image_{idx}.nii.gz'))
  296. latent_heatmap = latent_heatmaps[idx].squeeze()
  297. latent_heatmap_img = nib.Nifti1Image(latent_heatmap, np.eye(4))
  298. nib.save(latent_heatmap_img, os.path.join(latent_heatmaps_dir, f'latent_heatmap_{idx}.nii.gz'))
  299. #Save the predictions and labels
  300. np.save(os.path.join(grad_cam_dir, 'preds.npy'), preds)
  301. np.save(os.path.join(grad_cam_dir, 'labels.npy'), labels)
  302. registered_images_dir = os.path.join(grad_cam_dir, 'registered_images')
  303. registered_heatmaps_dir = os.path.join(grad_cam_dir, 'registered_heatmaps')
  304. registration_transform_dir = os.path.join(grad_cam_dir, 'registration_transforms')
  305. if not os.path.exists(registration_transform_dir):
  306. os.makedirs(registration_transform_dir)
  307. if not os.path.exists(registered_images_dir):
  308. os.makedirs(registered_images_dir)
  309. if not os.path.exists(registered_heatmaps_dir):
  310. os.makedirs(registered_heatmaps_dir)
  311. #Register the images and heatmaps
  312. import ants
  313. mni_1mm_brain = '/usr/local/fsl/data/standard/MNI152_T1_1mm_brain.nii.gz'
  314. mni_1mm_brain = ants.image_read(mni_1mm_brain)
  315. for idx in tqdm(range(len(os.listdir(heatmaps_dir))), desc='Registering Images and Heatmaps'):
  316. image = ants.image_read(os.path.join(images_dir, f'image_{idx}.nii.gz'))
  317. heatmap = ants.image_read(os.path.join(heatmaps_dir, f'heatmap_{idx}.nii.gz'))
  318. registered_image = ants.registration(fixed=mni_1mm_brain, moving=image, type_of_transform='SyN')
  319. registered_heatmap = ants.apply_transforms(fixed=mni_1mm_brain, moving=heatmap, transformlist=registered_image['fwdtransforms'])
  320. ants.image_write(registered_image['warpedmovout'], os.path.join(registered_images_dir, f'registered_image_{idx}.nii.gz'))
  321. ants.image_write(registered_heatmap, os.path.join(registered_heatmaps_dir, f'registered_heatmap_{idx}.nii.gz'))
  322. for transform in registered_image['fwdtransforms']:
  323. if '.nii.gz' in transform:
  324. shutil.move(transform, os.path.join(registration_transform_dir, f'warp_{idx}.nii.gz'))
  325. elif '.mat' in transform:
  326. shutil.move(transform, os.path.join(registration_transform_dir, f'affine_{idx}.mat'))
  327. else:
  328. raise ValueError('Unknown transform type')
  329. for transform in registered_image['invtransforms']:
  330. if '.nii.gz' in transform:
  331. shutil.move(transform, os.path.join(registration_transform_dir, f'inv_warp_{idx}.nii.gz'))
  332. responders = np.where(labels == 1)[0]
  333. non_responders = np.where(labels == 0)[0]
  334. responder_images = np.zeros(mni_1mm_brain.shape)
  335. for idx in tqdm(responders, desc='Averaging Responder Images'):
  336. image = ants.image_read(os.path.join(registered_heatmaps_dir, f'registered_heatmap_{idx}.nii.gz'))
  337. responder_images += image.numpy()
  338. responder_images /= len(responders)
  339. non_responder_images = np.zeros(mni_1mm_brain.shape)
  340. for idx in tqdm(non_responders, desc='Averaging Non-Responder Images'):
  341. image = ants.image_read(os.path.join(registered_heatmaps_dir, f'registered_heatmap_{idx}.nii.gz'))
  342. non_responder_images += image.numpy()
  343. non_responder_images /= len(non_responders)
  344. responder_average = ants.from_numpy(responder_images, origin=mni_1mm_brain.origin, spacing=mni_1mm_brain.spacing, direction=mni_1mm_brain.direction)
  345. non_responder_average = ants.from_numpy(non_responder_images, origin=mni_1mm_brain.origin, spacing=mni_1mm_brain.spacing, direction=mni_1mm_brain.direction)
  346. ants.image_write(responder_average, os.path.join(grad_cam_dir, 'responder_average.nii.gz'))
  347. ants.image_write(non_responder_average, os.path.join(grad_cam_dir, 'non_responder_average.nii.gz'))
  348. all_subjects_average = np.zeros(mni_1mm_brain.shape)
  349. for idx in tqdm(range(len(os.listdir(registered_heatmaps_dir))), desc='Averaging All Subjects Images'):
  350. image = ants.image_read(os.path.join(registered_heatmaps_dir, f'registered_heatmap_{idx}.nii.gz'))
  351. all_subjects_average += image.numpy()
  352. all_subjects_average /= len(os.listdir(registered_heatmaps_dir))
  353. all_subjects_average = ants.from_numpy(all_subjects_average, origin=mni_1mm_brain.origin, spacing=mni_1mm_brain.spacing, direction=mni_1mm_brain.direction)
  354. ants.image_write(all_subjects_average, os.path.join(grad_cam_dir, 'all_subjects_average.nii.gz'))
  355. all_subjects_abs_average = np.abs(all_subjects_average.numpy())
  356. all_subjects_abs_average_img = ants.from_numpy(all_subjects_abs_average, origin=mni_1mm_brain.origin, spacing=mni_1mm_brain.spacing, direction=mni_1mm_brain.direction)
  357. ants.image_write(all_subjects_abs_average_img, os.path.join(grad_cam_dir, 'all_subjects_abs_average.nii.gz'))
  358. all_subjects_abs_average_masked = all_subjects_abs_average * (mni_1mm_brain.numpy() > 0).astype(np.float32)
  359. all_subjects_abs_average_masked_img = ants.from_numpy(all_subjects_abs_average_masked, origin=mni_1mm_brain.origin, spacing=mni_1mm_brain.spacing, direction=mni_1mm_brain.direction)
  360. ants.image_write(all_subjects_abs_average_masked_img, os.path.join(grad_cam_dir, 'all_subjects_abs_average_masked.nii.gz'))
  361. def median_decoding(config):
  362. '''
  363. This function decodes and saves the median responder and non-responder images for contrastive analysis.
  364. '''
  365. images_dir = str(config['images_dir'])
  366. intermediates_dir = str(config['intermediates_dir'])
  367. if not os.path.exists(intermediates_dir):
  368. os.makedirs(intermediates_dir)
  369. train_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'train_df.csv'))
  370. val_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'val_df.csv'))
  371. test_df = pd.read_csv(os.path.join(config['dataframes_folder'], 'test_df.csv'))
  372. train_df['split'] = 'train'
  373. val_df['split'] = 'val'
  374. test_df['split'] = 'test'
  375. df = pd.concat([train_df, val_df, test_df], axis=0)
  376. if not 'outcome' in df.columns:
  377. raise ValueError('The metadata file must contain an outcome column. Since this is a classification task')
  378. # Define universal params
  379. batch_size = int(config['batch_size'])
  380. num_workers = int(config['num_workers'])
  381. # Set up the data module
  382. use_clinical = bool(config['use_clinical'])
  383. use_train_transform = bool(config['use_train_transform'])
  384. preload = bool(config['preload'])
  385. image_dim = tuple(map(int, config['image_dim']))
  386. outcome_col = str(config['outcome_col'])
  387. # Check if the debugger is on, if so make num_workers = 1
  388. if DEBUGGING:
  389. num_workers = 1
  390. # Load the checkpoint
  391. vqvae = BrainVQVAE.load_from_checkpoint(config['vqvae_checkpoint_path'])
  392. vqvae.intermediates_dir = intermediates_dir
  393. # Load the SVM classifier
  394. classifier = pickle.load(open(config['svm_path'], 'rb'))
  395. features_to_keep = np.load(config['svm_feature_indices'])
  396. data_module = ImagingDataModule(
  397. images_dir=images_dir,
  398. metadata_df=df,
  399. train_ids=[],
  400. val_ids=df[df['split'] == 'train']['study_id'].values,
  401. test_ids=df['study_id'].values,
  402. batch_size=1,
  403. num_workers=num_workers,
  404. use_clinical=use_clinical,
  405. use_train_transform=use_train_transform,
  406. preload=preload,
  407. crop_or_pad_dim=image_dim,
  408. outcome_col=outcome_col
  409. )
  410. # Get the dataloaders
  411. data_module.setup()
  412. train_loader = data_module.val_dataloader() #
  413. train_mean_latent_predictions = []
  414. encoded_volumes = []
  415. train_labels = []
  416. grad_cam_dir = os.path.join(intermediates_dir, 'gradcam')
  417. if not os.path.exists(grad_cam_dir):
  418. os.makedirs(grad_cam_dir)
  419. with torch.no_grad():
  420. # Run all the training data (in the validation data loader) to get the median of each feature
  421. for batch in tqdm(train_loader, desc='Generating predictions for training data', total=len(train_loader)):
  422. x, label = batch
  423. x = x.to(vqvae.device)
  424. label = label.to(vqvae.device)
  425. latents = vqvae.encode(x)
  426. quantized_latents = vqvae.quantize(latents)[0]
  427. mean_latent = torch.mean(quantized_latents, dim=[2,3,4])
  428. mean_latent = mean_latent.view(1, 32, -1)
  429. detached_latent = mean_latent.detach().cpu().numpy().reshape(-1)[features_to_keep]
  430. train_mean_latent_predictions.append(detached_latent)
  431. encoded_volumes.append(latents.detach())
  432. train_labels.append(label.detach())
  433. # Make it a numpy array
  434. train_mean_latent_predictions = torch.tensor(train_mean_latent_predictions)
  435. train_labels = torch.tensor(train_labels)
  436. # Generate mean responder and non-responder latents
  437. encoded_volumes = torch.stack(encoded_volumes).squeeze()
  438. responder_indices = torch.where(train_labels == 1)[0]
  439. non_responder_indices = torch.where(train_labels == 0)[0]
  440. responder_encoded = encoded_volumes[responder_indices]
  441. non_responder_encoded = encoded_volumes[non_responder_indices]
  442. median_responder_encoded = torch.median(responder_encoded, dim=0).values.unsqueeze(0)
  443. median_non_responder_encoded = torch.median(non_responder_encoded, dim=0).values.unsqueeze(0)
  444. median_responder_quantized = vqvae.quantize(median_responder_encoded)[0]
  445. median_non_responder_quantized = vqvae.quantize(median_non_responder_encoded)[0]
  446. responder_decoded = vqvae.decode(median_responder_quantized)
  447. non_responder_decoded = vqvae.decode(median_non_responder_quantized)
  448. save_model_space_image(responder_decoded.squeeze().cpu().detach().numpy(), os.path.join(grad_cam_dir, 'median_responder_image.nii.gz'))
  449. save_model_space_image(non_responder_decoded.squeeze().cpu().detach().numpy(), os.path.join(grad_cam_dir, 'median_non_responder_image.nii.gz'))
  450. def main():
  451. parser = argparse.ArgumentParser(description='Evaluate SVM, run Grad-CAM analysis, or median decoding for VQ-VAE model')
  452. parser.add_argument('--config', type=str, required=True, help='Path to the config file')
  453. parser.add_argument('--svm_path', type=str, help='Path to the svm checkpoint', required=False)
  454. parser.add_argument('--svm_feature_indices', type=str, help='Path to the svm feature indices', required=False)
  455. parser.add_argument('--dataframes_folder', type=str, help='Path to the dataframes folder with train.df, val.df, test.df', required=False)
  456. parser.add_argument('--mode', type=str, choices=['eval', 'gradcam', 'median_decoding'], default='eval', help="Which mode to run: 'eval' for evaluation, 'gradcam' for Grad-CAM analysis, 'median_decoding' to save median responder/non-responder images")
  457. # Accept any additional arguments
  458. parser.add_argument('args', nargs=argparse.REMAINDER)
  459. args, unknown = parser.parse_known_args()
  460. config_file = args.config
  461. # Load the config file
  462. with open(config_file) as file:
  463. config = yaml.load(file, Loader=yaml.FullLoader)
  464. # Override config with command-line arguments if provided
  465. if args.svm_path:
  466. config['svm_path'] = args.svm_path
  467. if args.svm_feature_indices:
  468. config['svm_feature_indices'] = args.svm_feature_indices
  469. if args.dataframes_folder:
  470. config['dataframes_folder'] = args.dataframes_folder
  471. # Copy the config file to the intermediates directory
  472. intermediates_dir = str(config['intermediates_dir'])
  473. if not os.path.exists(intermediates_dir):
  474. os.makedirs(intermediates_dir)
  475. shutil.copy(config_file, os.path.join(intermediates_dir, 'config.yaml'))
  476. if args.mode == 'eval':
  477. eval(config)
  478. elif args.mode == 'gradcam':
  479. run_gradcam_analysis(config)
  480. elif args.mode == 'median_decoding':
  481. median_decoding(config)
  482. else:
  483. raise ValueError(f"Unknown mode: {args.mode}")
  484. if __name__ == '__main__':
  485. main()

eval_svm.py at commit ab62c28, no license · at the source

Overview

Authors: Hrishikesh Suresh1,2,3, Karim Mithani1,2,3, Vicki Li1,2, Timur H. Latypov2, Nebras M. Warsi1,2,3, Simeon M. Wong1,2, Lauren Erdman4, Jaeyoung Kang2, Jurgen Germann1,5, Flavia Venetucci Gouveia2, Sebastian C. Coleman2, Alexandre Berger2, Vann Chau6, Shelly Weiss6, Carolina Gorodetsky6, Elizabeth Donner6, Alexander G. Weil7, Jignesh Tailor8, Taylor J. Abel9, Madison Remick9
and 27 other authorsEmefa Akwayena9, Dewi Schrader10, Robert J. Bollo11, Matthew D. Smyth12, Diana Aum13, Sean M. Lew14, Shelly Wang15, Toba N. Niazi15, Aria Fallah16, Jeffrey S. Raskin17, Howard L. Weiner18, Nisha Gadgil18, Gregory W. Albert19, Aristides Hadjinicolaou20, Philippe Major20, Farbod Niazi21, Guillaume Theaud21, Sami Obaid22, Elysa Widjaja23, Birgit Ertl-Wagner24, Logi Vidarsson24, Margot J. Taylor24, Alexandre Boutet25, James T. Rutka3,26, Melissa A. LoPresti27, Puneet Jain6, George M. Ibrahim1,2,3,26,28
28 affiliations
  1. Institute of Biomedical Engineering, University of Toronto,Toronto, ON Canada
  2. Program in Neuroscience and Mental Health, The Hospital for Sick Children Research Institute,Toronto, ON Canada
  3. Division of Neurosurgery, Department of Surgery, University of Toronto,Toronto, ON Canada
  4. Department of Pediatrics, Cincinnati Children’s Hospital,Cincinnati, OH USA
  5. Krembil Brain Institute,Toronto, ON Canada
  6. Division of Neurology, The Hospital for Sick Children,Toronto, ON Canada
  7. Division of Neurosurgery, CHU Sainte-Justine and Centre hospitalier de l’Université de Montréal,Montréal, QC Canada
  8. Deparment of Neurosurgery, Riley Hospital for Children,Indianapolis, IN USA
  9. Department of Neurosurgery, UPMC Children’s Hospital of Pittsburgh,Pittsburgh, PA USA
  10. Division of Neurology, BC Children’s Hospital,Vancouver, BC Canada
  11. Department of Neurosurgery, University of Utah Health,Salt Lake City, UT USA
  12. Johns Hopkins University, Department of Neurosurgery, Johns Hopkins All Children’s Hospital,St. Petersburg, FL USA
  13. Department of Neurosurgery, St. Louis Children’s Hospital,St. Louis, MO USA
  14. Department of Neurosurgery, Medical College Wisconsin,Milwaukee, WI USA
  15. Division of Neurosurgery, Nicklaus Children’s Hospital,Miami, FL USA
  16. Department of Neurosurgery, UCLA Mattel Children’s Hospital,Los Angeles, CA USA
  17. Department of Neurosurgery, Children’s Hospital of Chicago,Chicago, IL USA
  18. Department of Neurosurgery, Texas Children’s Hospital,Houston, TX USA
  19. Department of Neurosurgery, Arkansas Children’s Hospital,Little Rock, AR USA
  20. Division of Neurology, CHU Sainte-Justine,Montréal, QC Canada
  21. Centre de recherche du CHUM,Montréal, QC Canada
  22. Department of Surgery, Université de Montréal,Montréal, QC Canada
  23. Department of Medical Imaging, Children’s Hospital of Chicago,Chicago, IL USA
  24. Department of Diagnostic & Interventional Radiology, The Hospital for Sick Children,Toronto, ON Canada
  25. Joint Department of Medical Imaging, University Health Network,Toronto, ON Canada
  26. Division of Neurosurgery, The Hospital for Sick Children,Toronto, ON Canada
  27. Department of Neurosurgery, University of Rochester Medical Center,Rochester, NY USA
  28. Institute of Medical Science, University of Toronto,Toronto, ON Canada
Journal: Nature communications, volume 17, issue 1, article 4932
Dates: received 14 June 2025; accepted 20 March 2026; published online 7 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41467-026-71555-0 · PMID 41946715 · PMCID PMC13234157 · OpenAlex W7151426170
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), epilepsy (population), clinical / translational (subfield)
Keywords: Network models, Epilepsy, Prognosis, Predictive markers, Magnetic resonance imaging
MeSH: Deep Learning*, Epilepsy*, Vagus Nerve Stimulation*, Adolescent, Brain, Child, Child, Preschool, Female, Humans, Magnetic Resonance Imaging, Male, Predictive Learning Models, Representation Machine Learning, Treatment Outcome (* major topic)
Topic: Vagus Nerve Stimulation Research (Neurology, Neuroscience), according to OpenAlex
Funding: Project Grant from the Canadian Institutes of Health Research (PJT159561). Investigator-initiated grant from LivaNova PLC (VNS Manufacturer in this study) for prospective data from 4 sites for children treated on-label
Citations: cited by 2 papers (Europe PMC); 102 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

Its files are read in the Code ↔ Paper reader above, with 3 matches between paragraphs and lines of code.

gmilab/VQVNS

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: ab62c28f297629eb8b0d3dd716101cd2182636ff, 25 November 2025
Languages: Python (23), Jupyter (1)
Size: 45 files, 24 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, environment (pyproject.toml, demo/environment.yml), 1 notebook
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (17 files), PyTorch (17 files), NiBabel (14 files), MONAI (11 files), PyTorch Lightning (10 files), pandas (9 files), Matplotlib (6 files), scikit-learn (5 files), seaborn (5 files), ANTs (4 files), FreeSurfer (3 files), FSL (3 files), SciPy (2 files), SHAP (1 file), XGBoost (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
25 files

huggingface.co/hsuresh/vqvns

License: apache
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 75438ce6e41ad6eecb5c2cbfa601aa20f199e050, 5 November 2025
Size: 5 files, 0 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
1 file

Zenodo 18510266

License: CC-BY-4.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (17 files), PyTorch (17 files), NiBabel (14 files), MONAI (11 files), PyTorch Lightning (10 files), pandas (9 files), Matplotlib (6 files), scikit-learn (5 files), seaborn (5 files), ANTs (4 files), FreeSurfer (3 files), FSL (3 files), SciPy (2 files), SHAP (1 file), XGBoost (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers (HTTP 200)
  • 29 September 2026: the link answers (HTTP 200)
25 files
At the source:

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-71555-0.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 48 scripts, each with its path and the digest of its content;
  • 3 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Data availability statement

The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • no repository, dataset or request procedure was recognized in it

Read it in the paper: doi.org/10.1038/s41467-026-71555-0.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 47 authors, 5 keywords, 14 MeSH terms, 1 funder, 89 references.

Cite

This paper

Suresh, H., Mithani, K., Li, V., Latypov, T. H., Warsi, N. M., Wong, S. M., Erdman, L., Kang, J., Germann, J., Gouveia, F. V., Coleman, S. C., Berger, A., Chau, V., Weiss, S., Gorodetsky, C., Donner, E., Weil, A. G., Tailor, J., Abel, T. J., . . . Ibrahim, G. M. (2026). A deep representation learning model to predict response to vagus nerve stimulation. Nature communications, 17(1), 4932. https://doi.org/10.1038/s41467-026-71555-0

BibTeX

@article{suresh2026deep,
author = {Suresh, Hrishikesh and Mithani, Karim and Li, Vicki and Latypov, Timur H. and Warsi, Nebras M. and Wong, Simeon M. and Erdman, Lauren and Kang, Jaeyoung and Germann, Jurgen and Gouveia, Flavia Venetucci and Coleman, Sebastian C. and Berger, Alexandre and Chau, Vann and Weiss, Shelly and Gorodetsky, Carolina and Donner, Elizabeth and Weil, Alexander G. and Tailor, Jignesh and Abel, Taylor J. and Remick, Madison and Akwayena, Emefa and Schrader, Dewi and Bollo, Robert J. and Smyth, Matthew D. and Aum, Diana and Lew, Sean M. and Wang, Shelly and Niazi, Toba N. and Fallah, Aria and Raskin, Jeffrey S. and Weiner, Howard L. and Gadgil, Nisha and Albert, Gregory W. and Hadjinicolaou, Aristides and Major, Philippe and Niazi, Farbod and Theaud, Guillaume and Obaid, Sami and Widjaja, Elysa and Ertl-Wagner, Birgit and Vidarsson, Logi and Taylor, Margot J. and Boutet, Alexandre and Rutka, James T. and LoPresti, Melissa A. and Jain, Puneet and Ibrahim, George M.},
title = {{A deep representation learning model to predict response to vagus nerve stimulation}},
journal = {Nature communications},
year = {2026},
month = apr,
volume = {17},
number = {1},
pages = {4932},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-71555-0},
url = {https://doi.org/10.1038/s41467-026-71555-0},
pmid = {41946715},
pmcid = {PMC13234157}
}

RIS

TY - JOUR
AU - Suresh, Hrishikesh
AU - Mithani, Karim
AU - Li, Vicki
AU - Latypov, Timur H.
AU - Warsi, Nebras M.
AU - Wong, Simeon M.
AU - Erdman, Lauren
AU - Kang, Jaeyoung
AU - Germann, Jurgen
AU - Gouveia, Flavia Venetucci
AU - Coleman, Sebastian C.
AU - Berger, Alexandre
AU - Chau, Vann
AU - Weiss, Shelly
AU - Gorodetsky, Carolina
AU - Donner, Elizabeth
AU - Weil, Alexander G.
AU - Tailor, Jignesh
AU - Abel, Taylor J.
AU - Remick, Madison
AU - Akwayena, Emefa
AU - Schrader, Dewi
AU - Bollo, Robert J.
AU - Smyth, Matthew D.
AU - Aum, Diana
AU - Lew, Sean M.
AU - Wang, Shelly
AU - Niazi, Toba N.
AU - Fallah, Aria
AU - Raskin, Jeffrey S.
AU - Weiner, Howard L.
AU - Gadgil, Nisha
AU - Albert, Gregory W.
AU - Hadjinicolaou, Aristides
AU - Major, Philippe
AU - Niazi, Farbod
AU - Theaud, Guillaume
AU - Obaid, Sami
AU - Widjaja, Elysa
AU - Ertl-Wagner, Birgit
AU - Vidarsson, Logi
AU - Taylor, Margot J.
AU - Boutet, Alexandre
AU - Rutka, James T.
AU - LoPresti, Melissa A.
AU - Jain, Puneet
AU - Ibrahim, George M.
TI - A deep representation learning model to predict response to vagus nerve stimulation
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/04/07
VL - 17
IS - 1
SP - 4932
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-71555-0
UR - https://doi.org/10.1038/s41467-026-71555-0
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-71555-0",
"type": "article-journal",
"title": "A deep representation learning model to predict response to vagus nerve stimulation",
"container-title": "Nature communications",
"author": [
{
"family": "Suresh",
"given": "Hrishikesh"
},
{
"family": "Mithani",
"given": "Karim"
},
{
"family": "Li",
"given": "Vicki"
},
{
"family": "Latypov",
"given": "Timur H."
},
{
"family": "Warsi",
"given": "Nebras M."
},
{
"family": "Wong",
"given": "Simeon M."
},
{
"family": "Erdman",
"given": "Lauren"
},
{
"family": "Kang",
"given": "Jaeyoung"
},
{
"family": "Germann",
"given": "Jurgen"
},
{
"family": "Gouveia",
"given": "Flavia Venetucci"
},
{
"family": "Coleman",
"given": "Sebastian C."
},
{
"family": "Berger",
"given": "Alexandre"
},
{
"family": "Chau",
"given": "Vann"
},
{
"family": "Weiss",
"given": "Shelly"
},
{
"family": "Gorodetsky",
"given": "Carolina"
},
{
"family": "Donner",
"given": "Elizabeth"
},
{
"family": "Weil",
"given": "Alexander G."
},
{
"family": "Tailor",
"given": "Jignesh"
},
{
"family": "Abel",
"given": "Taylor J."
},
{
"family": "Remick",
"given": "Madison"
},
{
"family": "Akwayena",
"given": "Emefa"
},
{
"family": "Schrader",
"given": "Dewi"
},
{
"family": "Bollo",
"given": "Robert J."
},
{
"family": "Smyth",
"given": "Matthew D."
},
{
"family": "Aum",
"given": "Diana"
},
{
"family": "Lew",
"given": "Sean M."
},
{
"family": "Wang",
"given": "Shelly"
},
{
"family": "Niazi",
"given": "Toba N."
},
{
"family": "Fallah",
"given": "Aria"
},
{
"family": "Raskin",
"given": "Jeffrey S."
},
{
"family": "Weiner",
"given": "Howard L."
},
{
"family": "Gadgil",
"given": "Nisha"
},
{
"family": "Albert",
"given": "Gregory W."
},
{
"family": "Hadjinicolaou",
"given": "Aristides"
},
{
"family": "Major",
"given": "Philippe"
},
{
"family": "Niazi",
"given": "Farbod"
},
{
"family": "Theaud",
"given": "Guillaume"
},
{
"family": "Obaid",
"given": "Sami"
},
{
"family": "Widjaja",
"given": "Elysa"
},
{
"family": "Ertl-Wagner",
"given": "Birgit"
},
{
"family": "Vidarsson",
"given": "Logi"
},
{
"family": "Taylor",
"given": "Margot J."
},
{
"family": "Boutet",
"given": "Alexandre"
},
{
"family": "Rutka",
"given": "James T."
},
{
"family": "LoPresti",
"given": "Melissa A."
},
{
"family": "Jain",
"given": "Puneet"
},
{
"family": "Ibrahim",
"given": "George M."
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "4932",
"DOI": "10.1038/s41467-026-71555-0",
"PMID": "41946715",
"PMCID": "PMC13234157",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-71555-0",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
7
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s41586-026-10631-3 [code]
A prognostic human brain network for diffuse midline glioma.
Journal: Nature
In common: ANTs, FreeSurfer, FSL, 7 other tools, DOI 10.7910/dvn/ilxiks, clinical / translational, 8 references
[2] doi:10.1126/sciadv.aeb5842 [code]
Regulation of autism-related self-injurious behavior by electrical stimulation of corticostriatal circuits in mice and humans.
Journal: Science advances
In common: ANTs, SciPy, NumPy, 2 references, 4 authors
[3] doi:10.1162/imag.a.1352 [code]
Brain-age in ultra-low-field MRI: How well does it work?
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MONAI, ANTs, FreeSurfer, 6 other tools, structural MRI / diffusion, 3 references
[4] doi:10.1371/journal.pbio.3003856 [code]
Aging and metabolism contribute separately to brain-body health.
Journal: PLoS biology
In common: ANTs, FreeSurfer, FSL, 8 other tools, structural MRI / diffusion, clinical / translational, 2 references
[5] doi:10.1162/imag.a.1164 [code]
Bias and generalizability of brain age prediction models: A multi-cohort evaluation with anatomical and interpretability insights.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MONAI, ANTs, FreeSurfer, 9 other tools, structural MRI / diffusion
[6] doi:10.1002/alz.71649 [code]
Postmortem brain MRI reveals differential associations of subcortical and limbic volumes with cortical thinning and neurodegenerative pathologies.
Journal: Alzheimer's & dementia : the journal of the Alzheimer's Association
In common: ANTs, FreeSurfer, FSL, 8 other tools, structural MRI / diffusion, 2 references
[7] doi:10.1126/sciadv.adu9309 [code]
Variations of global brain asymmetry are associated with aging and related diseases.
Journal: Science advances
In common: ANTs, FreeSurfer, FSL, 6 other tools, 4 references
[8] doi:10.1162/imag.a.1252 [code]
Does the brain's E:I balance really shape long-range temporal correlations? Lessons learned from 3T MRI.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: ANTs, FreeSurfer, FSL, 7 other tools, structural MRI / diffusion, 3 references
[9] doi:10.1038/s41467-026-73996-z [code]
Genetic architecture of white matter microstructure captured by unsupervised deep representation learning of fractional anisotropy maps.
Journal: Nature communications
In common: MONAI, PyTorch Lightning, NiBabel, 7 other tools, structural MRI / diffusion, 2 references
[10] doi:10.1038/s41467-026-71918-7 [code]
Developmental disinhibition gates language lateralization in childhood.
Journal: Nature communications
In common: ANTs, FreeSurfer, FSL, 8 other tools, 2 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.