def update_precision(model, variance=1): old = model.params.precision a_new, b_new = get_gamma_params(old, variance) new = scipy.stats.gamma.rvs(a_new, scale=(1 / b_new)) a_old, b_old = get_gamma_params(new, variance) model.params.precision = new log_p_new = model.joint_dist.log_p(model.data, model.params) log_q_new = scipy.stats.gamma.logpdf(new, a_new, scale=(1 / b_new)) model.params.precision = old log_p_old = model.joint_dist.log_p(model.data, model.params) log_q_old = scipy.stats.gamma.logpdf(old, a_old, scale=(1 / b_old)) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, log_q_new, log_q_old): model.params.precision = new else: model.params.precision = old
def update_alpha(model): """ Metropolis-Hastings update of the Beta-Bernoulli or IBP concentration parameter from a Gamma(1, 1) prior. Note: The model parameters will be updated in place. Parameters ---------- model: pgfa.models.base.AbstractModel """ a = model.params.alpha_prior[0] b = model.params.alpha_prior[1] alpha_old = model.params.alpha log_p_old = model.feat_alloc_dist.log_p(model.params) alpha_new = scipy.stats.gamma.rvs(a, scale=(1 / b)) model.params.alpha = alpha_new log_p_new = model.feat_alloc_dist.log_p(model.params) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): model.params.alpha = alpha_new else: model.params.alpha = alpha_old
def _update_V_element_symmetric(i, j, model, proposal_precision): proposal_std = 1 / np.sqrt(proposal_precision) v_old = model.params.V[i, j] log_p_old = model.log_p v_new = scipy.stats.norm.rvs(v_old, proposal_std) model.params.V[i, j] = v_new model.params.V[j, i] = v_new log_p_new = model.log_p log_q_old = scipy.stats.norm.logpdf(v_old, v_new, proposal_std) log_q_new = scipy.stats.norm.logpdf(v_new, v_old, proposal_std) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, log_q_new, log_q_old): model.params.V[i, j] = v_new model.params.V[j, i] = v_new else: model.params.V[i, j] = v_old model.params.V[j, i] = v_old
def update_V_random_grid_pairwise(model, num_points=10): if model.params.K < 2: return ka, kb = np.random.choice(model.params.K, 2, replace=False) params = model.params.copy() old = params.V[[ka, kb]].flatten() D = params.D dim = 2 * D e = scipy.stats.multivariate_normal.rvs(np.zeros(dim), np.eye(dim)) e /= np.linalg.norm(e) r = scipy.stats.gamma.rvs(1, 1) grid = np.arange(1, num_points + 1) ys = old[np.newaxis, :] + grid[:, np.newaxis] * r * e[np.newaxis, :] log_p_new = np.zeros(num_points) for i in range(num_points): params.V[[ka, kb]] = ys[i].reshape((2, D)) log_p_new[i] = model.joint_dist.log_p(model.data, params) if np.all(np.isneginf(log_p_new)) or np.any(np.isnan(log_p_new)): return try: idx = discrete_rvs( np.exp(0.5 * np.log(grid) + log_normalize(log_p_new))) except ValueError: return new = ys[idx] xs = new[np.newaxis, :] - grid[:, np.newaxis] * r * e[np.newaxis, :] log_p_old = np.zeros(num_points) for i in range(num_points): params.V[[ka, kb]] = xs[i].reshape((2, D)) log_p_old[i] = model.joint_dist.log_p(model.data, params) if do_metropolis_hastings_accept_reject(log_sum_exp(log_p_new), log_sum_exp(log_p_old), 0, 0): params.V[[ka, kb]] = new.reshape((2, D)) else: params.V[[ka, kb]] = old.reshape((2, D)) model.params = params
def update(self, model): anchors = np.random.choice(model.params.N, replace=False, size=2) if (np.sum(model.params.Z[anchors[0]]) == 0) or ((np.sum( model.params.Z[anchors[1]]) == 0)): return features, log_q_feature_fwd = self._select_features( anchors, model.params.Z) if features[0] == features[1]: V_new, Z_new, log_q_sm_fwd = self._propose_split( anchors, features, model, model.params.V, model.params.Z) _, log_q_feature_rev = self._select_features(anchors, Z_new) K_new = Z_new.shape[1] _, _, log_q_sm_rev = self._propose_merge( anchors, np.array([K_new - 2, K_new - 1]), V_new, Z_new) else: V_new, Z_new, log_q_sm_fwd = self._propose_merge( anchors, features, model.params.V, model.params.Z) _, log_q_feature_rev = self._select_features(anchors, Z_new) K_new = Z_new.shape[1] _, _, log_q_sm_rev = self._propose_split( anchors, np.array([K_new - 1, K_new - 1]), model, V_new, Z_new, Z_target=model.params.Z[:, features]) params_fwd = model.params.copy() params_fwd.V = V_new params_fwd.Z = Z_new log_p_fwd = model.joint_dist.log_p(model.data, params_fwd) params_rev = model.params log_p_rev = model.joint_dist.log_p(model.data, params_rev) if do_metropolis_hastings_accept_reject( log_p_fwd, log_p_rev, self.annealing_factor * (log_q_feature_fwd + log_q_sm_fwd), self.annealing_factor * (log_q_feature_rev + log_q_sm_rev)): model.params = params_fwd else: model.params = params_rev
def update_row(self, model, row_idx): alpha = model.params.alpha tau_v = model.params.tau_v D = model.params.D N = model.params.N k_old = len(self._get_singleton_idxs(model.params.Z, row_idx)) k_new = scipy.stats.poisson.rvs(alpha / N) if (k_new == 0) and (k_old == 0): return model.params non_singleton_idxs = self._get_non_singleton_idxs( model.params.Z, row_idx) num_non_singletons = len(non_singleton_idxs) K_new = len(non_singleton_idxs) + k_new params_old = model.params.copy() params_new = model.params.copy() params_new.V = np.zeros((K_new, D)) params_new.V[:num_non_singletons] = model.params.V[non_singleton_idxs] if k_new > 0: params_new.V[num_non_singletons:] = scipy.stats.matrix_normal.rvs( mean=np.zeros((k_new, D)), rowcov=(1 / tau_v) * np.eye(k_new), colcov=np.eye(D)) params_new.Z = np.zeros((N, K_new), dtype=np.int8) params_new.Z[:, : num_non_singletons] = model.params.Z[:, non_singleton_idxs] params_new.Z[row_idx, num_non_singletons:] = 1 log_p_new = model.data_dist.log_p_row(model.data, params_new, row_idx) log_p_old = model.data_dist.log_p_row(model.data, model.params, row_idx) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): model.params = params_new else: model.params = params_old
def update_V_block_dim(model, variance=1): params = model.params.copy() a_prior, b_prior = model.params.V_prior for d in np.random.permutation(model.params.D): old = params.V[:, d].copy() new = np.zeros(params.K) log_p_new = 0 log_q_new = 0 log_p_old = 0 log_q_old = 0 for k in range(model.params.K): a, b = get_gamma_params(old[k], variance) new[k] = scipy.stats.gamma.rvs(a, scale=(1 / b)) log_p_new += scipy.stats.gamma.logpdf(new[k], a_prior, scale=(1 / b_prior)) log_q_new += scipy.stats.gamma.logpdf(new[k], a, scale=(1 / b)) a, b = get_gamma_params(new[k], variance) log_p_old += scipy.stats.gamma.logpdf(old[k], a_prior, scale=(1 / b_prior)) log_q_old += scipy.stats.gamma.logpdf(old[k], a, scale=(1 / b)) params.V[:, d] = new log_p_new += model.data_dist.log_p(model.data, params) params.V[:, d] = old log_p_old += model.data_dist.log_p(model.data, params) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, log_q_new, log_q_old): params.V[:, d] = new else: params.V[:, d] = old model.params = params
def update_row(self, model, row_idx): alpha = model.params.alpha D = model.params.D N = model.params.N k_old = len(self._get_singleton_idxs(model.params.Z, row_idx)) k_new = scipy.stats.poisson.rvs(alpha / N) if (k_new == 0) and (k_old == 0): return model.params non_singleton_idxs = self._get_non_singleton_idxs( model.params.Z, row_idx) num_non_singletons = len(non_singleton_idxs) K_new = len(non_singleton_idxs) + k_new params_old = model.params.copy() params_new = model.params.copy() params_new.V = np.zeros((K_new, D)) params_new.V[:num_non_singletons] = model.params.V[non_singleton_idxs] if k_new > 0: a, b = model.params.V_prior params_new.V[num_non_singletons:] = scipy.stats.gamma.rvs( a, scale=(1 / b), size=(k_new, model.params.D)) params_new.Z = np.zeros((N, K_new), dtype=np.int8) params_new.Z[:, : num_non_singletons] = model.params.Z[:, non_singleton_idxs] params_new.Z[row_idx, num_non_singletons:] = 1 log_p_new = model.data_dist.log_p(model.data, params_new) log_p_old = model.data_dist.log_p(model.data, model.params) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): model.params = params_new else: model.params = params_old
def update_V_random_grid(model, num_points=10): if model.params.K < 2: return params = model.params.copy() old = params.V.flatten() K, D = params.V.shape dim = K * D e = scipy.stats.multivariate_normal.rvs(np.zeros(dim), np.eye(dim)) e /= np.linalg.norm(e) r = scipy.stats.gamma.rvs(1, 1) grid = np.arange(1, num_points + 1) ys = old[np.newaxis, :] + grid[:, np.newaxis] * r * e[np.newaxis, :] log_p_new = np.zeros(num_points) for i in range(num_points): params.V = ys[i].reshape((K, D)) log_p_new[i] = model.joint_dist.log_p(model.data, params) idx = discrete_rvs(np.exp(0.5 * np.log(grid) + log_normalize(log_p_new))) new = ys[idx] xs = new[np.newaxis, :] - grid[:, np.newaxis] * r * e[np.newaxis, :] log_p_old = np.zeros(num_points) for i in range(num_points): params.V = xs[i].reshape((K, D)) log_p_old[i] = model.joint_dist.log_p(model.data, params) if do_metropolis_hastings_accept_reject(log_sum_exp(log_p_new), log_sum_exp(log_p_old), 0, 0): params.V = new.reshape((K, D)) else: params.V = old.reshape((K, D)) model.params = params
def update_V(model, variance=1): params = model.params.copy() a_prior, b_prior = model.params.V_prior Ds = np.random.permutation(model.params.D) Ks = np.random.permutation(model.params.K) for d in Ds: for k in Ks: old = params.V[k, d] a, b = get_gamma_params(old, variance) new = scipy.stats.gamma.rvs(a, scale=(1 / b)) params.V[k, d] = new log_p_new = model.data_dist.log_p(model.data, params) log_p_new += scipy.stats.gamma.logpdf(new, a_prior, scale=(1 / b_prior)) log_q_new = scipy.stats.gamma.logpdf(new, a, scale=(1 / b)) a, b = get_gamma_params(new, variance) params.V[k, d] = old log_p_old = model.data_dist.log_p(model.data, params) log_p_old += scipy.stats.gamma.logpdf(old, a_prior, scale=(1 / b_prior)) log_q_old = scipy.stats.gamma.logpdf(old, a, scale=(1 / b)) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, log_q_new, log_q_old): params.V[k, d] = new else: params.V[k, d] = old model.params = params
def update_V_perm(model): params = model.params.copy() for d in np.random.permutation(model.params.D): old = params.V[:, d].copy() new = params.V[np.random.permutation(params.K), d] params.V[:, d] = new log_p_new = model.data_dist.log_p(model.data, params) params.V[:, d] = old log_p_old = model.data_dist.log_p(model.data, params) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): params.V[:, d] = new else: params.V[:, d] = old model.params = params
def update_row(self, model, row_idx): alpha = model.params.alpha t_v = model.params.tau_v t_x = model.params.tau_x V = model.params.V Z = model.params.Z X = model.data D = model.params.D N = model.params.N m = np.sum(Z, axis=0) m -= Z[row_idx] k_old = np.sum(m == 0) k_new = np.random.poisson(alpha / N) if k_new == k_old: return model.params non_singletons_idxs = np.atleast_1d(np.squeeze(np.where(m > 0))) xmo = np.square( X[row_idx] - Z[row_idx, non_singletons_idxs] @ V[non_singletons_idxs]) log_p_old = 0 log_p_new = 0 for d in range(D): if np.isnan(xmo[d]): continue log_p_old -= 0.5 * np.log((1 / t_x) + k_old * (1 / t_v)) log_p_old -= 0.5 * np.sum(1 / ((1 / t_x) + k_old * (1 / t_v)) * xmo[d]) log_p_new -= 0.5 * np.log((1 / t_x) + k_new * (1 / t_v)) log_p_new -= 0.5 * np.sum(1 / ((1 / t_x) + k_new * (1 / t_v)) * xmo[d]) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): non_singletons_idxs = np.atleast_1d(np.squeeze(np.where(m > 0))) num_non_singletons = len(non_singletons_idxs) K = num_non_singletons + k_new Z = np.zeros((N, K), dtype=np.int64) Z[:, :num_non_singletons] = model.params.Z[:, non_singletons_idxs] Z[row_idx, num_non_singletons:] = 1 V = np.zeros((K, D)) V[:num_non_singletons] = model.params.V[non_singletons_idxs] if k_new > 0: V[num_non_singletons:] = self._sample_new_V( k_new, model.data, model.params) model.params.Z = Z model.params.V = V
def update_row(self, model, row_idx): singleton_idxs = get_singleton_idxs(model.params.Z, row_idx) k_old = len(singleton_idxs) k_new = scipy.stats.poisson.rvs(model.params.alpha / model.params.N) if (k_new == 0) and (k_old == 0): return model.params non_singleton_idxs = get_non_singleton_idxs(model.params.Z, row_idx) num_non_singletons = len(non_singleton_idxs) K_new = len(non_singleton_idxs) + k_new Z_new = np.zeros((model.params.N, K_new), dtype=np.int64) Z_new[:, :num_non_singletons] = model.params.Z[:, non_singleton_idxs] Z_new[row_idx, num_non_singletons:] = 1 V_new = np.zeros((K_new, K_new)) # Copy over old values for i in range(num_non_singletons): for j in range(num_non_singletons): V_new[i, j] = model.params.V[non_singleton_idxs[i], non_singleton_idxs[j]] # Propose new values for V std = 1 / np.sqrt(model.params.tau) if model.symmetric: for i in range(num_non_singletons, K_new): V_new[i, i] = scipy.stats.norm.rvs(0, std) for j in range(num_non_singletons): V_new[i, j] = scipy.stats.norm.rvs(0, std) V_new[j, i] = V_new[i, j] assert np.all(V_new.T == V_new) else: for i in range(num_non_singletons, K_new): for j in range(K_new): V_new[i, j] = scipy.stats.norm.rvs(0, std) if i != j: V_new[j, i] = scipy.stats.norm.rvs(0, std) for i in range(num_non_singletons): assert np.all( V_new[i, :num_non_singletons] == model.params.V[non_singleton_idxs[i]][non_singleton_idxs] ) params_new = model.params.copy() params_new.V = V_new params_new.Z = Z_new log_p_new = model.data_dist.log_p(model.data, params_new) log_p_old = model.data_dist.log_p(model.data, model.params) if do_metropolis_hastings_accept_reject(log_p_new, log_p_old, 0, 0): model.params = params_new