hmmlearn实现了三种HMM模型类,按照观测状态是连续状态还是离散状态,可以分为两类。GaussianHMM和GMMHMM是连续观测状态的HMM模型,而MultinomialHMM是离散观测状态的模型,也是我们在HMM原理系列篇里面使用的模型。
对于MultinomialHMM的模型,使用比较简单,"startprob_"参数对应我们的隐藏状态初始分布, "transmat_"对应我们的状态转移矩阵, "emissionprob_"对应我们的观测状态概率矩阵。
对于连续观测状态的HMM模型,GaussianHMM类假设观测状态符合高斯分布,而GMMHMM类则假设观测状态符合混合高斯分布。一般情况下我们使用GaussianHMM即高斯分布的观测状态即可。以下对于连续观测状态的HMM模型,我们只讨论GaussianHMM类。
在GaussianHMM类中,"startprob_"参数对应我们的隐藏状态初始分布, "transmat_"对应我们的状态转移矩阵, 比较特殊的是观测状态概率的表示方法,此时由于观测状态是连续值,我们无法像MultinomialHMM一样直接给出矩阵。而是采用给出各个隐藏状态对应的观测状态高斯分布的概率密度函数的参数。
如果观测序列是一维的,则观测状态的概率密度函数是一维的普通高斯分布。如果观测序列是维的,则隐藏状态对应的观测状态的概率密度函数是维高斯分布。高斯分布的概率密度函数参数可以用表示高斯分布的期望向量,表示高斯分布的协方差矩阵。在GaussianHMM类中,“means”用来表示各个隐藏状态对应的高斯分布期望向量形成的矩阵,而“covars”用来表示各个隐藏状态对应的高斯分布协方差矩阵形成的三维张量。
1:MultinomialHMM
模型概率自动对求log,所以求概率时要求e的(socre)次方。
#构建模型,本例子见李航老师统计学习方法HMM章节
import numpy as np
import math
from hmmlearn import hmm
states = ["box 1", "box 2", "box3"]
n_states = len(states)
observations = ["red", "white"]
n_observations = len(observations)
start_probability = np.array([0.2, 0.4, 0.4])
transition_probability = np.array([
[0.5, 0.2, 0.3],
[0.3, 0.5, 0.2],
[0.2, 0.3, 0.5]
])
emission_probability = np.array([
[0.5, 0.5],
[0.4, 0.6],
[0.7, 0.3]
])
model = hmm.MultinomialHMM(n_components=n_states)
model.startprob_=start_probability
model.transmat_=transition_probability
model.emissionprob_=emission_probability
#维特比算法
seen = np.array([[0,1,0]]).T
see = np.array([0,1,0])
logprob, box = model.decode(seen, algorithm="viterbi")
print("The ball picked:", ", ".join(map(lambda x: observations[x], see)))
print("The hidden box", ", ".join(map(lambda x: states[x], box)))
print (math.exp(logprob))
#前向算法
box2 = model.predict(seen)
print("The ball picked:", ", ".join(map(lambda x: observations[x], see)))
print("The hidden box", ", ".join(map(lambda x: states[x], box2)))
print (math.exp(model.score(seen)))
#baum-welch算法
states = ["box 1", "box 2", "box3"]
n_states = len(states)
observations = ["red", "white"]
n_observations = len(observations)
model2 = hmm.MultinomialHMM(n_components=n_states, n_iter=20, tol=0.01)
X2 = np.array([[0,1,1,1],[1,0,1,1],[0,0,1,1]])#自定义观测序列
model2.fit(X2)
print( model2.startprob_)
print( model2.transmat_)
print (model2.emissionprob_)
print (math.exp(model2.score(X2)))
print("\n")
model2.fit(X2)
print (model2.startprob_)
print (model2.transmat_)
print (model2.emissionprob_)
print (math.exp(model2.score(X2)))
print("\n")
model2.fit(X2)
print (model2.startprob_)
print (model2.transmat_)
print (model2.emissionprob_)
print (math.exp(model2.score(X2)))
选择一个分数高的
2.GaussianHMM
下面我们再给一个GaussianHMM的实例,这个实例中,我们的观测状态是二维的,而隐藏状态有4个。因此我们的“means”参数是的矩阵,而“covars”参数是的张量。
startprob = np.array([0.6, 0.3, 0.1, 0.0])
# The transition matrix, note that there are no transitions possible
# between component 1 and 3
transmat = np.array([[0.7, 0.2, 0.0, 0.1],
[0.3, 0.5, 0.2, 0.0],
[0.0, 0.3, 0.5, 0.2],
[0.2, 0.0, 0.2, 0.6]])
# The means of each component
means = np.array([[0.0, 0.0],
[0.0, 11.0],
[9.0, 10.0],
[11.0, -1.0]])
# The covariance of each component
covars = .5 * np.tile(np.identity(2), (4, 1, 1))
# Build an HMM instance and set parameters
model3 = hmm.GaussianHMM(n_components=4, covariance_type="full")
# Instead of fitting it from the data, we directly set the estimated
# parameters, the means and covariance of the components
model3.startprob_ = startprob
model3.transmat_ = transmat
model3.means_ = means
model3.covars_ = covars
注意上面有个参数covariance_type,取值为"full"意味所有的都需要指定。取值为“spherical”则的非对角线元素为0,对角线元素相同。取值为“diag”则的非对角线元素为0,对角线元素可以不同,"tied"指所有的隐藏状态对应的观测状态分布使用相同的协方差矩阵
我们现在跑一跑HMM问题一解码的过程,由于观测状态是二维的,我们用的三维观测序列, 所以这里的 输入是一个的张量,代码如下:
seen = np.array([[1.1,2.0],[-1,2.0],[3,7]])
logprob, state = model3.decode(seen, algorithm="viterbi")
print(state)
输出结果如下:
[0 0 1]
再看看HMM问题一对数概率的计算:
print (math.exp(model3.score(seen)))