Skip to content

Incorrect HiddenMarkovModel log_prob #958

@EWeinstein

Description

@EWeinstein

There appears to be an error in the HiddenMarkovModel distribution log_prob implementation. The probability of the first hidden state in the sequence is computed as matmul(initial_distribution, transition_distribution) rather than as initial_distribution.

Code to reproduce problem:

import tensorflow.compat.v2 as tf
import tensorflow_probability as tfp
import numpy as np

x = tf.convert_to_tensor(np.array([0]), dtype=tf.int32)
a0 = tfp.distributions.Categorical(probs=[0.99, 0.01])
a = tfp.distributions.Categorical(probs=[[0.01, 0.99], [0.01, 0.99]])
e = tfp.distributions.Categorical(probs=[[0.99, 0.01], [0.01, 0.99]])
model = tfp.distributions.HiddenMarkovModel(a0, a, e, 1)

logp = model.log_prob(x)
expected_logp = tf.math.log(tf.reduce_sum(a0.probs[None, :]*e.probs[:, 0]))
computed_logp = tf.math.log(tf.reduce_sum(tf.matmul(a0.probs[None, :], a.probs)*e.probs[:, 0]))

print('tfp result: ', tf.exp(logp)) # Output: 0.0198
print('Expected behavior: ', tf.exp(expected_logp)) # Output: 0.9802
print('Match tfp calculation: ', tf.exp(computed_logp)) # Output: 0.0198

The problem can be found in lines 437-441 of the source code:

def forward_step(log_prev_step, log_prob_observation):
return _log_vector_matrix(log_prev_step,
log_transition) + log_prob_observation
fwd_prob = tf.foldl(forward_step, observation_probs, initializer=log_init)

foldl computes _log_vector_matrix(log_prev_step, log_transition) + log_prob_observation in the first step of the iteration, as well as in the later iterations where it is appropriate.

This convention would in theory be ok if used consistently, but it does not match the documentation, does not match the sampling function,

print('samples', model._sample_n(10))  # Output: [[0],[0],[0],[0],[0],[0],[0],[0],[0],[0]]

and does not match the posterior mode calculation,

e2 = tfp.distributions.Categorical(probs=[[0.5, 0.5], [0.5, 0.5]])
model = tfp.distributions.HiddenMarkovModel(a0, a, e2, 1)
print('posterior mode', model.posterior_mode(x))  # Output: [0]
print('marginal hidden probs', model._marginal_hidden_probs())  # Output: [[0.99000007 0.01      ]]

Tensorflow version: 2.2.0
Tensorflow Probability version: 0.10.0

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions