def _L21_gamma_hypermodel_sampler(M, G, X0, gammas, n_orient, beta, n_burnin, n_samples, sc_n_samples=10, ss_n_samples=200, random_state=None, verbose=False): """Run Gamma sampler Parameters ---------- M : array, shape (n_samples, n_times) The data. G : array, shape (n_samples, n_features) The forward operator / design matrix. X0 : array, shape (n_features, n_times) The initial X. gammas : array, shape (n_locations, n_times) The initial gammas. n_orient : int The number of orientation (1 : fixed or 3 : free or loose). Used for M/EEG application as there is 3 features per physical locations. We have n_locations = n_features // n_orient. bela : float The beta scale paraemter of the gamma distribution n_burnin : int The number of iterations in the burnin phase. n_samples : int The number of sampels to draw. ss_n_samples : int The number of samples in the slice sampler. random_state : int | None An integer to fix the seed of the numpy random number generator. Necessary to have replicable results. verbose : bool If True print info on optimization. Returns ------- XChain : array, shape (n_features, n_times, n_samples) The X samples along the chain. gammaChain : array, shape (n_locations, n_samples) The gamma samples along the chain. """ rng = check_random_state(random_state) n_dipoles = G.shape[1] n_locations = n_dipoles // n_orient _, n_times = M.shape XChain = np.zeros((n_dipoles, n_times, n_samples)) gammaChain = np.zeros((n_locations, n_samples)) # precompute some terms GColSqNorm = np.sum(G ** 2, axis=0) GTM = np.dot(G.T, M) GTG = np.dot(G.T, G) if not X0.all(): X = np.zeros((n_locations * n_orient, n_times)) else: X = X0 for k in range(-n_burnin, n_samples): if verbose: print("Running iter %d" % k) # update X by single component Gibbs sampler # initialize with 0 instead of current state (this had a proper reason, # but we should re-examine) # X = np.zeros((n_locations * n_orient, n_times)) for kSCGibbs in range(sc_n_samples): # print(" -- Running SC iter %d" % kSCGibbs) randLocOrder = rng.permutation(n_locations) for jLoc in randLocOrder: # a only depends on the location a = GColSqNorm[jLoc] / 2. c = 1. / gammas[jLoc] # extract X for this location XLoc = X[jLoc * n_orient: (jLoc + 1) * n_orient, :] XLocSqNorm = linalg.norm(XLoc, 'fro') ** 2 # update all time points and all dir without random shuffle for jTime in range(n_times): for jDir in range(n_orient): # get corresponding dipole, time and block index jComp = jDir + jLoc * n_orient XjComp = X[jComp, jTime] # compute b and d b = GTM[jComp, jTime] - np.dot(X[:, jTime].T, GTG[:, jComp]) + \ 2 * a * XjComp d = XLocSqNorm - XjComp**2 # call slice sampler XjComp = _sc_slice_sampler( a, b, c, d, XjComp, ss_n_samples, rng) # update auxillary variables XLocSqNorm = d + XjComp**2 X[jComp, jTime] = XjComp # check for instabilities cause by insufficient sampling steps, # usually leading to an explosion of the residual # if (linalg.norm(G.dot(X) - M, 'fro') / linalg.norm(M, 'fro')) > 10: # raise ValueError('relative residual exceeded threshold, ' # 'the sampler is likely to diverge due to ' # 'insufficient precision in the block-sampling') # update gamma by umbrella sampler # Compute the amplitudes of the sources for one hyperparameter XBlkNorm = np.sqrt(groups_norm2(X.copy(), n_orient)) gammas = _cond_gamma_hyperprior_sampler(XBlkNorm, beta, rng) # store results if k >= 0: XChain[:, :, k] = X gammaChain[:, k] = gammas return XChain, gammaChain
def compute_block_norms(w, n_orient): return np.sqrt(groups_norm2(w.copy(), n_orient))
def compute_block_norms(w, nDir): return np.sqrt(groups_norm2(w.copy(), nDir))
def _L21_gamma_hypermodel_sampler(M, G, X0, gammas, n_orient, beta, n_burnin, n_samples, sc_n_samples=10, ss_n_samples=200, verbose=False): # XXX : add docstring rng = np.random.RandomState(42) n_dipoles = G.shape[1] n_locations = n_dipoles // n_orient _, n_times = M.shape XChain = np.zeros((n_dipoles, n_times, n_samples)) gammaChain = np.zeros((n_locations, n_samples)) # precompute some terms GColSqNorm = np.sum(G ** 2, axis=0) GTM = np.dot(G.T, M) GTG = np.dot(G.T, G) if not X0.all(): X = np.zeros((n_locations * n_orient, n_times)) else: X = X0 for k in range(-n_burnin, n_samples): if verbose: print("Running iter %d" % k) # update X by single component Gibbs sampler # initialize with 0 instead of current state (this had a proper reason, # but we should re-examine) # X = np.zeros((n_locations * n_orient, n_times)) for kSCGibbs in range(sc_n_samples): # print(" -- Running SC iter %d" % kSCGibbs) randLocOrder = rng.permutation(n_locations) for jLoc in randLocOrder: # a only depends on the location a = GColSqNorm[jLoc] / 2. c = 1. / gammas[jLoc] # extract X for this location XLoc = X[jLoc * n_orient: (jLoc + 1) * n_orient, :] XLocSqNorm = linalg.norm(XLoc, 'fro') ** 2 # update all time points and all dir without random shuffle for jTime in range(n_times): for jDir in range(n_orient): # get corresponding dipole, time and block index jComp = jDir + jLoc * n_orient XjComp = X[jComp, jTime] # compute b and d b = GTM[jComp, jTime] - np.dot(X[:, jTime].T, GTG[:, jComp]) + \ 2 * a * XjComp d = XLocSqNorm - XjComp**2 # call slice sampler XjComp = _sc_slice_sampler( a, b, c, d, XjComp, ss_n_samples) # update auxillary variables XLocSqNorm = d + XjComp**2 X[jComp, jTime] = XjComp # check for instabilities cause by insufficient sampling steps, # usually leading to an explosion of the residual # if (linalg.norm(G.dot(X) - M, 'fro') / linalg.norm(M, 'fro')) > 10: # raise ValueError('relative residual exceeded threshold, ' # 'the sampler is likely to diverge due to ' # 'insufficient precision in the block-sampling') # update gamma by umbrella sampler # Compute the amplitudes of the sources for one hyperparameter XBlkNorm = np.sqrt(groups_norm2(X.copy(), n_orient)) gammas = _cond_gamma_hyperprior_sampler(XBlkNorm, beta) # store results if k >= 0: XChain[:, :, k] = X gammaChain[:, k] = gammas return XChain, gammaChain