HMM学习笔记之维特比算法

     寻找最可能的隐藏状态序列(Finding most probable sequence of hidden states)

     对于一个特殊的隐马尔科夫模型(HMM)及一个相应的观察序列,我们常常希望能找到生成此序列最可能的隐藏状态序列。

1、穷举搜索

      给定一个 HMM,我们想计算出某个可观察序列的概率。考虑天气的例子,我们知道一个描述天气和海藻状态的 HMM,而且我们还有一个海藻状态的序列。假设这个状态中的某三天是(dry,damp,soggy),在这三天中的每一天,天气都可能是晴朗,多云或者下雨,我们可以用下图来描述观察序列和隐藏序列:

  在这个图中的每一列表示天气的状态可能,并且每个状态都指向相邻的列的每个状态,每个状态转换在状态转移矩阵中都有一个概率。每一列的下面是当天的可观察的海藻的状态,在每种状态下出现这种可观察状态的概率是由混淆矩阵给出的。

      我们可以通过列出所有可能的隐藏状态序列并且计算对于每个组合相应的观察序列的概率来找到最可能的隐藏状态序列。最可能的隐藏状态序列是使下面这个概率最大的组合: 

                                                                        Pr(观察序列|隐藏状态的组合)                

  一个可能的计算可观察概率的方法是找到每一个可能的隐藏状态的序列,这里有3= 27种,这个时候的可观察序列的概率就是 Pr(dry, damp, soggy | HMM)=Pr(dry, damp, soggy | sunny, sunny, sunny) + . . . . + Pr(dry, damp, soggy | rainy, rainy, rainy)。

       对于网格中所显示的观察序列,最可能的隐藏状态序列是下面这些概率中最大概率所对应的那个隐藏状态序列: 
Pr(dry,damp,soggy | sunny,sunny,sunny), Pr(dry,damp,soggy | sunny,sunny,cloudy), Pr(dry,damp,soggy | sunny,sunny,rainy), . . . . Pr(dry,damp,soggy | rainy,rainy,rainy)

  很显然,这种计算的效率非常低,尤其是当模型中的状态非常多或者序列很长的时候。事实上,我们可以利用概率不随时间变化这个假设来降低时间的开销。

2、使用递归降低复杂度

      在给定了一个可观察序列和HMM的情况下,我们可以考虑递归的来寻找最可能的隐藏序列。我们可以先定义一个部分概率 δ,即到达某个中间状态的概率。接下来我们将讨论如何计算 t=1 和 t=n (n>1) 的部分概率。

     我们首先定义局部概率  ,它是到达网格中的某个特殊的中间状态时的概率。 然后,我们将介绍如何在t =1和t =n (>1)时计算这些局部概率。 这些局部概率与前向算法中所计算的局部概率是不同的,因为它们表示的是时刻t时到达某个状态最可能的路径的概率,而不是所有路径概率的总和。

1) 部分概率和部分最优路径

  考虑下面这个图以及可观察序列 (dry, damp, soggy) 的一阶转移

  对于每一个中间状态和终止状态 (t=3) 都有一个最可能的路径。比如说,在 t=3 时刻的三个状态都有一个如下的最可能的路径:

  我们可以称这些路径为部分最优路径。这些部分最优路径都有一个概率,也就是部分概率 δ。和前向算法中的部分概率不一样,这里的概率只是一个最可能路径的概率,而不是所有路径的概率和。

  我们可以用 δ(i, t) 来表示在t时刻,到状态i的所有可能的序列(路径)中概率最大的序列的概率,部分最优路径就是达到这个最大概率的路径,对于每一个时刻的每一个状态都有这样一个概率和部分最优路径。

  最后,我们通过计算 t=T 时刻的每一个状态的最大概率和部分最优路径,选择其中概率最大的状态和它的部分最优路径来得到全局的最优路径。

  2) 计算 t=1 时刻的部分概率

  当 t=1 时刻的时候,到达某个状态最大可能的路径还不存在,但是我们可以直接使用在 t=1 时刻某个状态的概率和这个状态到可观察序列 k的转移概率:

  3) 计算 t>1 时刻的部分概率

  接下来我们可以根据 t-1 时刻的部分概率来求 t 时刻的部分概率

  我们可以计算所有到状态 X 的路径的概率,找到其中最可能的路径,也就是局部最优路径。注意到这里,到达X的路径必然会经过 t-1 时刻的 A、B 和 C,所以我们可以利用之前的结果。达到X的最可能的路径就是下面三个之一:

  (状态序列),. . .,A,X (状态序列),. . .,B,X (状态序列),. . .,C,X

  我们需要做的就是找到以 AX、BX 和 CX 结尾的路径中概率最大的那个。

  根据一阶马尔科夫的假设,一个状态的发生之和之前的一个状态有关系,所以X在某个序列的最后发生的概率只依赖于其之前的一个状态:

Pr (到达A的最优路径) . Pr (X | A) . Pr (观察状态 | X)

  有个了这个公式,我们就可以利用t-1时刻的结果和状态转移矩阵和混淆矩阵的数据:

  将上面这个表达式推广一下,就可以得到 t 时刻可观察状态为 k的第 i 个状态的最大部分概率的计算公式:

  其中 aji 表示从状态 j 转移到状态 i 的概率,bikt 表示状态i被观察成 kt 的概率。

  4) 后向指针

  考虑下图

  在每一个中间状态和结束状态都有一个部分最优概率 δ(i, t)。但是我们的目的是找到最可能的隐藏状态序列,所以我们需要一个方法去记住部分最优路径的每一个节点。

  考虑到要计算 t 时刻的部分概率,我们只需要知道 t-1 时刻的部分概率,所以我们只需要记录那个导致了 t 时刻最大部分概率的的状态,也就是说,在任意时刻,系统都必须处在一个能在下一时刻产生最大部分概率的状态。如下图所示:

  我们可以利用一个后向指针 φ 来记录导致某个状态最大局部概率的前一个状态,即

  这里 argmax 表示能最大化后面公式的j值,同样可以发现这个公式和 t-1 时刻的部分概率和转移概率有关,因为后向指针只是为了找到“我从哪里来”,这个问题和可观察状态没有关系,所以这里不需要再乘上混淆矩阵因子。全局的行为如下图所示:

  5) 优点

  使用 viterbi 算法对一个可观察状态进行解码有两个重要的优点:

  a) 通过使用递归来减少复杂度,这点和之前的前向算法是一样的

  b) 可以根据可观察序列找到最优的隐藏序列,这个的计算公式是:

其中 

  这里就是一个从左往右翻译的过程,通过前面的翻译结果得到后面的结果,起始点是初始向量 π。

  3. 补充

  但在序列某个地方有噪声干扰的时候,某些方法可能会和正确答案相差的较远。但是 Viterbi 算法会查看整个序列来决定最可能的终止状态,然后通过后向指针来找到之前的状态,这对忽略孤立的噪声非常有用。

  Viterbi 算法提供了一个根据可观察序列计算隐藏序列的很高效的方法,它利用递归来降低计算复杂度,并且使用之前全部的序列来做判断,可以很好的容忍噪声。

  在计算的过程中,这个算法计算每一个时刻每一个状态的部分概率,并且使用一个后向指针来记录达到当前状态的最大可能的上一个状态。最后,最可能的终止状态就是隐藏序列的最后一个状态,然后通过后向指针来查找整个序列的全部状态。

参考:https://blog.csdn.net/likelet/article/details/7056068

https://wenku.baidu.com/view/ff413e1cc5da50e2524d7f1c.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是维特比算法的C语言实现: ``` #include <stdio.h> #include <stdlib.h> #define N 3 // 状态数 #define M 4 // 观测符号数 int main() { int i, j, t; int obs_seq[] = {0, 1, 2, 0}; // 观测序列 double a[N][N] = {{0.5, 0.2, 0.3}, {0.3, 0.5, 0.2}, {0.2, 0.3, 0.5}}; // 转移概率矩阵 double b[N][M] = {{0.5, 0.5, 0.0, 0.0}, {0.0, 0.5, 0.5, 0.0}, {0.0, 0.0, 0.5, 0.5}}; // 发射概率矩阵 double pi[N] = {0.2, 0.4, 0.4}; // 初始状态概率 double delta[M][N]; // delta矩阵 int psi[M][N]; // psi矩阵 int q[M]; // 最优状态序列 // 初始化 for (i = 0; i < N; i++) { delta[0][i] = pi[i] * b[i][obs_seq[0]]; psi[0][i] = 0; } // 递推 for (t = 1; t < M; t++) { for (j = 0; j < N; j++) { double max_delta = 0.0; int max_i = 0; for (i = 0; i < N; i++) { double tmp_delta = delta[t - 1][i] * a[i][j] * b[j][obs_seq[t]]; if (tmp_delta > max_delta) { max_delta = tmp_delta; max_i = i; } } delta[t][j] = max_delta; psi[t][j] = max_i; } } // 终止 double max_delta = 0.0; int max_i = 0; for (i = 0; i < N; i++) { if (delta[M - 1][i] > max_delta) { max_delta = delta[M - 1][i]; max_i = i; } } // 回溯 q[M - 1] = max_i; for (t = M - 2; t >= 0; t--) { q[t] = psi[t + 1][q[t + 1]]; } // 输出结果 printf("最优状态序列为:"); for (t = 0; t < M; t++) { printf("%d ", q[t]); } printf("\n"); return 0; } ``` 其中,`a`数组为转移概率矩阵,`b`数组为发射概率矩阵,`pi`数组为初始状态概率,`obs_seq`数组为观测序列。程序中使用了`delta`和`psi`两个矩阵来辅助计算。最终,程序输出最优状态序列。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值