隐马尔可夫模型的前向算法(java实现),今天奉上

隐马尔可夫模型的前向算法(手动实现),今天奉上,由于研究生期间,实现的时候没有多加注释,这里为了让更好的人进入自然语言处理领域,特此,将前向算法奉上,具体公式可参考52nlp的HMN系列博客。

参考了大部分网站公式和借鉴。在此表示感谢。

后向算法和维特比算法,后续更新。

HMM类:

1 package jxutcm.edu.cn.hmm.model;
  2 
  3 import jxutcm.edu.cn.hmm.bean.HMMHelper;
  4 
  5 /**
  6  * 实现了 HMM(隐马尔可夫模型, Hidden Markov Models)的 前向(Forward), 后向(Backward),
  7  * 前向-后向(Baum-Welch)算法 这里均计算对数概率(将乘法转换为加法)
  8  *  HMM五元素:λ=(N, M, A, B, pi) 
  9  *  N:隐藏状态数 hidden states 
 10  *  M:观测状态数 observed states 
 11  *  A: 状态转移矩阵 transition matrix 
 12  *  B:发射矩阵 emission matrix 
 13  *  pi:初始隐状态向量 initial state vector
 14  *                                                                           P(q_t|q_t-1)
 15  * 隐藏状态: q1 ——>q2 ——> ……——>q_t-1——>q_t——>——>q_T
 16  *                      |                 |                                 |                  |                          |
 17  *                      |                 |                                 |                  |                          |
 18  *  显示状态:O1            O2                             O_t-1        O_t                    O_T
 19  *  隐数目——N个;显数目——M个
 20  */
 21 public class HMM {
 22     /**
 23      * 隐藏状态名称列表——在获取最优隐藏状态序列时需要
 24      * 如enum Box {one, two, three}; // 隐藏状态(箱子编号)
 25      */
 26     public String[] state;
 27     /**
 28      * 观察状态名称列表——在根据观测索引获取获取观测序列时需要
 29      * enum Color {red, yellow, blue, green}; // 观察状态(观测到的颜色值)
 30      */
 31     public String[] syms;
 32     
 33     public int N;
 34     /**
 35      *  观测状态数 observed states
 36      *  观测状态名称叫syms
 37      */
 38     public int M;
 39     /**
 40      * 隐藏状态转移矩阵
 41      * logA[ i ][ j ] = log(P( i -> j )) 表示从i状态转移到 j 状态的概率——取自然对数
 42      */
 43     public double[][] logA;
 44     /**
 45      * 发射矩阵(混淆矩阵)
 46      * logB[ i ][Ot] = log(P(emit Ot in state i)) 表示状态 i 下发射出 Ot 的概率——Ot为第t时刻的显示序列单号
 47      */
 48     public double[][] logB;
 49     /**
 50      * 初始状态概率分布——每个隐藏状态发生的概率
 51      */
 52     public double[] logPI;
 53     
 54     /**
 55      * 观察到的序列
 56      */
 57     //public int[] O;//如yellow red blue yellow green 这些在enum Color {red,yellow,blue,green }的索引位置
 58     
 59     public HMM(){}
 60     
 61     public  HMM(int N, int M){
 62         this.N=N;
 63         this.M=M;
 64         this.logA=new double[N][N];
 65         this.logB=new double[N][M];
 66         this.logPI=new double[N];
 67         for(int i=0; i<N; i++){
 68             for(int j=0; j<N; j++){
 69                 this.logA[ i ][ j ] = Double.NEGATIVE_INFINITY;
 70             }
 71             for(int j=0; j<M; j++){
 72                 this.logB[ i ][ j ]=Double.NEGATIVE_INFINITY;
 73             }
 74             this.logPI[ i ] = Double.NEGATIVE_INFINITY;
 75         }
 76     }
 77     
 78     /**
 79      * (已经有具体HMM的各个参数情况下调用)
 80      * @param state隐藏状态名称
 81      *            enum Box {one,two,three }
 82      *  @param syms 观测状态名称
 83      *            enum Color {red,yellow,blue,green}
 84      * @param A
 85      *            隐藏状态的转移矩阵
 86      *                         1             2           3
 87      *                      one        two        three
 88      *           one  {0.500,   0.375,   0.125}
 89      *           two  {0.250,   0.125,   0.625},
 90      *           three{0.250,   0.375,   0.375}
 91      * @param B 从隐藏状态——观察状态的发射矩阵(混淆矩阵)
 92      *                            0        1         2        3
 93      *                          red yellow blue  green
 94      *            one     {0.60,  0.20,  0.15,  0.05},
 95      *            two     {0.25,  0.25,  0.25,  0.25},
 96      *            three  {0.05,  0.10,  0.35,  0.50}
 97      */
 98     public HMM(double[][] A, double[][] B, double[] PI){
 99         this.N=A.length;
100         this.M=B[0].length;
101         this.logA=new double[N][N];
102         this.logB=new double[N][M];
103         this.logPI=new double[N];
104         for(int i=0; i<N; i++){
105             for(int j=0; j<N; j++){
106                 this.logA[ i ][ j ] = Math.log( A[ i ][ j ] );
107             }
108             for(int j=0; j<M; j++){
109                 this.logB[ i ][ j ]=Math.log( B[ i ][ j ] );
110             }
111             this.logPI[ i ] = Math.log( PI[ i ] );
112         }
113     }
114     
115     /**
116      * 打印转移矩阵
117      */
118     public void printA() {
119         System.out.println("转移矩阵:");
120         for (int i = 1; i < N; i++) {
121             for (int j = 1; j < N; j++){
122                 System.out.print(HMMHelper.fmtlog(logA[i][j]));
123             }
124             System.out.println();
125         }
126     }
127 
128     /**
129      * 打印发射矩阵
130      */
131     public void printB() {
132         System.out.println("发射矩阵:");
133         for (int i = 1; i < N; i++) {
134             for (int j = 1; j < N; j++){
135                 System.out.print(HMMHelper.fmtlog(logB[i][j]));
136             }
137             System.out.println();
138         }
139     }
140     
141     
142 }

Forward类:

1 package jxutcm.edu.cn.hmm.model;
 2 
 3 import jxutcm.edu.cn.hmm.bean.HMMHelper;
 4 import jxutcm.edu.cn.util.TCMMath;
 5 
 6 /**
 7  * 前向算法:
 8  * 目的:
 9  * 1、先计算前向变量矩阵
10  * 2、再用前向变量矩阵 来 计算一个观测序列的概率
11  * @author aool
12  */
13 public class Forward extends HMM{
14     public int[] O;//观测序列observe//如yellow red blue yellow green 这些在enum Color {red,yellow,blue,green }的索引位置
15 
16     public double[][] alpha; //前向变量矩阵
17     
18     public Forward(double[][] A, double[][] B, double[] PI, int[] O){
19         super(A, B, PI);
20         this.O=O;
21     }
22     
23     /**
24      * 【计算前向变量矩阵】
25      * 在时间 t 的条件下,hmm输出观察序列O(1)O(2)...O(t)且该时间t下的隐藏状态为s_i(第i个隐藏状态,共N种隐藏状态)的概率
26      * alpha[ t ][ i ] = alpha_t( i ) = log(P(O(1)O(2)...O(t), q_t=s_i | λ))
27      */
28     public void CalculateForeMatrix(){
29         int T = O.length;
30         alpha = new double[ T ][ N ];//每一时刻(每行)上 可能出现的多个状态的发生的前向变量概率
31         //1、初始化,计算初始时刻(直觉上的第1时刻)所有状态的局部概率
32         for (int i = 0; i < N ; i++){
33             alpha[ 0 ][ i ] = logPI[ i ] + logB[ i ][ O[ 0 ] ];
34         }
35         //2、归纳,递归计算每个时间点的局部概率
36         for (int t = 1; t < T; t++){//从(直觉上的第2时刻)即t=1(下标从0开始)观测值算起——第时间t下开始循环
37             for (int i = 0; i < N; i++) {//在时间t下,对于每个状态s_i——计算到时间t+1的前向变量概率
38                 double sum = Double.NEGATIVE_INFINITY; // = log(0)
39                 for (int j = 0; j < N; j++){//到第 j 种隐状态下的累计概率
40                     sum = TCMMath.logplus( sum, alpha[t - 1][ j ] + logA[ j ][ i ]);
41                 }
42                 alpha[ t ][ i ] = logB[ i ][ O[ t ] ] + sum;//在 【t 时刻】 下 输出观察序列 O1O2……Ot(已知观测序列的局部) 且位于第 i 种隐藏状态发生的概率
43             }
44         }
45     }
46     
47     /**
48      * 【计算观测序列的概率】——前提是先计算前向变量矩阵
49      * P( O | μ ) = ∑alpha_T( i ) (求和上界N,求和下界i=1)
50      * @return 返回的结果是概率的自然对数
51      * 计算 t=T 时刻下输出观察序列 O0……OT(已经观测序列的局部)且位于第 T 状态下发生的概率
52      */
53     public double logProb() {
54         //3.终止,观察序列的概率等于最终时刻( T )所有局部概率之和
55         double sum = Double.NEGATIVE_INFINITY; // = log(0)
56         int T = O.length;
57         for (int i = 0; i < N; i++){
58             sum = TCMMath.logplus(sum, alpha[ T-1 ][ i ]);//下标从0开始
59         }
60         return sum;
61     }
62     
63     /**
64      * 打印前向变量矩阵
65      */
66     public void print() {
67         for (int j = 0; j < N; j++) {
68             for (int i = 0; i < alpha.length; i++){
69                 System.out.print(HMMHelper.fmtlog(alpha[ i ][ j ]));
70             }
71             System.out.println();
72         }
73     }
74 }

测试类:

1 package jxutcm.edu.cn.hmm.model;
 2 
 3 import jxutcm.edu.cn.hmm.bean.HMMHelper;
 4 
 5 public class Demo1 {
 6     enum Box {one, two, three}; // 隐藏状态(箱子编号)
 7     enum Color {red, yellow, blue, green}; // 观察状态(观测到的颜色值)
 8 
 9     public static void main(String[] args) {
10         test();
11     }
12 
13     public static void test() {
14         // 状态转移矩阵
15         double[][] A = { 
16                 { 0.500, 0.375, 0.125 }, 
17                 { 0.250, 0.125, 0.625 }, 
18                 { 0.250, 0.375, 0.375 } };
19         // 发射矩阵
20         double[][] B = { 
21                 { 0.60, 0.20, 0.15, 0.05 }, 
22                 { 0.25, 0.25, 0.25, 0.25 }, 
23                 { 0.05, 0.10, 0.35, 0.50 } };
24         
25           // 初始概率向量
26           double[] PI = { 0.63, 0.17, 0.20 };
27         
28         // 观察序列
29         int[] O = { Color.yellow.ordinal(), Color.red.ordinal(), Color.blue.ordinal(), Color.yellow.ordinal(),Color.green.ordinal() };
30         System.out.println("初始概率向量:{"+PI[0]+" "+PI[1]+" "+PI[2]+"}");
31         System.out.println("隐藏状态序列:{"+Box.one+" "+Box.two+" "+Box.three+"}");
32         System.out.println("观测序列:{"+Color.yellow+" "+Color.red+" "+Color.blue+" "+Color.yellow+" "+Color.green+"}");
33         
34         /**
35          * 前向算法测试——求解观察序列的概率
36          */
37         Forward foreward=new Forward(A, B, PI, O);
38         foreward.CalculateForeMatrix();//计算前向变量矩阵
39         System.out.println( HMMHelper.fmtlog( foreward.logProb() ) );//计算观测序列O的概率
40         
41         /**
42          * 后向算法测试

43          */
47    }
48 }

时间: 2024-10-26 05:33:41

隐马尔可夫模型的前向算法(java实现),今天奉上的相关文章

隐马尔科夫模型的维特比算法java实现,详细原理请自行查看52nlp的

/**     * [计算维特比矩阵]     * delta[ t ][ k ] = v_k(i) =log( max(P(pi in state k has sym i | path pi)) )     */    public void CalculateViterbiMatrix() {        int T = O.length;        delta = new double[ T ][N];        PSI = new int[ T ][N];        //1

隐马尔可夫模型学习小记——forward算法

首先是forward算法的Python实现: #-*-coding:utf-8-*- __author__ = 'ZhangHe' def forward(N,M,A,B,P,observed): p = 0.0 #观察到的状态数目 LEN = len(observed) #中间概率LEN*M Q = [([0]*N) for i in range(LEN)] #第一个观察到的状态,状态的初始概率乘上隐藏状态到观察状态的条件概率. for j in range(N): Q[0][j] = P[j

隐马尔可夫训练参数,BaumWelch算法,java实现【参考52nlp的博客算法原理实现】

package jxutcm.edu.cn.hmm.model; import jxutcm.edu.cn.hmm.bean.HMMHelper;import jxutcm.edu.cn.util.TCMMath; /** *  Baum-Welch算法也叫前向-后向算法: *  目的: *  1.在给定多个观测状态序列(多个观测序列,维数可不同)的条件下,训练和学习HMM模型的参数A,B,pi *  2.该算法得出的是一个局部最优解,较依赖于初始值 * @author aool */publi

马尔科夫链和隐马尔可夫模型(转载)

马尔可夫模型是由Andrei A. Markov于1913年提出的 ?? 设 SS是一个由有限个状态组成的集合 S={1,2,3,-,n?1,n}S={1,2,3,-,n?1,n} 随机序列 XX 在 tt时刻所处的状态为 qtqt,其中 qt∈Sqt∈S,若有: P(qt=j|qt?1=i,qt?2=k,?)=P(qt=j|qt?1=i)P(qt=j|qt?1=i,qt?2=k,?)=P(qt=j|qt?1=i) aij≥0∑jnaij=1aij≥0∑jnaij=1 则随机序列 XX构成一个一

机器学习——隐马尔可夫模型

目录: 隐马尔可夫模型 Viterbi算法(必须掌握) 简述:普通领域不常用,自然语言与金融领域用的比较多,总共涉及到概率问题,求参数问题,取范围问题. 用到的知识点有全概率公式,条件概率公式,边缘概率公式,贝叶斯公式,极大似然估计 概率计算问题 直接计算法 暴力算法 前向算法 后向算法  后向算法不作要求,原理与前向算法一样,只是方向不同,计算方法有些出入. 原文地址:https://www.cnblogs.com/qianchaomoon/p/12155876.html

隐马尔科夫模型学习笔记

隐马尔科夫模型在股票量化交易中有应用,最早我们找比特币交易模型了解到了这个概念,今天又看了一下<统计学习方法>里的隐马尔科夫模型一章. 隐马尔科夫模型从马尔科夫链的概念而来,马尔科夫链是指下一个状态只和当前的n个状态有关,和历史状态无关的一个时间上的事件链,隐马尔科夫模型在这个状态链的基础上,让每一个状态都能产生观测值,从而可以产生一个可观测的数据链,让原来的状态链变成了幕后产生数据的状态链,称为因马尔科夫链. 隐马尔科夫链应用比较广泛,主要能够处理三类问题:. 一个是给定了马尔科夫模型参数和

隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率

隐马尔科夫模型HMM(一)HMM模型 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数(TODO) 隐马尔科夫模型HMM(四)维特比算法解码隐藏状态序列(TODO) 在隐马尔科夫模型HMM(一)HMM模型中,我们讲到了HMM模型的基础知识和HMM的三个基本问题,本篇我们就关注于HMM第一个基本问题的解决方法,即已知模型和观测序列,求观测序列出现的概率. 1. 回顾HMM问题一:求观测序列的概率 首先我们回顾下HMM模型的问题一.这个

隐马尔可夫模型(七)——隐马尔可夫模型的学习问题(前向后向算法)(转载)

隐马尔可夫模型的学习问题:给定一个输出序列O=O1O2...OT,如何调节模型μ=(A,B,π)的参数,使得P(O|M)最大. 最大似然估计是一种解决方法,如果产生的状态序列为Q=q1q2...qT,根据最大似然估计,可以通过以下公式推算: πi' = δ(q1,si) aij' =  Q中从状态qi转移到qj的次数/Q中从状态qi转移到另一状态(包括qj)的次数 bj(k)' = Q中从状态qj发出符号Vk的次数/ Q中到达状态qj的次数 δ(x,y)为克罗奈克函数,当x=y时,δ(x,y)=

机器学习算法总结(七)——隐马尔科夫模型(前向后向算法、鲍姆-韦尔奇算法、维特比算法)

概率图模型是一类用图来表达变量相关关系的概率模型.它以图为表示工具,最常见的是用一个结点表示一个或一组随机变量,结点之间的变表是变量间的概率相关关系.根据边的性质不同,可以将概率图模型分为两类:一类是使用有向无环图表示变量间的依赖关系,称为有向图模型或贝叶斯网:另一类是使用无向图表示变量间的相关关系,称为无向图模型或马尔科夫网. 隐马尔科夫模型(简称HMM)是结构最简单的动态贝叶斯网,是一种著名的有向图模型,主要用于时间序数据建模,在语音识别,自然语言处理,生物信息,模式识别中有着广泛的应用,虽