jmschrei / pomegranate

Fast, flexible and easy to use probabilistic modelling in Python.
http://pomegranate.readthedocs.org/en/latest/
MIT License
3.37k stars 590 forks source link

Can't make HMM work #448

Closed sandaur closed 6 years ago

sandaur commented 6 years ago

Hello, i'm trying to make work a Hidden Markov Model with continuous observations. I try to fit the model using a single sequence of 3 normalized histograms (each histogram is an observation) but it seems not to work, the transition matrix does not change after using fit(). Here is my code.

import numpy as np
from pomegranate import *

seq = np.array([
    [ #Sequence 1
        [0.46078431372549017, 0.0, 0.0, 0.0, 0.0, 0.0, 0.23529411764705882, 0.0, 0.30392156862745096, 0.0],                 #observation 1
        [0.47783251231527096, 0.0, 0.0, 0.18719211822660098, 0.0, 0.0, 0.14285714285714285, 0.0, 0.1921182266009852, 0.0],  #observation 2
        [0.40066225165562913, 0.0, 0.0, 0.3741721854304636, 0.0, 0.0, 0.09602649006622517, 0.0, 0.1291390728476821, 0.0]    #observation 3
    ]
])

s1 = State(NormalDistribution(0, 1))
s2 = State(NormalDistribution(0, 1))
s3 = State(NormalDistribution(0, 1))
s4 = State(NormalDistribution(0, 1))
s5 = State(NormalDistribution(0, 1))
s6 = State(NormalDistribution(0, 1))

model = HiddenMarkovModel()
model.add_states(s1,s2,s3,s4,s5,s6)

model.add_transition( model.start, s1, 0.5 )
model.add_transition( model.start, s2, 0.5 )

model.add_transition( s1, s3, 0.5 )
model.add_transition( s1, s4, 0.5 )
model.add_transition( s2, s3, 0.5 )
model.add_transition( s2, s4, 0.5 )

model.add_transition( s3, s5, 0.5 )
model.add_transition( s3, s6, 0.5 )
model.add_transition( s4, s5, 0.5 )
model.add_transition( s4, s6, 0.5 )

model.add_transition( s5, model.end, 1 )
model.add_transition( s6, model.end, 1 )

model.bake()

print("Original Transition Matrix")
print(model.dense_transition_matrix())

model.fit(seq)

print("Fitted Transition Matrix")
print(model.dense_transition_matrix())

Any idea of what could i been doing wrong? Thanks in advance.

jmschrei commented 6 years ago

Try MultivariateGaussianDistribution instead of NormalDistribution. I'm currently working on a patch that will make it so that if you specify NormalDistribution on multivariate data it will model each feature using a normal distribution, but right now it just does something wrong.

sandaur commented 6 years ago

Thanks for answer.

What i did was change all the constructions of my states for this

State(MultivariateGaussianDistribution([0,0], np.eye(2)))

But got the same result. I have to change something else?

jmschrei commented 6 years ago

Your data is 10 dimensional, right? Why are you modeling it with a two dimensional Gaussian?

On Wed, May 30, 2018 at 10:31 AM sandaur notifications@github.com wrote:

Thanks for answer.

What i did was change all the constructions of my states for this

State(MultivariateGaussianDistribution([0,0], np.eye(2)))

But got the same result. I have to change something else?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/jmschrei/pomegranate/issues/448#issuecomment-393250315, or mute the thread https://github.com/notifications/unsubscribe-auth/ADvEECkgaVbulWG-Excvb58Fbfuk-6FSks5t3teJgaJpZM4USOUl .

sandaur commented 6 years ago

I'm sorry, i haven't used this distribution before, copy paste the first example i had found.

Now i used this, 10 dimensional mean vector and 10x10 dimensional covariance matrix.

State(MultivariateGaussianDistribution(np.zeros([10]), np.eye(10)))

Still nothing, got the same unaltered transition matrix.

jmschrei commented 6 years ago

The reason is because the model wasn't training. If you passed in verbose=True you would see the following:

[1] Improvement: nan    Time (s): 4.697e-05
Total Training Improvement: nan
Total Training Time (s): 0.0004

The reason is because if you make the probabilities to each state equal, and the emissions of each state equal, than the probability of going down any path through the model is equal. This is similar to if you tried to train a k-means model by selecting the same point to be the centroid for each cluster.

If you set each state instead to State(MultivariateGaussianDistribution(np.random.randn(10), np.eye(10))), then your model would train, and you'd output like the following:

Original Transition Matrix
[[0.  0.  0.  0.  0.5 0.5 0.  0. ]
 [0.  0.  0.  0.  0.5 0.5 0.  0. ]
 [0.5 0.5 0.  0.  0.  0.  0.  0. ]
 [0.5 0.5 0.  0.  0.  0.  0.  0. ]
 [0.  0.  0.  0.  0.  0.  0.  1. ]
 [0.  0.  0.  0.  0.  0.  0.  1. ]
 [0.  0.  0.5 0.5 0.  0.  0.  0. ]
 [0.  0.  0.  0.  0.  0.  0.  0. ]]
[1] Improvement: 286.736450997  Time (s): 0.008253
[2] Improvement: 1.38151676765e-08  Time (s): 0.001807
[3] Improvement: -0.0242289283095   Time (s): 0.001808
Total Training Improvement: 286.712222082
Total Training Time (s): 0.0122
Fitted Transition Matrix
[[0.         0.         0.         0.         0.01589021 0.98410979
  0.         0.        ]
 [0.         0.         0.         0.         0.01589021 0.98410979
  0.         0.        ]
 [0.08566092 0.91433908 0.         0.         0.         0.
  0.         0.        ]
 [0.08566092 0.91433908 0.         0.         0.         0.
  0.         0.        ]
 [0.         0.         0.         0.         0.         0.
  0.         1.        ]
 [0.         0.         0.         0.         0.         0.
  0.         1.        ]
 [0.         0.         0.02393773 0.97606227 0.         0.
  0.         0.        ]
 [0.         0.         0.         0.         0.         0.
  0.         0.        ]]