def test_unsupported_alignment(): img1, mask_img = random_niimg((8, 7, 6, 10)) img2, _ = random_niimg((7, 6, 8, 5)) args = {'alignment_method': 'scaled_procrustes', 'mask': mask_img} algo = PairwiseAlignment(**args) with pytest.raises(NotImplementedError): algo.fit(img1, img2)
def _map_template_to_image(imgs, train_index, template, alignment_method, n_pieces, clustering, n_bags, masker, memory, memory_level, n_jobs, verbose): '''Learn alignment operator from the template toward new images. Parameters ---------- imgs: list of 3D Niimgs Target images to learn mapping from the template to a new subject train_index: list of int Matching index between imgs and the corresponding template images to use to learn alignment. len(train_index) must be equal to len(imgs) template: list of 3D Niimgs Learnt in a first step now used as source image All other arguments are the same are passed to PairwiseAlignment Returns ------- mapping: instance of PairwiseAlignment class Alignment estimator fitted to align the template with the input images ''' mapping_image = index_img(template, train_index) mapping = PairwiseAlignment(n_pieces=n_pieces, alignment_method=alignment_method, clustering=clustering, n_bags=n_bags, mask=masker, memory=memory, memory_level=memory_level, n_jobs=n_jobs, verbose=verbose) mapping.fit(mapping_image, imgs) return mapping
def test_pairwise_identity(): img1, mask_img = random_niimg((8, 7, 6, 10)) args_list = [{ 'alignment_method': 'identity', 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'n_bags': 4, 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'n_bags': 3, 'mask': mask_img, 'n_jobs': 2 }, { 'alignment_method': 'identity', 'n_pieces': 3, 'n_bags': 2, 'mask': mask_img, 'n_jobs': 2, 'parallel_backend': 'multiprocessing' }] for args in args_list: algo = PairwiseAlignment(**args) assert_algo_transform_almost_exactly(algo, img1, img1, mask=mask_img)
def _align_images_to_template(imgs, template, alignment_method, n_pieces, clustering, n_bags, masker, memory, memory_level, n_jobs, verbose): '''Convenience function : for a list of images, return the list of estimators (PairwiseAlignment instances) aligning each of them to a common target, the template. All arguments are used in PairwiseAlignment ''' aligned_imgs = [] for img in imgs: piecewise_estimator = \ PairwiseAlignment(n_pieces=n_pieces, alignment_method=alignment_method, clustering=clustering, n_bags=n_bags, mask=masker, memory=memory, memory_level=memory_level, n_jobs=n_jobs, verbose=verbose) piecewise_estimator.fit(img, template) aligned_imgs.append(piecewise_estimator.transform(img)) return aligned_imgs
def test_pairwise_identity(): img1, mask_img = random_niimg((8, 7, 6, 10)) args_list = [{ 'alignment_method': 'identity', 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'n_bags': 4, 'mask': mask_img }, { 'alignment_method': 'identity', 'n_pieces': 3, 'n_bags': 3, 'mask': mask_img, 'n_jobs': 2 }] for args in args_list: algo = PairwiseAlignment(**args) assert_algo_transform_almost_exactly(algo, img1, img1, mask=mask_img) # test intersection of clustering and mask data_mask = copy.deepcopy(mask_img.get_fdata()) data_mask[0] = 0 # create ground truth clustering_mask = new_img_like(mask_img, data_mask) data_clust = copy.deepcopy(data_mask) data_clust[1] = 3 # create 2-parcels clustering, smaller than background clustering = new_img_like(mask_img, data_clust) # clustering is smaller than mask assert (mask_img.get_fdata() > 0).sum() > (clustering.get_data() > 0).sum() algo = PairwiseAlignment(alignment_method='identity', mask=mask_img, clustering=clustering) with pytest.warns(UserWarning): algo.fit(img1, img1) assert (algo.mask.get_fdata() > 0).sum() == (clustering.get_fdata() > 0).sum() # test warning raised if parcel is 0 : null_im = new_img_like(img1, np.zeros_like(img1.get_fdata())) with pytest.warns(UserWarning): algo.fit(null_im, null_im)
def test_models_against_identity(): img1, mask_img = random_niimg((7, 6, 8, 5)) img2, _ = random_niimg((7, 6, 8, 5)) masker = NiftiMasker(mask_img=mask_img) masker.fit() ground_truth = masker.transform(img2) identity_baseline_score = zero_mean_coefficient_determination( ground_truth, masker.transform(img1)) for alignment_method in [ 'permutation', 'ridge_cv', 'scaled_orthogonal', 'optimal_transport', 'diagonal' ]: algo = PairwiseAlignment(alignment_method=alignment_method, mask=mask_img, n_pieces=2, n_bags=1, n_jobs=1) algo.fit(img1, img2) im_test = algo.transform(img1) algo_score = zero_mean_coefficient_determination( ground_truth, masker.transform(im_test)) assert_greater(algo_score, identity_baseline_score)
target_test = df[df.subject == 'sub-02'][df.acquisition == 'pa'].path.values ############################################################################# # Define the estimator used to align subjects, fit it and use it to predict # ------------------------------------------------------------------------- # To proceed with alignment we use PairwiseAlignment class. # We will use the common model proposed in the literature: # * we will align the whole brain through multiple local alignments. # * these alignments are calculated on a parcellation of the brain in 150 # pieces, this parcellation creates group of functionnally similar voxels. # from fmralign.pairwise_alignment import PairwiseAlignment alignement_estimator = PairwiseAlignment(alignment_method='scaled_orthogonal', n_pieces=150, mask=masker) # Learn alignment operator from subject 1 to subject 2 on training data alignement_estimator.fit(source_train, target_train) # Predict test data for subject 2 from subject 1 target_pred = alignement_estimator.transform(source_test) ############################################################################# # Score the prediction of test data with and without alignment # --------------------------------------------------- # To score the quality of prediction we use r2 score on each voxel # activation profile across contrasts. This score is 1 for a perfect prediction # and can get arbitrarly bad (here we clip it to -1 for bad predictions) from sklearn.metrics import r2_score import numpy as np
def align_one_target(sources_train, sources_test, target_train, target_test, method, masker, pairwise_method, clustering, n_pieces, n_jobs, decoding_dir=None, srm_atlas=None, srm_components=40, ha_radius=5, ha_sparse_radius=3, smoothing_fwhm=6, surface=False): overhead_time = 0 aligned_sources_test = [] if surface == "rh": clustering = clustering.replace("lh", "rh") # clustering = load_surf_data( # "/storage/store2/tbazeill/schaeffer/FreeSurfer5.3/fsaverage/label/rh.Schaefer2018_700Parcels_17Networks_order.annot") sources_train = np.asarray( [t.replace("lh", "rh") for t in sources_train]) sources_test = np.asarray( [t.replace("lh", "rh") for t in sources_test]) target_train.replace("lh", "rh") target_test.replace("lh", "rh") if surface in ["rh", "lh"]: from nilearn.surface import load_surf_data clustering = load_surf_data(clustering) if method == "anat_inter_subject": fit_start = time.process_time() if surface in ["lh", "rh"]: aligned_sources_test = load_clean(sources_test, masker) aligned_target_test = load_clean(target_test, masker) else: aligned_sources_test = np.vstack( [masker.transform(s) for s in sources_test]) aligned_target_test = masker.transform(target_test) elif method == "smoothing": fit_start = time.process_time() smoothing_masker = NiftiMasker(mask_img=masker.mask_img_, smoothing_fwhm=smoothing_fwhm).fit() aligned_sources_test = np.vstack( [smoothing_masker.transform(s) for s in sources_test]) aligned_target_test = smoothing_masker.transform(target_test) elif method in ["pairwise", "intra_subject"]: fit_start = time.process_time() for source_train, source_test in zip(sources_train, sources_test): if method == "pairwise": if surface in ["lh", "rh"]: source_align = SurfacePairwiseAlignment( alignment_method=pairwise_method, clustering=clustering, n_jobs=n_jobs) else: source_align = PairwiseAlignment( alignment_method=pairwise_method, clustering=clustering, n_pieces=n_pieces, mask=masker, n_jobs=n_jobs) source_align.fit(source_train, target_train) aligned_sources_test.append( source_align.transform(source_test)) elif method == "intra_subject": source_align = IntraSubjectAlignment( alignment_method="ridge_cv", clustering=clustering, n_pieces=n_pieces, mask=masker, n_jobs=n_jobs) source_align.fit(source_train, source_test) aligned_sources_test.append( source_align.transform(target_train)) if surface in ["lh", "rh"]: aligned_sources_test = np.vstack(aligned_sources_test) aligned_target_test = load_clean(target_test, masker) else: aligned_target_test = masker.transform(target_test) aligned_sources_test = np.vstack( [masker.transform(t) for t in aligned_sources_test]) elif method == "srm": common_time = time.process_time() fastsrm = FastSRM(atlas=srm_atlas, n_components=srm_components, n_iter=1000, n_jobs=n_jobs, aggregate="mean", temp_dir=decoding_dir) reduced_SR = fastsrm.fit_transform( [masker.transform(t).T for t in sources_train]) overhead_time = time.process_time() - common_time fit_start = time.process_time() fastsrm.aggregate = None fastsrm.add_subjects([masker.transform(t).T for t in [target_train]], reduced_SR) aligned_test = fastsrm.transform([ masker.transform(t).T for t in np.hstack([sources_test, [target_test]]) ]) aligned_sources_test = np.hstack(aligned_test[:-1]).T aligned_target_test = aligned_test[-1].T elif method == "HA": overhead_time = 0 fit_start = time.process_time() from mvpa2.algorithms.searchlight_hyperalignment import SearchlightHyperalignment from mvpa2.datasets.base import Dataset pymvpa_datasets = [] flat_mask = load_img(masker.mask_img_).get_fdata().flatten() n_voxels = flat_mask.sum() flat_coord_grid = make_coordinates_grid( masker.mask_img_.shape).reshape((-1, 3)) masked_coord_grid = flat_coord_grid[flat_mask != 0] for sub, sub_data in enumerate( np.hstack([[target_train], sources_train])): d = Dataset(masker.transform(sub_data)) d.fa['voxel_indices'] = masked_coord_grid pymvpa_datasets.append(d) ha = SearchlightHyperalignment(radius=ha_radius, nproc=1, sparse_radius=ha_sparse_radius) ha.__call__(pymvpa_datasets) aligned_sources_test = [] for j, source_test in enumerate(sources_test): if surface in ["lh", "rh"]: array_source = load_clean(source_test, masker) else: array_source = masker.transform(source_test) aligned_sources_test.append( array_source.dot(ha.projections[j + 1].proj.toarray())) aligned_sources_test = np.vstack(aligned_sources_test) aligned_target_test = masker.transform(target_test).dot( ha.projections[0].proj.toarray()) fit_time = time.process_time() - fit_start return aligned_sources_test, aligned_target_test, fit_time, overhead_time
# on the norm of R. # * the optimal transport plan, which yields the minimal transport cost # while respecting the mass conservation constraints. Calculated with # entropic regularization. # * we also include identity (no alignment) as a baseline. # Then for each method we define the estimator fit it, predict the new image and plot # its correlation with the real signal. # from fmralign.pairwise_alignment import PairwiseAlignment from fmralign.metrics import score_voxelwise methods = ['identity', 'scaled_orthogonal', 'ridge_cv', 'optimal_transport'] for method in methods: alignment_estimator = PairwiseAlignment(alignment_method=method, n_pieces=n_pieces, mask=roi_masker) alignment_estimator.fit(source_train, target_train) target_pred = alignment_estimator.transform(source_test) # derive correlation between prediction, test method_error = score_voxelwise(target_test, target_pred, masker=roi_masker, loss='corr') # plot correlation for each method aligned_score = roi_masker.inverse_transform(method_error) title = "Correlation of prediction after {} alignment".format(method) display = plotting.plot_stat_map(aligned_score, display_mode="z",
target_test = df[df.subject == 'sub-02'][df.acquisition == 'pa'].path.values ############################################################################# # Define the estimator used to align subjects, fit it and use it to predict # ------------------------------------------------------------------------- # To proceed with alignment we use the class PairwiseAlignment with the \ # visual mask we created before. \ # We use the scaled orthogonal method, common in the literature under the \ # name hyperalignment. As we work on a single ROI, we will search correspondence \ # between the full data of each subject and so we set the number of cluster \ # n_pieces to 1. We learn alignment estimator on train data and use it \ # to predict target test data # from fmralign.pairwise_alignment import PairwiseAlignment alignment_estimator = PairwiseAlignment( alignment_method='scaled_orthogonal', n_pieces=1, mask=roi_masker) alignment_estimator.fit(source_train, target_train) predicted_img = alignment_estimator.transform(source_test) ############################################################################# # Score the prediction of test data with and without alignment # --------------------------------------------------- # To score the quality of prediction we use r2 score \ # on each voxel activation profile across contrasts # This score is 1 for a perfect prediction and can get \ # arbitrarly bad (here we clip it to -1 for bad predictions) import numpy as np from sklearn.metrics import r2_score # Mask the real test data for subject 2 to get a ground truth vector ground_truth = roi_masker.transform(target_test)