Beispiel #1
0
def pf_observe(data_point, particle, prior, **kwargs):
    """
    Evaluate P(output | particle) (i.e. P(obs | S)).
    Returns:
      - weight for this data point given its particle.
    """
    out_prior_counts = \
      prior.ssm.out_trans_mat_hyperparams[particle.switch_state, :]
    prev_output = kwargs["prev_output"]
    if prev_output is None:
        out_trans_counts = np.zeros(prior.ssm.num_outputs)
        # weigh by the prior
        out_dist = distributions.DirMultinomial(out_trans_counts, out_prior_counts)
    else:
        out_trans_counts = \
          particle.out_trans_counts[particle.switch_state, prev_output, :]
        # weigh the particle by its probability
        out_dist = distributions.DirMultinomial(out_trans_counts, out_prior_counts)
        # update the particle counts
        particle.out_trans_counts[particle.switch_state,
                                  kwargs["prev_output"],
                                  data_point] += 1
    # calculate weight
    weight = out_dist.posterior_pred_pmf(data_point)
    return weight
 def predict_output(self, num_preds, prev_output):
     """
     Predict output for number of given time steps, given
     previous output (if any).
     """
     output_probs = np.zeros((num_preds, self.num_outputs))
     out_trans_mat_hyperparams = self.prior.ssm.out_trans_mat_hyperparams
     # resample particles before making predictions
     #self.resample()
     # record previous outputs for each particle
     particle_prev_outputs = np.ones(self.num_particles)
     if prev_output is not None:
         # at first time step, the previous output is determined by
         # the data, assuming we had observed any data
         particle_prev_outputs *= prev_output
     else:
         # special case where there's no previous output
         # in this case, draw outputs from initial set of
         # particles. draw as many samples from prior as there
         # are particles
         for n in xrange(self.num_particles):
             prev_counts = np.zeros(self.num_outputs)
             init_out_hyperparams = self.prior.ssm.init_out_hyperparams
             pred_dist = \
               distributions.DirMultinomial(prev_counts, init_out_hyperparams)
             sampled_output = pred_dist.sample_posterior_pred()
             particle_prev_outputs[n] = sampled_output
     for n in xrange(num_preds):
         # first predict transition of particles to new switch state
         new_particles = []
         for prev_particle in self.particles:
             particle = switch_ssm.pf_trans_sample(prev_particle,
                                                   self.prior)
             new_particles.append(particle)
         self.particles = new_particles
         # then sample an output from each particle and then
         # reweight it by the evidence
         for p in xrange(self.num_particles):
             prev_output = particle_prev_outputs[p]
             curr_particle = self.particles[p]
             switch_state = curr_particle.switch_state
             pred_dist = \
               distributions.DirMultinomial(curr_particle.out_trans_counts[switch_state,
                                                                           prev_output, :],
                                            out_trans_mat_hyperparams[prev_output, :])
             sampled_output = pred_dist.sample_posterior_pred()
             self.weights[p] *= switch_ssm.pf_observe(
                 sampled_output,
                 curr_particle,
                 self.prior,
                 prev_output=prev_output)
             output_probs[n, sampled_output] += self.weights[p]
             # update previous output
             particle_prev_outputs[p] = sampled_output
         output_probs[n, :] /= self.weights.sum()
         # resample outputs
         self.resample()
     return output_probs
 def predict_output(self, num_preds):
     """
     Predict output given current set of particles.
     """
     possible_outputs = np.arange(self.num_outputs)
     output_probs = np.zeros((num_preds, self.num_outputs))
     out_mat_hyperparams = self.prior.hmm.out_mat_hyperparams
     # resample particles before making predictions
     self.resample()
     for n in xrange(num_preds):
         # first predict transition of particles to new hidden
         # state
         new_particles = []
         for prev_particle in self.particles:
             particle = bayes_hmm.pf_trans_sample(prev_particle, self.prior)
             new_particles.append(particle)
         self.particles = new_particles
         # then sample an output from each particle and then
         # reweight it by the evidence
         for p in xrange(self.num_particles):
             curr_particle = self.particles[p]
             hidden_state = curr_particle.hidden_state
             pred_dist = \
               distributions.DirMultinomial(curr_particle.output_counts[hidden_state, :],
                                            out_mat_hyperparams[hidden_state, :])
             sampled_output = pred_dist.sample_posterior_pred()
             self.weights[p] *= bayes_hmm.pf_observe(
                 sampled_output, curr_particle, self.prior)
             output_probs[n, sampled_output] += self.weights[p]
         output_probs[n, :] /= self.weights.sum()
         # resample particles
         self.resample()
     return output_probs
Beispiel #4
0
def pf_trans_sample(prev_particle, prior):
    """
    Sample transition to new particle given previous particle.
    """
    # sample transition to new particle using posterior predictive
    # dirichlet distribution
    new_particle = copy.deepcopy(prev_particle)
    # get the relevant counts for the switch state
    if prev_particle.switch_state is None:
        # if the switch state isn't given, then we're in the first
        # time point and the state is drawn from the prior
        init_switch_probs = np.random.dirichlet(prior.ssm.init_switch_hyperparams)
        new_particle.switch_state = \
          np.random.multinomial(1, init_switch_probs).argmax()
    else:
        prev_counts = \
          prev_particle.switch_trans_counts[prev_particle.switch_state, :]
        # prior counts for the each of the possible switch state
        # given the previous switch state
        switch_state_prior_counts = \
          prior.ssm.switch_trans_mat_hyperparams[prev_particle.switch_state, :]
        log_scores = np.log(prev_counts + switch_state_prior_counts)
        if (log_scores == -np.inf).any():
            print "WARNING: transition probability to new particle contained -inf"
        # sample new switch state
        next_state_dist = distributions.DirMultinomial(prev_counts,
                                                       switch_state_prior_counts)
        new_particle.switch_state = next_state_dist.sample_posterior_pred()
        # update the particle's state transition count
        new_particle.switch_trans_counts[prev_particle.switch_state,
                                         new_particle.switch_state] += 1
    return new_particle
Beispiel #5
0
def pf_trans_sample(prev_particle, prior):
    """
    Sample transition to new particle given previous particle.
    """
    # sample transition to new particle using posterior predictive
    # dirichlet distribution
    new_particle = copy.deepcopy(prev_particle)
    # get the relevant counts (i.e. counts conditioned on the previous state)
    prev_counts = \
      prev_particle.hidden_trans_counts[prev_particle.hidden_state, :]
    # prior counts for the each of the possible hidden states
    # given the previous hidden state
    hidden_state_prior_counts = \
      prior.hmm.trans_mat_hyperparams[prev_particle.hidden_state, :]
    log_scores = np.log(prev_counts + hidden_state_prior_counts)
    if (log_scores == -np.inf).any():
        print "WARNING: transition probability to new particle contained -inf"
    # sample new hidden state
    next_state_dist = distributions.DirMultinomial(prev_counts,
                                                   hidden_state_prior_counts)
    new_particle.hidden_state = next_state_dist.sample_posterior_pred()
    # update the particle's state transition count
    new_particle.hidden_trans_counts[prev_particle.hidden_state,
                                     new_particle.hidden_state] += 1
    return new_particle
Beispiel #6
0
def pf_observe(data_point, particle, prior):
    """
    Evaluate P(output | particle) (i.e. P(obs | S)).
    Returns:
      - weight for this data point given its particle.
    """
    out_prior_counts = prior.hmm.out_mat_hyperparams[particle.hidden_state, :]
    # weigh the particle by its probability
    out_dist = \
      distributions.DirMultinomial(particle.output_counts[particle.hidden_state, :],
                                   out_prior_counts)
    weight = out_dist.posterior_pred_pmf(data_point)
    # update the particle counts
    particle.output_counts[particle.hidden_state, data_point] += 1
    return weight
Beispiel #7
0
 def test_dir_multinomial(self):
     """
     Test Dirichlet-Multinomial distribution.
     """
     p = np.array([0.2, 0.1, 0.7])
     N = 10000
     # sample random counts
     counts = np.random.multinomial(N, p)
     state_ind = 1
     # get empirical estimate of posterior predictive distribution
     # of the state
     num_iters = 100000
     num_occurs_ind = 0
     num_occurs = np.zeros(len(p))
     for n in xrange(num_iters):
         num_occurs += np.random.multinomial(1, p)
     # empirical estimate of posterior predictive
     emp_posterior_pred = num_occurs / float(num_iters)
     for state_ind in xrange(len(p)):
         print "--"
         print "Empirical estimate of posterior predictive distribution"
         print "P(X = %d | %s): %.4f" % (state_ind,
                                         np.array_str(p, precision=4),
                                         emp_posterior_pred[state_ind])
         print "Analytic calculation of posterior predictive distribution"
         alpha = np.ones(len(p))
         dir_mult = distributions.DirMultinomial(counts, alpha)
         logp = dir_mult.log_posterior_pred_pmf(state_ind)
         print "P(X = %d | %s): %.4f" % (
             state_ind, np.array_str(counts, precision=4), np.exp(logp))
         # since we're using non-zero alpha values, it shouldn't be
         # an exact match
         abs_error = 0.02
         assert (np.allclose(emp_posterior_pred[state_ind],
                             np.exp(logp), atol=abs_error)), \
                "Empirical and analytic calculation don't match."