隐马尔科夫模型,Hidden Marcov Model,是可用于标注问题的统计学习模型,描述由隐藏的马尔科夫链随机生成观测序列的过程,属于生成模型,是一种比较重要的机器学习方法,在语音识别等领域有重要的应用。

本文不打算使用书面的一大堆公式来说明,本人对公式无感,能用例子说明的根本不想碰公式,不知道是不是霍金说过,多加一条公式就会损失一大片读者。PS:不管有没有说过了,是这个意思,whatever

首先说明一下基本概念,概念来自李航《统计学习方法》第十章【1】

然后根据书中的例子,来具体说明一下HMM的三要素功能

书中的例子举得很明白,所以现在应该也了解了隐马尔科夫模型的三个要素了

下面通过博客园博主Skyme的博文《一文搞懂HMM》【2】的例子对HMM做一个代码上的解释,需要说明的是,我无意侵犯其知识产权,只是觉得该文举得例子比较好,所以就想拿过来用,毕竟自己画图举例什么的太过麻烦,博文原地址我也给出来了,算是论文里面的引用吧。

好的言归正传,我们来看一下HMM需要解决的基本的三个问题,仍然是使用【1】书的内容:

结合具体的问题,来看一下这三个问题究竟是什么。

假设我手里有三个不同的骰子。第一个骰子是我们平常见的骰子(称这个骰子为D6),6个面,每个面(1,2,3,4,5,6)出现的概率是1/6。第二个骰子是个四面体(称这个骰子为D4),每个面(1,2,3,4)出现的概率是1/4。第三个骰子有八个面(称这个骰子为D8),每个面(1,2,3,4,5,6,7,8)出现的概率是1/8。

我们假设开始掷骰子的时候的初始概率是一样的也就是1/3,则初始状态是        PI={1/3,1/3,1/3} 分别对应于D6,D4,D8, 为了方便阐述,我们假设每个状态的转移概率都是1/3,则转移矩阵(也就是上文提到的A矩阵)是
 
                                                   

然后观测结果集合是{1,2, 3, 4,5, 6, 7, 8}

每个状态的观测概率矩阵,也就是上文提到的B矩阵


 到此,PI,A,B 这HMM三要素都到齐了,至于观测序列,则根据具体的问题具体说明

现在模型已经给出了,让我们看一下HMM的三个问题对于这个问题的具体实现

[1],概率计算问题:我们已知上面的HMM模型参数,也知道现在的观测序列,现在我们想知道从原始模型到这个观测序列的概率是多少。

现在我们假设现在的观测序列是 1-6-3

我现在想知道从之前的模型参数值(PI,A,B)掷骰子到1-6-3的概率有多大

解决办法:

如果使用最原始的首先枚举出每个可能的状态集然后分别求概率,然后把这些概率想加,这种办法的效率太低,因此需要使用一种更加好的算法来计算

这里使用的是前向算法,计算理论推导在【1】书中有详细的过程,这里使用【2】举得例子

需要说明的是原文的计算结果似乎是有错误,所以这里讲原文的求和数据省去了,但是方法还是一样计算,这下应该是很明了的的计算方法,就像一条计算链条,多长的结果都能计算出来,下面是代码实现过程:

package com.luchi.hmm;
import com.luchi.hmm.problem1.status;
/*
* @description
* 隐马尔科夫模型主要解决的是三个问题
* 1,预测问题,也就是解码问题,已知模型lambda=(A,B,PI)和观测序列,其给定观测序列条件概率P(I|O)最大的状态序列I
* 2,概率计算问题:给定模型lambda=(A,B,PI)和观测序列O,计算在该模型lambda下观测序列O出现的概率P(O|lambda)
* 3,学习问题,已知观测序列O,估计模型lambda=(A,B,PI)的参数
*
* 这里解决的是第二个问题,也就是计算概率问题,这里使用了前向算法
* @author:luchi
*/
public class problem2 {
//定义状态转移矩阵
double [][]trans=new double[][]{
{0.33,0.33,0.33},
{0.33,0.33,0.33},
{0.33,0.33,0.33},
};
//状态名称
enum status{
D6,
D4,
D8
};
//总状态数
int status_length=3;
//掷骰子事件分别是1,2,3,4,5,6
//每个状态下掷骰子事件发生概率
double[][] emission_probability = new double[][]{
{0.167, 0.167, 0.167,0.167,0.167,0.167,0,0},
{0.250,0.250,0.250,0.250,0,0,0,0},
{0.125,0.125,0.125,0.125,0.125,0.125,0.125,0.125}
};
int activity_length=emission_probability[0].length;
//观察序列为
int []observation=new int[]{1,6,3};
//初始序列
double[]start=new double[]{0.33,0.33,0.33};
//计算出现的概率
public void calcuProb(){
double[][]midStore=new double[observation.length][status_length];
double totalProb=0.0;
//初始化第一个概率
for(int i=0;i<status_length;i++){
double temp=start[i]*emission_probability[i][observation[0]-1];
midStore[0][i]=temp;
totalProb+=temp;
}
if(observation.length>=1){
for(int i=1;i<observation.length;i++){
totalProb=0.0;
int desPos=observation[i]-1;
for(int j=0;j<status_length;j++){
double temp=0.0;
for(int t=0;t<status_length;t++){
temp+=midStore[i-1][t]*trans[t][j]*emission_probability[j][desPos];
}
midStore[i][j]=temp;
totalProb+=temp;
}
System.out.println(totalProb);
}
}
}
public static void main(String[]args){
problem2 p=new problem2();
p.calcuProb();
}
}

 算出来的结果是:0.003082643085456001

[2],学习问题:知道骰子有几种(隐含状态数量),不知道每种骰子是什么(转换概率),观测到很多次掷骰子的结果(可见状态链),我想反推出每种骰子是什么(转换概率)。

也就是不知道上面所描述的HMM模型参数(PI,A,B),现在需根据观测结果O 来反推HMM的参数,这是一个学习过程,也是一个比较重要的问题,一般使用E-M算法进行推导,因为可以把HMM的状态模型看作是未知参数,因此就有了E步和M步,因为本人对EM算法的理解还处于高斯混合模型GMM阶段,并不算很熟悉,所以不打算详细介绍,有兴趣的话可以看【1】的第181-184的推导

[3].预测问题:知道HMM的参数(PI,A,B)也已知观测掷骰子的结果O(o1,o2,o3,o4...),现在想知道o1,o2,o3...是由哪些骰子(D6,D4,D8)掷出来的

这里使用的是维特比算法,维特比算法实际上是用动态规划求解隐马尔科夫预测问题,也就是使用动态规划求解概率最大路径,这个时候一条路径对应的一个状态序列。下面通过一个例题说明:

由此可见,维特比算是其实是一个类似回溯算法一样的计算过程,每个阶段都储存上一个阶段到这个阶段概率最大的状态,然后到达最终态的时候回溯找到状态序列

还是以文章的掷骰子为题为例,HMM的模型(PI,A,B)都不变,现在观察到的点数(观测序列)是(1 6 3 5 2 7 3 5 2 4),然后我们根据维特比算法来求解最大概率的掷到这个点数序列的状态集

(也就是是哪个筛子掷的的集合),根据上图例10.3的维特比算法的说明可以将这个问题用以下代码实现

package com.luchi.hmm;
/*
* @description
* 隐马尔科夫模型主要解决的是三个问题
* 1,预测问题,也就是解码问题,已知模型lambda=(A,B,PI)和观测序列,其给定观测序列条件概率P(I|O)最大的状态序列I
* 2,概率计算问题:给定模型lambda=(A,B,PI)和观测序列O,计算在该模型lambda下观测序列O出现的概率P(O|lambda)
* 3,学习问题,已知观测序列O,估计模型lambda=(A,B,PI)的参数
*
* 这个首先解决的是第一个问题,也就是预测问题,主要有两种算法,一个是近似算法,一个是维特比算法,这里使用了viterbi算法
@author:luchi
* */
public class problem1 {
//定义状态转移矩阵
double [][]trans=new double[][]{
{0.33,0.33,0.33},
{0.33,0.33,0.33},
{0.33,0.33,0.33},
};
//状态名称
enum status{
D6,
D4,
D8
};
//总状态数
int status_length=3;
//掷骰子事件分别是1,2,3,4,5,6
//每个状态下掷骰子事件发生概率
double[][] emission_probability = new double[][]{
{0.167, 0.167, 0.167,0.167,0.167,0.167,0,0},
{0.250,0.250,0.250,0.250,0,0,0,0},
{0.125,0.125,0.125,0.125,0.125,0.125,0.125,0.125}
};
int activity_length=emission_probability[0].length;
//观察序列为
int []observation=new int[]{1,6,3,5,2,7,3,5,2,4};
//初始序列
double[]start=new double[]{0.33,0.33,0.33};
//维特比算法求解
public void viterbi(){
//初始化存储中间矩阵
double[][]midStore=new double[observation.length][status_length];
int[][]traceBack=new int[observation.length][status_length];
//初始化第一个数据
for(int i=0,desPos=observation[0]-1;i<status_length;i++){
midStore[0][i]=start[0]*emission_probability[i][desPos];
}
//从第二个观测序列开始计算
for(int i=1;i<observation.length;i++){
int desPos=observation[i]-1; //注意数组是从0开始的,而不是1
for(int j=0;j<status_length;j++){
double maxProb=-1;
int traceStatus=0;
//比较前面的序列
for(int t=0;t<status_length;t++){
double tempProb=midStore[i-1][t]*trans[t][j]*emission_probability[j][desPos];
if(tempProb>maxProb){
maxProb=tempProb;
traceStatus=t;
}
}
midStore[i][j]=maxProb;
traceBack[i][j]=traceStatus;
}
}
//比较最后一个阶段的最大概率
int max_end_status=0;
double max_end_prob=-1;
for(int end_status=0;end_status<status_length;end_status++){
double prob=midStore[observation.length-1][end_status];
if(prob>max_end_prob){
max_end_prob=prob;
max_end_status=end_status;
}
}
//回溯输出最大概率状态模型
int []path=new int[observation.length];
path[observation.length-1]=max_end_status;
int curStatus=max_end_status;
for(int i=observation.length-1;i>=1;i--){
int preStatus=traceBack[i][curStatus];
path[i-1]=preStatus;
curStatus=preStatus;
}
for(int i=0;i<path.length;i++){
System.out.println(status.values()[path[i]]);
}
}
public static void main(String[]args){
problem1 p=new problem1();
p.viterbi();
}
}

 预测的结果是:D4 D6 D4 D6 D4 D8 D4 D6 D4 D4

恩,这就是我对Hidden Morcov Model的浅见,不足之处还望指正

参考文献:

【1】李航 《统计学习方法》

【2】skyme 《一文搞懂HMM》 http://www.cnblogs.com/skyme/p/4651331.html#commentform

  • 大小: 55.6 KB
  • 大小: 135.7 KB
  • 大小: 50.8 KB
  • 大小: 68.3 KB
  • 大小: 82.1 KB
  • 大小: 7 KB
  • 大小: 5.4 KB
  • 大小: 5.4 KB
  • 大小: 10.1 KB
  • 大小: 38.1 KB
  • 大小: 128.9 KB
  • 大小: 135.4 KB
  • 大小: 203.6 KB
  • 查看图片附件

隐马尔科夫模型(HMM)浅见相关推荐

  1. 隐马尔科夫模型HMM自学 (3)

    Viterbi Algorithm 本来想明天再把后面的部分写好,可是睡觉今天是节日呢?一时情不自禁就有打开电脑.......... 找到可能性最大的隐含状态序列 崔晓源 翻译 多数情况下,我们都希望 ...

  2. 隐马尔科夫模型HMM自学 (2)

    HMM 定义 崔晓源 翻译 HMM是一个三元组 (,A,B).  the vector of the initial state probabilities;  the state transitio ...

  3. 隐马尔科夫模型HMM自学(1)

    介绍 崔晓源 翻译 我们通常都习惯寻找一个事物在一段时间里的变化规律.在很多领域我们都希望找到这个规律,比如计算机中的指令顺序,句子中的词顺序和语音中的词顺序等等.一个最适用的例子就是天气的预测. 首 ...

  4. 【NLP】用于语音识别、分词的隐马尔科夫模型HMM

    大家好,今天介绍自然语言处理中经典的隐马尔科夫模型(HMM).HMM早期在语音识别.分词等序列标注问题中有着广泛的应用. 了解HMM的基础原理以及应用,对于了解NLP处理问题的基本思想和技术发展脉络有 ...

  5. python地图匹配_基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法

    1. 摘要 本篇博客简单介绍下用隐马尔科夫模型(Hidden Markov Model, HMM)来解决地图匹配(Map-Matching)问题.转载请注明网址. 2. Map-Matching(MM ...

  6. 隐马尔科夫模型 HMM 与 语音识别 speech recognition (1):名词解释

    0.引言 想在 CSDN 上看一下隐马尔科夫模型,简称HMM(Hidden Markov Model)的例子,找了几篇博文,却发现大部分都是转载的,转载的还没有出处,文中的表述与逻辑也看的人晕头转向, ...

  7. 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数

    在本篇我们会讨论HMM模型参数求解的问题,这个问题在HMM三个问题里算是最复杂的.在研究这个问题之前,建议先阅读这个系列的前两篇以熟悉HMM模型和HMM的前向后向算法,以及EM算法原理总结,这些在本篇 ...

  8. 一、隐马尔科夫模型HMM

    隐马尔科夫模型HMM(一)HMM模型基础 隐马尔科夫模型(Hidden Markov Model,以下简称HMM)是比较经典的机器学习模型了,它在语言识别,自然语言处理,模式识别等领域得到广泛的应用. ...

  9. 隐马尔科夫模型 (HMM) 算法介绍及代码实现

    Table of Contents Hidden Markov Model (隐马尔科夫模型) 定义 基本问题 前向算法 算法流程 实现代码 后向算法 算法流程 实现代码 Viterbi算法 算法流程 ...

最新文章

  1. 操作系统(四) | 经典进程的同步问题(生产者--消费者问题、哲学家进餐问题、读者--写者问题)
  2. [Android] 开发第二天
  3. 2008.02.05
  4. Apache ServiceComb
  5. MySQL 之 索引
  6. 复练-关于面试的科技树-能力三核的彩蛋
  7. Linux中usb设置burst,Re: 关于IMX6UL第二个USB接口在linux驱动的问题
  8. Mozilla Firefox 66 将使用更少的内存,提高扩展性能
  9. 09.Java数据算法
  10. 【分享】如何创建自己的Visual Studio 2005/2008配色
  11. 2018-10-27
  12. vs禁用函数安全检查
  13. 年龄识别数据集IMDB-WIKI
  14. shell脚本中执行ssh
  15. 蚂蚁区块链BaaS平台架构与实践
  16. 从MWC 2016看手机发展
  17. 移植 u-boot-2020.07 到 iTOP-4412(二)地址相关码 boot
  18. sqlplus format 999 A10,以及SQL.PNO的含义
  19. 第7章:OFDM 信道估计与均衡(1)
  20. Testin云测:从双11看淘宝京东暗战移动电商

热门文章

  1. 终于解决了PADS,Altium,ORCAD的相互转换问题
  2. J storm战队成员_J.Storm战队踢掉队内三号位Forev主动扣分
  3. 第十七次ScrumMeeting博客
  4. 怎样才能批量查询网站的谷歌PR权重?把手教你批量查询网站谷歌PR权重值
  5. 程序设计基础(计算机类2014) 实验4 选择控制结构1
  6. 身边策神 振江 刘盛义等等
  7. 引起进程调度的原因有以下几类
  8. 基于YOLOV3实现交通标志识别(Pytorch实现)
  9. Zcash 对以太坊来说意味着什么?
  10. 信息时代的必修课:冗余度(善用信息冗余成为沟通的高手)