def test_logitnormal_moments(self): # global parameters for computing lognormals gh_loc, gh_weights = hermgauss(4) # log normal parameters lognorm_means = np.random.random((5, 3)) # should work for arrays now lognorm_infos = np.random.random((5, 3))**2 + 1 alpha = 2 # dp parameter # draw samples num_draws = 10**5 samples = np.random.normal(lognorm_means, 1/np.sqrt(lognorm_infos), size = (num_draws, 5, 3)) logit_norm_samples = sp.special.expit(samples) # test lognormal means np_test.assert_allclose( np.mean(logit_norm_samples, axis = 0), ef.get_e_logitnormal( lognorm_means, lognorm_infos, gh_loc, gh_weights), atol = 3 * np.std(logit_norm_samples) / np.sqrt(num_draws)) # test Elog(x) and Elog(1-x) log_logistic_norm = np.mean(np.log(logit_norm_samples), axis = 0) log_1m_logistic_norm = np.mean(np.log(1 - logit_norm_samples), axis = 0) tol1 = 3 * np.std(np.log(logit_norm_samples))/ np.sqrt(num_draws) tol2 = 3 * np.std(np.log(1 - logit_norm_samples))/ np.sqrt(num_draws) np_test.assert_allclose( log_logistic_norm, ef.get_e_log_logitnormal( lognorm_means, lognorm_infos, gh_loc, gh_weights)[0], atol = tol1) np_test.assert_allclose( log_1m_logistic_norm, ef.get_e_log_logitnormal( lognorm_means, lognorm_infos, gh_loc, gh_weights)[1], atol = tol2) # test prior prior_samples = np.mean((alpha - 1) * np.log(1 - logit_norm_samples), axis = 0) tol3 = 3 * np.std((alpha - 1) * np.log(1 - logit_norm_samples)) \ /np.sqrt(num_draws) np_test.assert_allclose( prior_samples, ef.get_e_dp_prior_logitnorm_approx( alpha, lognorm_means, lognorm_infos, gh_loc, gh_weights), atol = tol3) x = np.random.normal(0, 1e2, size = 10) def e_log_v(x): return np.sum(ef.get_e_log_logitnormal(\ x[0:5], np.abs(x[5:10]), gh_loc, gh_weights)[0]) check_grads(e_log_v, order=2)(x)
def get_stick_breaking_entropy(stick_propn_mean, stick_propn_info, gh_loc, gh_weights): # return the entropy of logitnormal distriibution on the sticks whose # logit has mean stick_propn_mean and information stick_propn_info # Integration is done on the real line with respect to the Lesbegue measure # integration is done numerical with Gauss Hermite quadrature. # gh_loc and gh_weights specifiy the location and weights of the # quadrature points # we seek E[log q(V)], where q is the density of a logit-normal, and # V ~ logit-normal. Let W := logit(V), so W ~ Normal. Hence, # E[log q(W)]; we can then decompose log q(x) into the terms of a normal # distribution and the jacobian term. The expectation of the normal term # evaluates to the normal entropy, and we add the jacobian term to it. # The jacobian term is 1/(x(1-x)), so we simply add -EV - E(1-V) to the normal # entropy. assert np.all(gh_weights > 0) assert stick_propn_mean.shape == stick_propn_info.shape assert np.all(stick_propn_info) > 0 e_log_v, e_log_1mv =\ ef.get_e_log_logitnormal( lognorm_means = stick_propn_mean, lognorm_infos = stick_propn_info, gh_loc = gh_loc, gh_weights = gh_weights) return np.sum(ef.univariate_normal_entropy(stick_propn_info)) + \ np.sum(e_log_v + e_log_1mv)
def get_e_logitnorm_dp_prior(stick_propn_mean, stick_propn_info, alpha, gh_loc, gh_weights): # expected log prior for the stick breaking proportions under the # logitnormal variational distribution # integration is done numerical with Gauss Hermite quadrature. # gh_loc and gh_weights specifiy the location and weights of the # quadrature points assert np.all(gh_weights > 0) assert stick_propn_mean.shape == stick_propn_info.shape assert np.all(stick_propn_info) > 0 e_log_v, e_log_1mv = \ ef.get_e_log_logitnormal( lognorm_means = stick_propn_mean, lognorm_infos = stick_propn_info, gh_loc = gh_loc, gh_weights = gh_weights) return (alpha - 1) * np.sum(e_log_1mv)
def get_e_log_cluster_probabilities(stick_propn_mean, stick_propn_info, gh_loc, gh_weights): # the expected log mixture weights # stick_propn_mean is of shape ... x k_approx assert np.all(gh_weights > 0) assert stick_propn_mean.shape == stick_propn_info.shape if len(stick_propn_mean.shape) == 1: stick_propn_mean = stick_propn_mean[None, :] stick_propn_info = stick_propn_info[None, :] assert np.all(stick_propn_info) > 0 e_log_v, e_log_1mv = \ ef.get_e_log_logitnormal( lognorm_means = stick_propn_mean, lognorm_infos = stick_propn_info, gh_loc = gh_loc, gh_weights = gh_weights) return get_e_log_cluster_probabilities_from_e_log_stick(e_log_v, e_log_1mv)
def e_log_v(x): return np.sum(ef.get_e_log_logitnormal(\ x[0:5], np.abs(x[5:10]), gh_loc, gh_weights)[0])