美文网首页
概率图模型之隐马尔科夫模型(HMM)

概率图模型之隐马尔科夫模型(HMM)

作者: 妖皇裂天 | 来源:发表于2019-01-05 22:56 被阅读0次

  首先抄下《统计学习方法》中HMM的定义和相关知识点:隐马尔科夫模型是关于时序的概率模型,描述由一个隐藏的马尔科夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测而产生观测随机序列的过程。隐马尔科夫模型由初始状态概率向量\pi、状态转移概率矩阵A和观测概率矩阵B(也可称为发射概率矩阵)组成。隐马尔科夫模型做了两个基本假设——一是任意时刻的隐状态只与前一时刻的隐状态有关,二是任意时刻的观测只与当前时刻的隐状态有关。隐马尔科夫模型如下图所示:

隐马尔科夫模型.png
其中, 隐马尔科夫中的隐状态转移图.png 每一时刻的状态与前一时刻的所有状态和下一时刻的所有状态都有关。显然,如果能够记住中间每一时刻的所有状态的转移概率,对下一时刻的状态概率(或者上一时刻的状态概率)的计算是很有帮助的。
  对于概率预测问题,我们假设前向概率为 维特比算法.png 其中第一个for循环是为了初始化中间变量 隐马尔科夫中的隐状态转移展开图.png 假设我们已经得到了n-1时刻的 T_1 ,即 T_1[:,n-1] ,那么对于时刻n的每个隐状态k,都会用伪代码中的第二个for循环来计算时刻n是隐状态k的最大概率(保存在 T_1[k,n] 中)和对应的上一时刻n-1的最优隐状态(保存在 T_2[k,n] 中)。最后通过回溯 T_2 就可以得到最优路径。

  hmmlearn源码中实现3种模型——GaussianHMM、GMMHMM和MultinomialHMM。其中GaussianHMM假设观测状态是连续型且满足高斯分布,GMMHMM假设观测状态是连续型且满足混合高斯分布,MultinomialGMM假设观测状态是离散型。
  在代码实现上,hmmlearn在base.py中定义了基本HMM模型baseHMM类,类中定义了2个重要参数——self.startprob(HMM的初始状态\pi,维度是[n_components])和self.transmat_(HMM的状态转移矩阵A,维度是[n_components, n_components]),基类中并没有定义发射矩阵B,因为只有观测状态是离散型的HMM模型才有发射矩阵(代码在MultinomialGMM类中单独定义了self.emissionprob_)。而HMM中的3个基本问题则对应了类中的3个函数:

  1. 概率计算问题,对应了_baseHMM类中的score函数。代码中利用前向算法来计算概率,核心部分如下:
for i, j in iter_from_X_lengths(X, lengths):
    framelogprob = self._compute_log_likelihood(X[i:j])
    logprobij, _fwdlattice = self._do_forward_pass(framelogprob)
    logprob += logprobij

其中,_do_forward_pass函数实现了前向算法中的\alpha_{t+1}(i)=[\sum_{j=1}^N\alpha_t(j)a_{ji}]b(o_{t+1}),i=1,2,...,N,代码在https://github.com/hmmlearn/hmmlearn/blob/master/lib/hmmlearn/_hmmc.pyx中。具体核心代码如下:

for t in range(1, n_samples):
    for j in range(n_components):
        for i in range(n_components):
            work_buffer[i] = fwdlattice[t - 1, i] + log_transmat[i, j]  # 由于取log操作,这里的*运算变成了+运算
        fwdlattice[t, j] = _logsumexp(work_buffer) + framelogprob[t, j]

hmmlearn在计算概率时都对结果进行了取log操作,是为了防止序列过长而导致计算过程中出现数值下溢的情况,这在PRML的13.2.4节中有提到。当然,代码中也是实现了后向算法,可见_do_backward_pass函数:

for t in range(n_samples - 2, -1, -1):
    for i in range(n_components):
        for j in range(n_components):
            work_buffer[j] = (log_transmat[i, j] + framelogprob[t + 1, j] + bwdlattice[t + 1, j])
        bwdlattice[t, i] = _logsumexp(work_buffer)
  1. 学习问题,对应了_baseHMM类中的fit函数。核心代码如下:
for i, j in iter_from_X_lengths(X, lengths):
    framelogprob = self._compute_log_likelihood(X[i:j])
    logprob, fwdlattice = self._do_forward_pass(framelogprob)
    curr_logprob += logprob
    bwdlattice = self._do_backward_pass(framelogprob)
    posteriors = self._compute_posteriors(fwdlattice, bwdlattice)
    self._accumulate_sufficient_statistics(stats, X[i:j], framelogprob, posteriors, fwdlattice, bwdlattice)

其中,framelogprob就是发射概率(如果观测状态是离散型就是矩阵B,如果观测状态是连续型就是高斯对数密度),fwdlattice和bwdlattice分别是前向概率\alpha_t(i)和后向概率\beta_t(i),posteriors就是P(i_t=q_i, O|\lambda)=\alpha_t(i)\beta_t(i)

  1. 预测问题,对应了_baseHMM类中的predict函数(也可以说是对应decode函数)。核心部分代码如下:
for i, j in iter_from_X_lengths(X, lengths):
    logprobij, state_sequenceij = decoder(X[i:j])
    logprob += logprobij
    state_sequence[i:j] = state_sequenceij

其中最重要的维特比算法实现代码部分如下:

for t in range(1, n_samples):
    for i in range(n_components):
        for j in range(n_components):
            work_buffer[j] = (log_transmat[j, i] + viterbi_lattice[t - 1, j])
        viterbi_lattice[t, i] = _max(work_buffer) + framelogprob[t, i]

其中,viterbi_lattice保存的就是每个中间时刻的隐状态的最大累积概率。

相关文章

网友评论

      本文标题:概率图模型之隐马尔科夫模型(HMM)

      本文链接:https://www.haomeiwen.com/subject/nplplqtx.html