Exemplo n.º 1
0
def log_partition_function(natural_params, data):
    if isinstance(data, list):
        return sum(map(partial(log_partition_function, natural_params), data))

    log_pi, log_A, log_B = natural_params

    log_alpha = log_pi
    for y in data:
        log_alpha = logsumexp(log_alpha[:,None] + log_A, axis=0) + log_B[:,y]

    return logsumexp(log_alpha)
Exemplo n.º 2
0
    def entropy(self, sample=None):
        """
        Compute the entropy of the variational posterior distirbution.

        Recall that under the structured mean field approximation

        H[q(z)q(x)] = -E_{q(z)q(x)}[log q(z) + log q(x)]
                    = -E_q(z)[log q(z)] - E_q(x)[log q(x)]
                    = H[q(z)] + H[q(x)].

        That is, the entropy separates into the sum of entropies for the
        discrete and continuous states.

        For each one, we have

        E_q(u)[log q(u)] = E_q(u) [log q(u_1) + sum_t log q(u_t | u_{t-1}) + loq q(u_t) - log Z]
                         = E_q(u_1)[log q(u_1)] + sum_t E_{q(u_t, u_{t-1}[log q(u_t | u_{t-1})]
                             + E_q(u_t)[loq q(u_t)] - log Z

        where u \in {z, x} and log Z is the log normalizer.  This shows that we just need the
        posterior expectations and potentials, and the log normalizer of the distribution.

        Note
        ----
        We haven't implemented the exact calculations for the continuous states yet,
        so for now we're approximating the continuous state entropy via samples.
        """

        # Sample the continuous states
        if sample is None:
            sample = self.sample_continuous_states()
        else:
            assert isinstance(sample, list) and len(sample) == len(self.datas)

        negentropy = 0
        for s, prms in zip(sample, self.params):

            # 1. Compute log q(x) of samples of x
            negentropy += block_tridiagonal_log_probability(
                s, prms["J_diag"], prms["J_lower_diag"], prms["h"])

            # 2. Compute E_{q(z)}[ log q(z) ]
            log_pi0 = np.log(prms["pi0"] + 1e-16) - logsumexp(prms["pi0"])
            log_Ps = np.log(prms["Ps"] + 1e-16) - logsumexp(
                prms["Ps"], axis=1, keepdims=True)
            (Ez, Ezzp1,
             normalizer) = hmm_expected_states(prms["pi0"], prms["Ps"],
                                               prms["log_likes"])
            negentropy -= normalizer  # -log Z
            negentropy += np.sum(Ez[0] * log_pi0)  # initial factor
            negentropy += np.sum(Ez * prms["log_likes"])  # unitary factors
            negentropy += np.sum(Ezzp1 * log_Ps)  # pairwise factors

        return -negentropy
Exemplo n.º 3
0
    def _discrete_entropy(self):
        negentropy = 0
        discrete_expectations = self.discrete_expectations
        for prms, (Ez, Ezzp1, normalizer) in \
                zip(self.discrete_state_params, discrete_expectations):

            log_pi0 = np.log(prms["pi0"] + 1e-16) - logsumexp(prms["pi0"])
            log_Ps = np.log(prms["Ps"] + 1e-16) - logsumexp(prms["Ps"], axis=1, keepdims=True)
            negentropy -= normalizer  # -log Z
            negentropy += np.sum(Ez[0] * log_pi0)  # initial factor
            negentropy += np.sum(Ez * prms["log_likes"])  # unitary factors
            negentropy += np.sum(Ezzp1 * log_Ps)  # pairwise factors
        return -negentropy
Exemplo n.º 4
0
def _make_grad_hmm_normalizer(argnum, ans, pi0, Ps, ll):
    # Make sure everything is C contiguous and unboxed
    pi0 = to_c(pi0)
    Ps = to_c(Ps)
    ll = to_c(ll)

    dlog_pi0 = np.zeros_like(pi0)
    dlog_Ps = np.zeros_like(Ps)
    dll = np.zeros_like(ll)
    T, K = ll.shape

    # Forward pass to get alphas
    alphas = np.zeros((T, K))
    forward_pass(pi0, Ps, ll, alphas)
    log_Ps = np.log(Ps + LOG_EPS) - logsumexp(Ps, axis=1, keepdims=True)
    grad_hmm_normalizer(log_Ps, alphas, dlog_pi0, dlog_Ps, dll)

    # Compute necessary gradient
    # Account for the log transformation
    # df/dP = df/dlogP * dlogP/dP = df/dlogP * 1 / P
    if argnum == 0:
        return lambda g: g * dlog_pi0 / (pi0 + DIV_EPS)
    if argnum == 1:
        return lambda g: g * dlog_Ps / (Ps + DIV_EPS)
    if argnum == 2:
        return lambda g: g * dll
Exemplo n.º 5
0
    def log_transition_matrices(self, data, input, mask, tag):
        T, D = data.shape
        # Previous state effect
        log_Ps = np.tile(self.log_Ps[None, :, :], (T - 1, 1, 1))
        # Input effect
        log_Ps = log_Ps + np.dot(input[1:], self.Ws.T)[:, None, :]

        # Past observations effect

        #Off diagonal elements of transition matrix (state switches), from past observations
        log_Ps_offdiag = np.tile(
            np.dot(data[:-1], self.Rs.T)[:, None, :], (1, self.K, 1))
        mult_offdiag = 1 - np.tile(
            np.identity(self.K)[None, :, :], (log_Ps_offdiag.shape[0], 1, 1))

        #Diagonal elements of transition matrix (stickiness), from past observations
        log_Ps_diag = np.tile(
            np.dot(data[:-1], self.Ss.T)[:, None, :], (1, self.K, 1))
        mult_diag = np.tile(
            np.identity(self.K)[None, :, :], (log_Ps_diag.shape[0], 1, 1))

        log_Ps = log_Ps_diag * mult_diag  #Diagonal elements (stickness) from past observations
        log_Ps = log_Ps + np.identity(
            self.K) * self.s  #Diagonal elements (stickness) bias
        log_Ps = log_Ps + log_Ps_offdiag * mult_offdiag  #Off diagonal elements (state switching) from past observations
        log_Ps = log_Ps + (1 - np.identity(
            self.K)) * self.r  #Off diagonal elements (state switching) bias

        return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)  #Normalize
Exemplo n.º 6
0
def nll_GLM_GanmorCalciumAR1(w, X, Y, hyperparams, nlfun, S=10):
    """
    Negative log-likelihood for a GLM with Ganmor AR1 mixture model for calcium imaging data.

    Input:
        w:              [D x 1]  vector of GLM regression weights
        X:              [T x D]  design matrix
        Y:              [T x 1]  calcium fluorescence observations
        hyperparams:    [3 x 1]  model hyperparameters: log tau, log alpha, log Gaussian variance
        nlfun:          [func]   function handle for nonlinearity
        S:              [scalar] number of spikes to marginalize
        return_hess:    [bool]   flag for returning Hessian

    Output:
        negative log-likelihood, gradient, and Hessian
    """

    # unpack hyperparams
    tau, alpha, sig2 = hyperparams

    # compute AR(1) diffs
    taudecay = np.exp(-1.0 / tau)  # decay factor for one time bin
    Y = np.pad(Y, (1, 0))  # pad Y by a time bin
    Ydff = (Y[1:] - taudecay * Y[:-1]) / alpha

    # compute grid of spike counts
    ygrid = np.arange(0, S + 1)

    # Gaussian log-likelihood terms
    log_gauss_grid = -0.5 * (Ydff[:, None] - ygrid[None, :])**2 / (
        sig2 / alpha**2) - 0.5 * np.log(2.0 * np.pi * sig2)

    Xproj = X @ w
    poissConst = gammaln(ygrid + 1)

    # compute neglogli, gradient, and (optionally) Hessian
    f, logf, df, ddf = nlfun(Xproj)
    logPcounts = logf[:, None] * ygrid[None, :] - f[:,
                                                    None] - poissConst[None, :]

    # compute log-likelihood for each time bin
    logjoint = log_gauss_grid + logPcounts
    logli = logsumexp(logjoint, axis=1)  # log likelihood for each time bin
    negL = -np.sum(logli)  # negative log likelihood

    # gradient
    dLpoiss = (df / f)[:, None] * ygrid[
        None, :] - df[:, None]  # deriv of Poisson log likelihood
    gwts = np.sum(np.exp(logjoint - logli[:, None]) * dLpoiss,
                  axis=1)  # gradient weights
    gradient = -X.T @ gwts

    # Hessian
    ddLpoiss = (ddf / f - (df / f)**2)[:, None] * ygrid[None, :] - ddf[:, None]
    ddL = (ddLpoiss + dLpoiss**2)
    hwts = np.sum(np.exp(logjoint - logli[:, None]) * ddL,
                  axis=1) - gwts**2  # hessian weights
    H = -X.T @ (X * hwts[:, None])

    return negL, gradient, H
Exemplo n.º 7
0
    def backward(self, loglikhds, cython=True):
        loginit, logtrans, logobs = loglikhds

        beta = []
        for _logobs, _logtrans in zip(logobs, logtrans):
            T = _logobs.shape[0]
            _beta = np.zeros((T, self.nb_states))

            if cython:
                backward_cy(to_c(loginit), to_c(_logtrans), to_c(_logobs),
                            to_c(_beta))
            else:
                for k in range(self.nb_states):
                    _beta[T - 1, k] = 0.0

                _aux = np.zeros((self.nb_states, ))
                for t in range(T - 2, -1, -1):
                    for k in range(self.nb_states):
                        for j in range(self.nb_states):
                            _aux[j] = _logtrans[t, k, j] + _beta[
                                t + 1, j] + _logobs[t + 1, j]
                        _beta[t, k] = logsumexp(_aux)

            beta.append(_beta)
        return beta
Exemplo n.º 8
0
 def log_transition(self, x, u):
     logtrans = []
     for _x, _u in zip(x, u):
         T = np.maximum(len(_x) - 1, 1)
         _logtrans = np.tile(self.logmat[None, :, :], (T, 1, 1))
         logtrans.append(_logtrans - logsumexp(_logtrans, axis=-1, keepdims=True))
     return logtrans
Exemplo n.º 9
0
 def log_transition_matrices(self, data, input, mask, tag):
     T, D = data.shape
     log_Ps = np.dot(input[1:], self.Ws.T)[:, None, :]              # inputs
     log_Ps = log_Ps + np.dot(data[:-1], self.Rs.T)[:, None, :]     # past observations
     log_Ps = log_Ps + self.r                                       # bias
     log_Ps = np.tile(log_Ps, (1, self.K, 1))                       # expand
     return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)       # normalize
Exemplo n.º 10
0
def accelerate_D(doftotal, ctrl):
    ''' ctrl: ctrl's frequency calculation
    '''
    if r.topt == 1 and r.Popt == 0:
        pthick = [
            r.tmin / lam0 + (thick[i] - r.tmin / lam0) * doftotal[i]
            for i in range(Nlayer)
        ]
        pscale = 1.
        dofold = doftotal[Nlayer:]
    elif r.topt == 0 and r.Popt == 1:
        pthick = thick
        pscale = 1. + (r.Periodmax - r.Period) / r.Period * doftotal[0]
        dofold = doftotal[1:]
    elif r.topt == 1 and r.Popt == 1:
        pscale = 1. + (r.Periodmax - r.Period) / r.Period * doftotal[0]
        pthick = [
            r.tmin / lam0 + (thick[i] - r.tmin / lam0) * doftotal[1 + i]
            for i in range(Nlayer)
        ]
        dofold = doftotal[Nlayer + 1:]
    else:
        pscale = 1.
        pthick = thick
        dofold = doftotal

    # RCWA
    freqcmp = freq_list[ctrl] * (1 + 1j / 2 / Qref)
    planewave = {'p_amp': 0, 's_amp': 1, 'p_phase': 0, 's_phase': 0}
    phi = 0.
    theta = r.angle
    obj, dof, epsdiff = rcwa_assembly(dofold, freqcmp, theta, phi, planewave,
                                      pthick, pscale)
    R, _ = obj.RT_Solve(normalize=1)

    if r.polarization == 'ps' or r.polarization == 'sp':
        planewave = {'p_amp': 1, 's_amp': 0, 'p_phase': 0, 's_phase': 0}
        obj.MakeExcitationPlanewave(planewave['p_amp'],
                                    planewave['p_phase'],
                                    planewave['s_amp'],
                                    planewave['s_phase'],
                                    order=0)
        R2, _ = obj.RT_Solve(normalize=1)

        # the minimal of reflection
        Inc = 500.
        R = Inc / logsumexp(Inc / np.array([R, R2]))

    # mass
    rho = mload
    for i in range(Nlayer):
        mtmp = lam0 * pthick[i] * mstruct[i].density * np.mean(
            dof[i * Nx * Ny:(i + 1) * Nx * Ny])
        rho = rho + mtmp
    rho = rho**r.mpower

    integrand = rho / R * gamma[ctrl] * beta[ctrl] / (1 - beta[ctrl])**2
    integrand = cons.c**3 / 2 / laserP * integrand * dbeta / 1e9

    return integrand
Exemplo n.º 11
0
 def filter(self, obs, act=None):
     logliklhds = self.log_likelihoods(obs, act)
     alpha = self.forward(logliklhds)
     belief = [
         np.exp(_alpha - logsumexp(_alpha, axis=1, keepdims=True))
         for _alpha in alpha
     ]
     return belief
Exemplo n.º 12
0
 def mixture_log_density(var_mixture_params, x):
     """Returns a weighted average over component densities."""
     log_weights, var_params = unpack_mixture_params(var_mixture_params)
     component_log_densities = np.vstack(
         [component_log_density(params_k, x) for params_k in var_params]).T
     return logsumexp(component_log_densities + log_weights,
                      axis=1,
                      keepdims=False)
Exemplo n.º 13
0
 def log_transition(self, x, u):
     logtrans = []
     for _x, _u in zip(x, u):
         T = np.maximum(len(_x) - 1, 1)
         _in = np.hstack((_x[:T, :], _u[:T, :self.dm_act]))
         _logtrans = to_npy(self.rnr.forward(to_torch(_in)))
         logtrans.append(_logtrans - logsumexp(_logtrans, axis=-1, keepdims=True))
     return logtrans
Exemplo n.º 14
0
 def log_transition_matrices(self, data, input, mask, tag):
     T = data.shape[0]
     assert input.shape[0] == T
     # Previous state effect
     log_Ps = np.tile(self.log_Ps[None, :, :], (T-1, 1, 1))
     # Input effect
     log_Ps = log_Ps + np.dot(input[1:], self.Ws.T)[:, None, :]
     return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)
Exemplo n.º 15
0
 def transition_matrix(self, data, input, mask, tag):
     # For a single data point: data is x_{t-1}, input is x_t
     log_Ps = self.log_Ps[None, :, :]
     # Input effect
     log_Ps = log_Ps + np.dot(input, self.Ws.T)[:, None, :]
     # Past observations effect
     log_Ps = log_Ps + np.dot(data, self.Rs.T)[:, None, :]
     return np.exp(log_Ps - logsumexp(log_Ps, axis=2, keepdims=True))
def neural_net_predict(params, inputs):
    """Implements a deep neural network for classification.
       params is a list of (weights, bias) tuples.
       inputs is an (N x D) matrix.
       returns normalized class log-probabilities."""
    for W, b in params:
        outputs = np.dot(inputs, W) + b
        inputs = np.tanh(outputs)
    return outputs - logsumexp(outputs, axis=1, keepdims=True)
Exemplo n.º 17
0
    def _lowerbound(self, x, K=1):
        """
        Compute the lowerbound
        """
        # define network

        W1, W2, W3, W4, W5 = self.params["W1"], self.params["W2"], self.params["W3"],\
        self.params["W4"], self.params["W5"]
        b1, b2, b3, b4, b5 = self.params["b1"], self.params["b2"], self.params["b3"],\
        self.params["b4"], self.params["b5"]

        if self.continuous:
            W6, b6 = self.params["W6"], self.params["b6"]
            activation = lambda x: np.log(1 + np.exp(x))
        else:
            activation = lambda x: np.tanh(x, x)

        sigmoid = lambda x: 1. / (1 + np.exp(-x))

        # IWAE: first replicate the input
        N = x.shape[1]
        #x = np.repeat(x, K, axis = 1)
        #x = np.tile(x.reshape(-1, 1), (1, K)).reshape(x.shape[0], K * N)
        x = np.tile(x, (1, K))

        # compute forward pass
        h_encoder = activation(W1.dot(x) + b1)

        mu_encoder = W2.dot(h_encoder) + b2
        log_sigma_encoder = 0.5 * (W3.dot(h_encoder) + b3)

        eps = np.random.randn(self.n_hidden_variables, x.shape[1])
        z = mu_encoder + np.exp(log_sigma_encoder) * eps

        h_decoder = activation(W4.dot(z) + b4)

        y = sigmoid(W5.dot(h_decoder) + b5)

        if self.continuous:
            log_sigma_decoder = 0.5 * (W6.dot(h_decoder) + b6)
            logpxz = np.sum(-(0.5 * np.log(2 * np.pi) + log_sigma_decoder) -
                            0.5 * ((x - y) / np.exp(log_sigma_decoder))**2,
                            axis=0)
        else:
            logpxz = np.sum(x * np.log(y) + (1 - x) * np.log(1 - y), axis=0)

        KLD = 0.5 * np.sum(1 + 2 * log_sigma_encoder - mu_encoder**2 -
                           np.exp(2 * log_sigma_encoder),
                           axis=0)
        lowerbound_x = logpxz + KLD

        # then compute the weights
        log_ws_matrix = lowerbound_x.reshape(K, N)
        # now compute the IWAE bound
        lowerbound = np.sum(logsumexp(log_ws_matrix, axis=0) - np.log(K))

        return lowerbound
Exemplo n.º 18
0
    def log_prior(self):
        K = self.K
        log_P = self.log_Ps - logsumexp(self.log_Ps, axis=1, keepdims=True)

        lp = 0
        for k in range(K):
            alpha = self.alpha * np.ones(K) + self.kappa * (np.arange(K) == k)
            lp += np.dot((alpha - 1), log_P[k])
        return lp
Exemplo n.º 19
0
def forward_pass_np(log_pi0, log_Ps, log_likes):
    T, K = log_likes.shape
    alphas = []
    alphas.append(log_likes[0] + log_pi0)
    for t in range(T-1):
        anext = logsumexp(alphas[t] + log_Ps[t].T, axis=1)
        anext += log_likes[t+1]
        alphas.append(anext)
    return np.array(alphas)
Exemplo n.º 20
0
 def log_transition_matrices(self, data, input, mask, tag):
     T, D = data.shape
     # Previous state effect
     log_Ps = np.tile(self.log_Ps[None, :, :], (T-1, 1, 1))
     # Input effect
     log_Ps = log_Ps + np.dot(input[1:], self.Ws.T)[:, None, :]
     # Past observations effect
     log_Ps = log_Ps + np.dot(data[:-1], self.Rs.T)[:, None, :]
     return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)
Exemplo n.º 21
0
    def m_step(self, expectations, datas, inputs, masks, tags, **kwargs):
        K = self.K
        P = sum([np.sum(Ezzp1, axis=0) for _, Ezzp1, _ in expectations]) + 1e-32
        P = np.nan_to_num(P / P.sum(axis=-1, keepdims=True))

        # Set rows that are all zero to uniform
        P = np.where(P.sum(axis=-1, keepdims=True) == 0, 1.0 / K, P)
        log_P = np.log(P)
        self.log_Ps = log_P - logsumexp(log_P, axis=-1, keepdims=True)
Exemplo n.º 22
0
    def log_prior(self):
        K = self.K
        Ps = np.exp(self.log_Ps - logsumexp(self.log_Ps, axis=1, keepdims=True))

        lp = 0
        for k in range(K):
            alpha = self.alpha * np.ones(K) + self.kappa * (np.arange(K) == k)
            lp += dirichlet.logpdf(Ps[k], alpha)
        return lp
Exemplo n.º 23
0
 def get_error_and_ll(w, v_prior, X, y, K, location, scale):
     v_noise = np.exp(parser.get(w, 'log_v_noise')[0, 0]) * scale**2
     q = get_parameters_q(w, v_prior)
     samples_q = draw_samples(q, K)
     outputs = predict(samples_q, X) * scale + location
     log_factor = -0.5 * np.log(2 * math.pi * v_noise) - 0.5 * (
         np.tile(y, (1, K)) - np.array(outputs))**2 / v_noise
     ll = np.mean(logsumexp(log_factor - np.log(K), 1))
     error = np.sqrt(np.mean((y - np.mean(outputs, 1, keepdims=True))**2))
     return error, ll
Exemplo n.º 24
0
def hmm_expected_states(log_pi0, log_Ps, ll, memlimit=2**31):
    T, K = ll.shape

    # Make sure everything is C contiguous
    log_pi0 = to_c(log_pi0)
    log_Ps = to_c(log_Ps)
    ll = to_c(ll)

    alphas = np.zeros((T, K))
    forward_pass(log_pi0, log_Ps, ll, alphas)
    normalizer = logsumexp(alphas[-1])

    betas = np.zeros((T, K))
    backward_pass(log_Ps, ll, betas)

    # Compute E[z_t] for t = 1, ..., T
    expected_states = alphas + betas
    expected_states -= logsumexp(expected_states, axis=1, keepdims=True)
    expected_states = np.exp(expected_states)

    # Compute E[z_t, z_{t+1}] for t = 1, ..., T-1
    # Note that this is an array of size T*K*K, which can be quite large.
    # To be a bit more frugal with memory, first check if the given log_Ps
    # are TxKxK.  If so, instantiate the full expected joints as well, since
    # we will need them for the M-step.  However, if log_Ps is 1xKxK then we
    # know that the transition matrix is stationary, and all we need for the
    # M-step is the sum of the expected joints.
    stationary = (log_Ps.shape[0] == 1)
    if not stationary:
        expected_joints = alphas[:-1, :, None] + betas[1:, None, :] + ll[
            1:, None, :] + log_Ps
        expected_joints -= expected_joints.max((1, 2))[:, None, None]
        expected_joints = np.exp(expected_joints)
        expected_joints /= expected_joints.sum((1, 2))[:, None, None]

    else:
        # Compute the sum over time axis of the expected joints
        expected_joints = np.zeros((K, K))
        compute_stationary_expected_joints(alphas, betas, ll, log_Ps[0],
                                           expected_joints)
        expected_joints = expected_joints[None, :, :]

    return expected_states, expected_joints, normalizer
Exemplo n.º 25
0
def IWELBO(params, log_p, log_q, sample_q, M_iw_train, num_copies_training):

    _, lp, lq, _ = objective_utils(params, log_p, log_q, sample_q, M_iw_train,
                                   num_copies_training)
    # This will also work, but will not evaluate to IW-ELBO
    # lR = lp - lq
    # weights = autograd.core.getval(utils.softmax_matrix(lR))
    # targets = lR
    # return np.mean(np.sum(weights*targets, -1))
    return np.mean(autoscipy.logsumexp(lp - lq, -1)) - np.log(M_iw_train)
Exemplo n.º 26
0
def hmm_normalizer(pi0, Ps, ll):
    T, K = ll.shape
    alphas = np.zeros((T, K))

    # Make sure everything is C contiguous
    pi0 = to_c(pi0)
    Ps = to_c(Ps)
    ll = to_c(ll)

    forward_pass(pi0, Ps, ll, alphas)
    return logsumexp(alphas[-1])
Exemplo n.º 27
0
    def log_transition_matrices(self, data, input, mask, tag):
        # Pass the data and inputs through the neural network
        x = np.hstack((data[:-1], input[1:]))
        for W, b in zip(self.weights, self.biases):
            y = np.dot(x, W) + b
            x = self.nonlinearity(y)

        # Add the baseline transition biases
        log_Ps = self.log_Ps[None, :, :] + y[:, None, :]

        # Normalize
        return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)
Exemplo n.º 28
0
def nll_GLM_GanmorCalciumAR1(w, X, Y, hyperparams, nlfun, S=10):
    """
    Negative log-likelihood for a GLM with Ganmor AR1 mixture model for calcium imaging data.

    Input:
        w:              [D x 1]  vector of GLM regression weights
        X:              [T x D]  design matrix
        Y:              [T x 1]  calcium fluorescence observations
        hyperparams:    [3 x 1]  model hyperparameters: log tau, log alpha, log Gaussian variance
        nlfun:          [func]   function handle for nonlinearity
        S:              [scalar] number of spikes to marginalize
        return_hess:    [bool]   flag for returning Hessian

    Output:
        negative log-likelihood, gradient, and Hessian
    """
    # unpack hyperparams
    ar_coefs, log_alpha, log_sig2 = hyperparams
    alpha = np.exp(log_alpha)
    sig2 = np.exp(log_sig2)
    p = ar_coefs.shape[0]  # AR(p)
    # compute AR(p) diffs
    Ydecay = np.zeros_like(Y)
    Y = np.pad(Y, (p, 0))  # pad Y by p time bins
    for i, ai in enumerate(ar_coefs):
        Ydecay = Ydecay + ai * Y[p - 1 - i:-1 - i]
    # Ydecay2 = ar_coefs[0] * Y[1:-1]
    # Ydecay2 = Ydecay2 + ar_coefs[1] * Y[:-2]
    # print(np.linalg.norm(Ydecay - Ydecay2))
    # import ipdb; ipdb.set_trace()
    Ydff = (Y[p:] - Ydecay) / alpha

    # compute grid of spike counts
    ygrid = np.arange(0, S + 1)

    # Gaussian log-likelihood terms
    log_gauss_grid = -0.5 * (Ydff[:, None] - ygrid[None, :])**2 / (
        sig2 / alpha**2) - 0.5 * np.log(2.0 * np.pi * sig2)

    Xproj = X @ w
    poissConst = gammaln(ygrid + 1)

    # compute neglogli, gradient, and (optionally) Hessian
    f, logf, df, ddf = nlfun(Xproj)
    logPcounts = logf[:, None] * ygrid[None, :] - f[:,
                                                    None] - poissConst[None, :]

    # compute log-likelihood for each time bin
    logjoint = log_gauss_grid + logPcounts
    logli = logsumexp(logjoint, axis=1)  # log likelihood for each time bin
    negL = -np.sum(logli)  # negative log likelihood

    return negL
Exemplo n.º 29
0
    def log_transition_matrices(self, data, input, mask, tag):
        def bound_func(t, a, ap, lamb, k):
            return a - (1 - np.exp(-(t / lamb)**k)) * (0.0 * a + np.exp(ap))

        T, D = data.shape
        # Previous state effect
        log_Ps = np.tile(self.log_Ps[None, :, :], (T - 1, 1, 1))
        # Input effect
        boundary_input = 1. - bound_func(input[1:], 1.0, self.ap, self.lamb, 2)
        log_Ps = log_Ps + np.dot(boundary_input, self.Ws.T)[:, None, :]
        # Past observations effect
        log_Ps = log_Ps + np.dot(data[:-1], self.Rs.T)[:, None, :]
        return log_Ps - logsumexp(log_Ps, axis=2, keepdims=True)
Exemplo n.º 30
0
def hmm_filter(log_pi0, log_Ps, ll):
    T, K = ll.shape

    # Make sure everything is C contiguous
    log_pi0 = to_c(log_pi0)
    log_Ps = to_c(log_Ps)
    ll = to_c(ll)

    # Forward pass gets the predicted state at time t given
    # observations up to and including those from time t
    alphas = np.zeros((T, K))
    forward_pass(log_pi0, log_Ps, ll, alphas)

    # Predict forward with the transition matrix
    pz_tt = np.exp(alphas - logsumexp(alphas, axis=1, keepdims=True))
    pz_tp1t = np.matmul(pz_tt[:-1, None, :], np.exp(log_Ps))[:, 0, :]

    # Include the initial state distribution
    pz_tp1t = np.row_stack((np.exp(log_pi0 - logsumexp(log_pi0)), pz_tp1t))

    assert np.allclose(np.sum(pz_tp1t, axis=1), 1.0)
    return pz_tp1t