def plscorr_eval(train_fmri_ts, train_feat_ts, val_fmri_ts, val_feat_ts, out_dir, mask_file): """Compute PLS correlation between brain activity and CNN activation.""" train_feat_ts = train_feat_ts.reshape(-1, train_feat_ts.shape[3]).T val_feat_ts = val_feat_ts.reshape(-1, val_feat_ts.shape[3]).T train_fmri_ts = train_fmri_ts.T val_fmri_ts = val_fmri_ts.T # Iteration loop for different component number #for n in range(5, 19): # print '--- Components number %s ---' %(n) # plsca = PLSCanonical(n_components=n) # plsca.fit(train_feat_ts, train_fmri_ts) # pred_feat_c, pred_fmri_c = plsca.transform(val_feat_ts, val_fmri_ts) # pred_fmri_ts = plsca.predict(val_feat_ts) # # calculate correlation coefficient between truth and prediction # r = corr2_coef(val_fmri_ts.T, pred_fmri_ts.T, mode='pair') # # get top 20% corrcoef for model evaluation # vsample = int(np.rint(0.2*len(r))) # print 'Sample size for evaluation : %s' % (vsample) # r.sort() # meanr = np.mean(r[-1*vsample:]) # print 'Mean prediction corrcoef : %s' %(meanr) # model generation based on optimized CC number cc_num = 10 plsca = PLSCanonical(n_components=cc_num) plsca.fit(train_feat_ts, train_fmri_ts) from sklearn.externals import joblib joblib.dump(plsca, os.path.join(out_dir, 'plsca_model.pkl')) plsca = joblib.load(os.path.join(out_dir, 'plsca_model.pkl')) # calculate correlation coefficient between truth and prediction pred_fmri_ts = plsca.predict(val_feat_ts) fmri_pred_r = corr2_coef(val_fmri_ts.T, pred_fmri_ts.T, mode='pair') mask = vutil.data_swap(mask_file) vxl_idx = np.nonzero(mask.flatten() == 1)[0] tmp = np.zeros_like(mask.flatten(), dtype=np.float64) tmp[vxl_idx] = fmri_pred_r tmp = tmp.reshape(mask.shape) vutil.save2nifti(tmp, os.path.join(out_dir, 'pred_fmri_r.nii.gz')) pred_feat_ts = pls_y_pred_x(plsca, val_fmri_ts) pred_feat_ts = pred_feat_ts.T.reshape(96, 14, 14, 540) np.save(os.path.join(out_dir, 'pred_feat.npy'), pred_feat_ts) # get PLS-CCA weights feat_cc, fmri_cc = plsca.transform(train_feat_ts, train_fmri_ts) np.save(os.path.join(out_dir, 'feat_cc.npy'), feat_cc) np.save(os.path.join(out_dir, 'fmri_cc.npy'), fmri_cc) feat_weight = plsca.x_weights_.reshape(96, 14, 14, cc_num) #feat_weight = plsca.x_weights_.reshape(96, 11, 11, cc_num) fmri_weight = plsca.y_weights_ np.save(os.path.join(out_dir, 'feat_weights.npy'), feat_weight) np.save(os.path.join(out_dir, 'fmri_weights.npy'), fmri_weight) fmri_orig_ccs = get_pls_components(plsca.y_scores_, plsca.y_loadings_) np.save(os.path.join(out_dir, 'fmri_orig_ccs.npy'), fmri_orig_ccs)
def reg_cca(train_fmri_ts, train_feat_ts, val_fmri_ts, val_feat_ts, out_dir): """Conduct CCA between brain activity and CNN activation.""" train_feat_ts = train_feat_ts.reshape(-1, train_feat_ts.shape[3]).T val_feat_ts = val_feat_ts.reshape(-1, val_feat_ts.shape[3]).T train_fmri_ts = train_fmri_ts.T val_fmri_ts = val_fmri_ts.T #-- model training # for reduce complexity, a linear kernel is used #cca = rcca.CCACrossValidate(numCCs=[7, 8, 9, 10, 11, 12, 13], # kernelcca=True) CCnum = 7 #cca = rcca.CCA(kernelcca=True, reg=0.007743, numCC=CCnum) #cca.train([train_feat_ts, train_fmri_ts]) #cca.validate([val_feat_ts, val_fmri_ts]) #cca.compute_ev([val_feat_ts, val_fmri_ts]) #print 'Best CC number : %s' %(cca.best_numCC) #print 'Best reg : %s' %(cca.best_reg) out_file = os.path.join(out_dir, 'CCA_results_%s.hdf5' % (CCnum)) #cca.save(os.path.join(out_file)) #-- model exploring mask_file = r'/Users/sealhuang/brainDecoding/S1_mask.nii.gz' cca = rcca.CCA() cca.load(out_file) # model prediction performance fmri_pred_r = cca.corrs[1] feat_pred_r = cca.corrs[0].reshape(96, 11, 11) vutil.plot_cca_fweights(feat_pred_r, out_dir, 'pred_feat_r_CC%s' % (CCnum)) mask = vutil.data_swap(mask_file) vxl_idx = np.nonzero(mask.flatten() == 1)[0] tmp = np.zeros_like(mask.flatten(), dtype=np.float64) tmp[vxl_idx] = fmri_pred_r tmp = tmp.reshape(mask.shape) vutil.save2nifti( tmp, os.path.join(out_dir, 'pred_fmri_r_CC%s.nii.gz' % (CCnum))) # model weights visualization feat_weights = cca.ws[0] feat_weights = feat_weights.reshape(96, 11, 11, feat_weights.shape[1]) fmri_weights = cca.ws[1] vutil.plot_cca_fweights(feat_weights, out_dir, 'feat_weight_CC%s' % (CCnum)) vutil.save_cca_volweights(fmri_weights, mask_file, out_dir, 'cca_component') feat_cc = cca.comps[0] parallel_corr2_coef(train_feat_ts.T, feat_cc.T, os.path.join(out_dir, 'feat_cc_corr.npy'), block_size=7, n_jobs=1) feat_cc_corr = np.load(os.path.join(out_dir, 'feat_cc_corr.npy')) feat_cc_corr = feat_cc_corr.reshape(96, 11, 11, 7) vutil.plot_cca_fweights(feat_cc_corr, out_dir, 'feat_cc_corr')
def prf2visual_angle(prf_mtx, img_size, out_dir, base_name): """Generate retinotopic mapping based on voxels' pRF parameters. `prf_mtx` is a #voxel x pRF-features matrix, pRF features can be 2 columns (row, col) of image or 3 columns which adding a third pRF size parameters. """ feature_size = prf_mtx.shape[1] pos_mtx = prf_mtx[:, :2] # eccentricity ecc = retinotopy.coord2ecc(pos_mtx, img_size, 20) vol = ecc.reshape(18, 64, 64) vutil.save2nifti(vol, os.path.join(out_dir, base_name + '_ecc.nii.gz')) # angle angle = retinotopy.coord2angle(pos_mtx, img_size) vol = angle.reshape(18, 64, 64) vutil.save2nifti(vol, os.path.join(out_dir, base_name + '_angle.nii.gz')) # pRF size if feature_size > 2: size_angle = retinotopy.get_prf_size(prf_mtx, 55, 20) vol = size_angle.reshape(18, 64, 64) vutil.save2nifti(vol, os.path.join(out_dir, base_name + '_size.nii.gz'))
def retinotopic_mapping(corr_file, data_dir, vxl_idx=None, figout=False): """Make the retinotopic mapping using activation map from CNN.""" if figout: fig_dir = os.path.join(data_dir, 'fig') check_path(fig_dir) # load the cross-correlation matrix from file corr_mtx = np.load(corr_file, mmap_mode='r') # set voxel index if not isinstance(vxl_idx, np.ndarray): vxl_idx = np.arange(corr_mtx.shape[0]) elif len(vxl_idx) != corr_mtx.shape[0]: print 'mismatch on voxel number!' return else: print 'voxel index loaded.' pos_mtx = np.zeros((73728, 2)) pos_mtx[:] = np.nan for i in range(len(vxl_idx)): print 'Iter %s of %s' % (i + 1, len(vxl_idx)), tmp = corr_mtx[i, :] tmp = np.nan_to_num(np.array(tmp)) # significant threshold for one-tail test tmp[tmp <= 0.019257] = 0 if np.sum(tmp): tmp = tmp.reshape(96, 27, 27) mmtx = np.max(tmp, axis=0) print mmtx.min(), mmtx.max() # get indices of n maximum values max_n = 20 row_idx, col_idx = np.unravel_index( np.argsort(mmtx.ravel())[-1 * max_n:], mmtx.shape) nmtx = np.zeros(mmtx.shape) nmtx[row_idx, col_idx] = mmtx[row_idx, col_idx] if figout: fig_file = os.path.join(fig_dir, 'v' + str(vxl_idx[i]) + '.png') imsave(fig_file, nmtx) # center of mass x, y = ndimage.measurements.center_of_mass(nmtx) pos_mtx[vxl_idx[i], :] = [x, y] else: print ' ' #receptive_field_file = os.path.join(data_dir, 'receptive_field_pos.npy') #np.save(receptive_field_file, pos_mtx) #pos_mtx = np.load(receptive_field_file) # eccentricity dist = retinotopy.coord2ecc(pos_mtx, (27, 27)) # convert distance into degree # 0-4 degree -> d < 5.5 # 4-8 degree -> d < 11 # 8-12 degree -> d < 16.5 # 12-16 degree -> d < 22 # else > 16 degree ecc = np.zeros(dist.shape) for i in range(len(dist)): if np.isnan(dist[i]): ecc[i] = np.nan elif dist[i] < 2.7: ecc[i] = 1 elif dist[i] < 5.4: ecc[i] = 2 elif dist[i] < 8.1: ecc[i] = 3 elif dist[i] < 10.8: ecc[i] = 4 else: ecc[i] = 5 #dist_vec = np.nan_to_num(ecc) #vol = dist_vec.reshape(18, 64, 64) vol = ecc.reshape(18, 64, 64) vutil.save2nifti( vol, os.path.join(data_dir, 'train_max' + str(max_n) + '_ecc.nii.gz')) # angle angle_vec = retinotopy.coord2angle(pos_mtx, (27, 27)) #angle_vec = np.nan_to_num(angle_vec) vol = angle_vec.reshape(18, 64, 64) vutil.save2nifti( vol, os.path.join(data_dir, 'train_max' + str(max_n) + '_angle.nii.gz'))
def ridge_retinotopic_mapping(corr_file, vxl_idx=None, top_n=None): """Make the retinotopic mapping using activation map from CNN.""" data_dir = os.path.dirname(corr_file) # load the cross-correlation matrix from file corr_mtx = np.load(corr_file, mmap_mode='r') # corr_mtx.shape = (3025, vxl_num) if not isinstance(vxl_idx, np.ndarray): vxl_idx = np.arange(corr_mtx.shape[1]) if not top_n: top_n = 20 pos_mtx = np.zeros((73728, 2)) pos_mtx[:] = np.nan for i in range(len(vxl_idx)): print 'Iter %s of %s' % (i, len(vxl_idx)), tmp = corr_mtx[:, i] tmp = np.nan_to_num(np.array(tmp)) # significant threshold # one-tail test #tmp[tmp <= 0.17419] = 0 if np.sum(tmp): tmp = tmp.reshape(55, 55) print tmp.min(), tmp.max() # get indices of n maximum values row, col = np.unravel_index( np.argsort(tmp.ravel())[-1 * top_n:], tmp.shape) mtx = np.zeros(tmp.shape) mtx[row, col] = tmp[row, col] # center of mass x, y = ndimage.measurements.center_of_mass(mtx) pos_mtx[vxl_idx[i], :] = [x, y] else: print ' ' #receptive_field_file = os.path.join(data_dir, 'receptive_field_pos.npy') #np.save(receptive_field_file, pos_mtx) #pos_mtx = np.load(receptive_field_file) # eccentricity dist = retinotopy.coord2ecc(pos_mtx, (55, 55)) # convert distance into degree # 0-4 degree -> d < 5.5 # 4-8 degree -> d < 11 # 8-12 degree -> d < 16.5 # 12-16 degree -> d < 22 # else > 16 degree ecc = np.zeros(dist.shape) for i in range(len(dist)): if np.isnan(dist[i]): ecc[i] = np.nan elif dist[i] < 5.445: ecc[i] = 1 elif dist[i] < 10.91: ecc[i] = 2 elif dist[i] < 16.39: ecc[i] = 3 elif dist[i] < 21.92: ecc[i] = 4 else: ecc[i] = 5 vol = ecc.reshape(18, 64, 64) vutil.save2nifti(vol, os.path.join(data_dir, 'ecc_max%s.nii.gz' % (top_n))) # angle angle_vec = retinotopy.coord2angle(pos_mtx, (55, 55)) vol = angle_vec.reshape(18, 64, 64) vutil.save2nifti(vol, os.path.join(data_dir, 'angle_max%s.nii.gz' % (top_n)))