原创,如转载请注明出处http://blog.csdn.net/menglongli/article/details/17355897
背景:
HMM隐式马尔可夫,在语音识别里面有着很重要的应用,在视频识别里,也有很多人效仿使用之。
作为一名Pythoner 表示 Python版本的HMM实现库很少。
虽然少,但是还是有的,我们把目光投向scikit-learn库,scikit-learn是一个很好用的机器学习的第三方库。
(在这里,我用的Python版本是 2.7,以及与其对应的scikit learn)
但是里面的HMM模块是存在问题的,而且也被遗弃很久,有网上别处的原文如下:
So far, there are a few implementations of HMMs for Python. There is the one in scikit-learn (http://scikit-learn.org/stable/modules/hmm.html) that has been abandoned for some time and recently resumed. However it still seems to have numerical problems and misses support for special cases of HMMs with tied parameters.
《scikit-learn user guide, Release 0.12-git 》是一本sklearn学习的指导书,书中有一些关于HMM的应用的demo,但是并不多。
存在问题:
比如我想用fit函数去训练一个HMM模型
我在这里特意给出一个不连续的观察状态 0,1,2,3,9
from sklearn import hmm
X=[0,1,2,1,1,2,0,3,9]
model = hmm.MultinomialHMM(n_components=4)
model.n_symbols=10
model.fit([X],n_iter=100)
print model.eval(X)
我在这里对以上的代码做一些说明:
HMM训练时候的这个fit训练函数传入的是一个list,即一组观察序列,也就说不能写成 fit(X,n_iter=100)。
对于多组观察序列
X1=[0,1,2,1,1,2,0,3,9]
X2=[3,3,3,1,1,0,1,3,3]
我们写成下面的样子即可。
fit([X1,X2],n_iter=100)
一切都按预想的编写,但是在运行时候则会出现这样的控制台信息:
Traceback (most recent call last):
File "F:/Coding/PyCharm/VideoHandlingTry/trySklearnGHMM.py", line 6, in
model.fit([X],n_iter=100)
File "C:\Python27\lib\site-packages\sklearn\hmm.py", line 1038, in fit
raise ValueError(err_msg % obs)
ValueError: Input must be both positive integer array and every element must be continuous, but [[0, 1, 2, 1, 1, 2, 0, 3, 9]] was given.
即HMM要求所输入的input必须是连续的整数才行,而我们在训练HMM的时候知道,某一个观察序列,并不一定会出现所有的预设的状态。
解决方法:
还好这个世界上有很多的大牛,他们不断完善代码,
https://github.com/scikit-learn/scikit-learn/blob/5165fba67e420c37d83b06361e86f1998c13aecd/sklearn/hmm.py
这个是在网上找到的、别人修改过的HMM的fix版本,用它覆盖掉安装的C:\Python27\Lib\site-packages\sklearn\hmm.py的文件,
再次运行上面的代码,不再发生错误,能够训练并得到估计的结果:
(-6.0698265432603344, array([[ 1.19209233e-07, 1.19209233e-07, 1.19209233e-07,
9.99999642e-01],
[ 1.19209233e-07, 9.99999642e-01, 1.19209233e-07,
1.19209233e-07],
[ 1.19209233e-07, 1.61880953e-06, 9.99998143e-01,
1.19209233e-07],
[ 1.19209233e-07, 9.95753076e-01, 1.19210165e-07,
4.24668605e-03],
[ 1.19209233e-07, 9.99999642e-01, 1.19209332e-07,
1.19209233e-07],
[ 1.19209233e-07, 1.19209233e-07, 9.99999642e-01,
1.19209233e-07],
[ 1.19209233e-07, 1.19209233e-07, 1.19209233e-07,
9.99999642e-01],
[ 9.99999642e-01, 1.19209233e-07, 1.19209233e-07,
1.19209233e-07],
[ 9.99999642e-01, 1.19209233e-07, 1.19209233e-07,
1.19209233e-07]]))
对结果进行简要说明,-6.0698265432603344是得到的评估的值,是LOG的结果,所以是负的,越接近0,表示越符合当前的HMM模型。
PS:
另外一个需要注意的地方,就是在这个hmm模型的ctor(读see-tor,表示constructor构造函数)里面没有预留n_symbols这个参数,写代码的时候建议在训练 fit 函数执行前单独给出。如果不给出的话,则需要保证input里面的整数是连续的,即X2这种,(X1不行,因为9与0,1,2,3不构成连续),但是如果在训练前给出了n_symbols的值之后(model.n_symbols=10),X1也变成了合法的输入。当然啦,上面这句话成立的前提就是,你已经按替换了HMM的代码,即 fix 过的代码。如果用原来的库里面的HMM代码的话,写了 n_symbols 也是徒劳,即必须严格保证连续(而那不是我们想要的)。