Beispiel #1
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
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
Beispiel #8
0
    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
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
    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
Beispiel #13
0
    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