HMM之维特比算法

还是上节的妹子问题。

http://blog.csdn.net/hellonlp/article/details/7849208

现在是解码问题。什么是解码问题呢?请看下面。

现在给定了一个妹子(指定模型HMM),有人告诉你某个连续五天妹子表现,即观察序列为(打, 不打, 打, 打, 不打)。再不是评估问题问你 这个观察序列以后出现的概率是多少。这回是需要你结合观察序列去推测这个妹子那几天最可能的心情变化。心情变化是(高兴, 生气, 高兴, 平静, 生气),还是(生气, 生气, 高兴, 平静, 平静)呢?还是其他心情?

看到妹子连续的表现,推测心情的变化。这就是解码问题。

这个问题有个直接的办法。把所有情况列出来一一求解呗。

那么就是 分别计算 P( (打, 不打, 打, 打, 不打) | (高兴, 生气, 高兴, 平静, 生气))

  P( (打, 不打, 打, 打, 不打) | (生气, 生气, 高兴, 平静, 平静))

 …………

然后,看看那个概率最大。OK,最大的那个概率就是要求得的。但计算太麻烦了。


《统计学习方法》中介绍个近似算法。就是计算每个时段 t 最可能出现的状态。比如在 t = 3, 我们由上节的前向算法可以得到这个时段状态分别是 高兴, 平静,生气时候的概率。然后看谁大就选谁。

比如分别计算

在t = 3 时看到观测序列为(打,不打,打), 并且现在 t = 3 时候妹子心情状态为高兴的概率。

在t = 3 时看到观测序列为(打,不打,打), 并且现在 t = 3 时候妹子心情状态为平静的概率。

在t = 3 时看到观测序列为(打,不打,打), 并且现在 t = 3 时候妹子心情状态为生气的概率。

最后看这个里面谁大我就选谁。

算法里面学过动态规划的,一看就知道很大的问题。动态规划应该可以告诉这个问题。


维特比(Viterbi)算法

这就是个动态规划解马尔科夫模型的解码问题。

动态规划问题参见 : http://blog.csdn.net/hellonlp/article/details/7849208

现在问题就简单多了,把过路收费多少问题,看成概率大小的问题。就可以搞定的。

定义两个变量:Q_t ( i ) 为时刻 t 状态为 i的所有单个路径(i_1, i_2, …………i_t)中概率最大值

       公式1

                           R_t ( i )为时刻 t 状态为 i的所有单个路径(i_1, i_2, …………i_t)中概率最大路径的前一个段t  - 1中的状态结点的编号。

   说白点,就是Q_t (i)就是在 时刻 t 妹子的心情为第 i 种(高兴, 生气,平静)的最大概率。举例现在 t = 3时候, 看到的 (打, 不打, 打)。在此时妹子心情为 i = 1 (高兴)时候最大的概率。

有很多中可能的情况:(按照公式1)

P(i_t = 高兴,高兴,平静,打, 不打, 打 | 此人模型

P(i_t = 高兴,生气,平静,打, 不打, 打 | 此人模型

……………………

从中选出概率最大的一个。假设是第一个,那么公式中的单个路径就是(平静,高兴,高兴)这条路径(跟动态规划问题中经过收费站选择路线的问题挂钩了)。

此时的R_t(i = 3)是什么呢?就是 上述最大概率路径中前一个段(t = 2)的状态编号,也就是上述(平静,高兴,高兴)路径中间那个高兴的编号,就是1 号嘛。这个变量在512nlp称之为反向指针。就是指向该结点所处最好的那个路径的前一个结点的编号。


知道动态规划和上述变量后,我们可以依次计算每天妹子各种心情变化的概率。

第一天由于没有前一天,和上一节前向算法一样,P(state | t = 1) = P(state),因此,t = 1 时的概率等于当前状态的初始概率乘以相关的混淆概率。

也就是分别算出P(高兴,打|M),P( 平静,打|M),P(生气,打|M)的概率。

然后根据这个概率去递推第二天的  R_t ( i ) 变量的概率,还有分别算出他们的反向指针。

也就是 在第一天打人,第二天不打人,第二天心情分别为高兴, 生气,平静三种情况下各自的最大概率。

接着根据第二天概率去递推第三天的  R_t ( i ) 变量的概率,还有分别算出他们的反向指针。

也就是 在第一天打人,第二天不打人,第三天打人,第三天心情分别为高兴, 生气,平静三种情况下各自的最大概率。

………………

最后计算出

也就是 在第一天打人,第二天不打人,第三天打人,第四天打人,第五天不打人。第五天心情分别为高兴, 生气,平静三种情况下各自的最大概率。

上述三种情况对应着三种路径(类似  平静,高兴,高兴,……)。概率最大者,就是所说的最可能的情况。

问题到此还没有完,还需要使用反向指针,反向着往前慢慢推出该路径的各个状态。也就是使用反向指针递推着计算第四天,第三天,……,第一天的心情状态。

这样,打工告成,我们就结合观察序列推测这个妹子那几天最可能的心情变化。



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是维算法的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`两个矩阵来辅助计算。最终,程序输出最优状态序列。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值