HMM條件下的 前向算法 和 維特比解碼
一、隱馬爾科夫HMM如果:
有且僅僅有3種天氣:0晴天。1陰天。2雨天
各種天氣間的隔天轉化概率mp:
mp[3][3] | 晴天 | 陰天 | 雨天 |
晴天 | 0.33333 | 0.33333 | 0.33333 |
陰天 | 0.33333 | 0.33333 | 0.33333 |
雨天 | 0.33333 | 0.33333 | 0.33333 |
有2種活動: 0去公園,1不去公園
各種天氣下進行各種活動的概率:
w2a[3][2] | 去公園 | 不去公園 |
晴天 | 0.75 | 0.25 |
陰天 | 0.4 | 0.6 |
雨天 | 0.25 | 0.75 |
觀察5天的活動序列:0 0 1 0 1 ;(0去公園,1不去公園)
5天的動作觀察序列 O[5] | ||||
1天 | 2天 | 3天 | 4天 | 5天 |
去公園 | 去公園 | 不去 | 去公園 | 不去 |
0 | 0 | 1 | 0 | 1 |
第0天的天氣概率pi:
pi[3] | 第0天天氣概率 |
晴天 | 0.5 |
陰天 | 0.3 |
雨天 | 0.2 |
定義幾個宏及變量表示HMM:
#define T 5 //觀察N天 #define M 3 //每天可能有M種天氣 #define N 2 //動作種類。去公園+不去公園 float mp[M][M]; //相鄰兩天的天氣轉換概率 float w2a[M][N]; //weather to action,各天氣下採取各動作的概率 int O[T]; //N天觀察到的天氣序列 int bestPath[T][M];//bestPath[t][i]表示 (第t天處於第i種天氣狀態且出現“O0-Ot”觀察序列的概率最大的)路徑在時間t-1時刻的天氣狀態 float pi[M]; //一個M維向量,表示第一天各種天氣出現的概率
二、前向算法--出現觀察動作序列的概率
即求出現:“1去公園,2去公園,3不去公園,4去公園,5不去公園” 動作序列的概率。
這是一個求和問題。用DP思想的前向算法解決。
1、構造矩陣float sumP[T][M];
sumP[t][i]表示:在時間t,處於天氣i,且出現觀察動作序列O0-Ot的概率
2、填表求解過程:
//初始表 for(i=0; i<M; i++) { sumP[0][i] = pi[i]*w2a[ i ][ O[0] ]; } //填表 for(t=1; t<T; t++) { for (i=0; i<M; i++) { sumP[t][i]=0; for (j=0; j<M; j++) { sumP[t][i] += sumP[t-1][j]*mp[j][i]*w2a[ i ][ O[t] ]; } } }求觀察序列出現概率:
float sumPP=0; for(i=1;i<M;i++) { sumPP += sumP[T-1][i]; } cout<<"使用前向算法算出,觀察序列的出現概率為"<<sumPP<<endl;
三、維特比解碼-哪種天氣下出現觀察動作序列的概率最大
在哪種天氣序列下,出現觀察序列的概率最大,並求 (出現該天氣序列和觀察動作序列事件)的最大概率。
這是最優化問題,DP思想求最大,採用維特比解碼
1、構造矩陣maxP[T][M]
maxP[t][j], 算出第t天處於第i狀態且出現觀察序列O0~Ot的路徑中,(出現天氣路徑和觀察路徑)概率最大的路徑的概率。
bestPath[t][i],表示是第t天,天氣狀態為i狀態出現觀察序列O0~Ot的最大概率路徑下(即取得maxP[t][i])。第t-1天的天氣狀態。
2、填表過程:
//初始表 float maxpp=0; int maxPre=0; for(i=0;i<M;i++) { maxP[0][i] = pi[i]*w2a[ i ][ O[0] ]; if(maxP[0][i]>maxpp) { bestPath[0][i]=-1; maxpp=maxP[0][i]; } } //後填表 for(t=1;t<T;t++) //每一天 { for(i=0;i<M;i++)//maxP[t][j],要算出第t天處於第i狀態且出現觀察序列O0~Ot的路徑中,(出現天氣路徑和觀察路徑)概率最大的路徑的概率 { maxpp=0; maxPre=0; for(j=0;j<M;j++)//第t-1天,天氣為第j狀態 { float temp = maxP[t-1][j]*mp[j][i]*w2a[i][O[t]]; if(temp > maxpp) { maxpp = temp; maxPre = j; } } maxP[t][i] = maxpp; bestPath[t][i] = maxPre; } }
輸出最大概率及其天氣路徑:
float maxEndP=0; int lastChoice; for(i=0; i<M; i++) { if(maxP[T-1][i] > maxEndP) { maxEndP = maxP[T-1][i]; lastChoice = i; } } cout<<"最大的概率為:"<<maxEndP<<endl; cout<<"全部路徑中,出現觀察序列概率的最大的天氣路徑為:"<<endl; cout<<lastChoice<<" "; for(t=T-1; t>0; t--) { cout<<bestPath[t][lastChoice]<<" "; lastChoice = bestPath[t][lastChoice]; } cout<<endl;
四、代碼:
#include<iostream> using namespace std; #define T 5 //觀察N天 #define M 3 //每天可能有M種天氣 #define N 2 //動作種類,去公園+不去公園 float mp[M][M]; //相鄰兩天的天氣轉換概率 float w2a[M][N]; //weather to action,各天氣下採取各動作的概率 int O[T]; //N天觀察到的天氣序列 int bestPath[T][M];//bestPath[t][i]表示 (第t天處於第i種天氣狀態且出現“O0-Ot”觀察序列的概率最大的)路徑在時間t-1時刻的天氣狀態 float pi[M]; //一個M維向量,表示第一天各種天氣出現的概率,【通常包括一個1,其余為0】 void initHMM() { int i,j,k; //輸入天氣轉移概率 for(i=0; i<M; i++) { for(j=0;j<M;j++) { cin>>mp[i][j]; } } //輸入各天氣下,採取不同動作的概率 for(i=0; i<M; i++) { for(j=0; j<N; j++) { cin>>w2a[i][j]; } } //輸入pi for(i=0; i<M; i++) { cin>>pi[i]; } //輸入觀察序列 for(i=0; i<T; i++) { cin>>O[i]; } } /*維特比算法 已知HMM模型,轉移概率(天氣轉換概率),初始狀態(第0天的天氣或天氣概率),各天氣下採取各動作的概率。觀察序列(動作序列) 1.求出(使觀察序列出現概率最大的)天氣路徑, 即在那種天氣序列下。出現觀察序列的概率最大 2.求出 (出現天氣路徑且出現觀察序列的事件)的最大概率 這是一種最優化問題,求最大,DP思想 */ float viterbi() { float maxP[T][M]; int i,j,t; //初始表 float maxpp=0; int maxPre=0; for(i=0;i<M;i++) { maxP[0][i] = pi[i]*w2a[ i ][ O[0] ]; if(maxP[0][i]>maxpp) { bestPath[0][i]=-1; maxpp=maxP[0][i]; } } //後填表 for(t=1;t<T;t++) //每一天 { for(i=0;i<M;i++)//maxP[t][j],要算出第t天處於第i狀態且出現觀察序列O0~Ot的路徑中。(出現天氣路徑和觀察路徑)概率最大的路徑的概率 { maxpp=0; maxPre=0; for(j=0;j<M;j++)//第t-1天,天氣為第j狀態 { float temp = maxP[t-1][j]*mp[j][i]*w2a[i][O[t]]; if(temp > maxpp) { maxpp = temp; maxPre = j; } } maxP[t][i] = maxpp; bestPath[t][i] = maxPre; } } float maxEndP=0; int lastChoice; for(i=0; i<M; i++) { if(maxP[T-1][i] > maxEndP) { maxEndP = maxP[T-1][i]; lastChoice = i; } } cout<<"最大的概率為:"<<maxEndP<<endl; cout<<"全部路徑中,出現觀察序列概率的最大的天氣路徑(逆序)為:"<<endl; cout<<lastChoice<<" "; for(t=T-1; t>0; t--) { cout<<bestPath[t][lastChoice]<<" "; lastChoice = bestPath[t][lastChoice]; } cout<<endl; return maxEndP; } /* 前向算法 已知HMM模型,轉移概率(天氣轉換概率)。初始狀態(第0天的天氣或天氣概率)。各天氣下採取各動作的概率,觀察序列(動作序列) 1.求出觀察序列出現的概率為多大 即,在給定的初始天氣,轉移天氣概率。及天氣動作概率的條件下。出現觀察到的動作概率是多少 這是一個加法求和問題,DP思想 */ void forward() { float sumP[T][M]; //sumP[t][i]表示:在時間t。處於天氣i,且出現觀察動作序列O0-Ot的概率 int t,i,j,k; //初始表 for(i=0; i<M; i++) { sumP[0][i] = pi[i]*w2a[ i ][ O[0] ]; } //填表 for(t=1; t<T; t++) { for (i=0; i<M; i++) { sumP[t][i]=0; for (j=0; j<M; j++) { sumP[t][i] += sumP[t-1][j]*mp[j][i]*w2a[ i ][ O[t] ]; } } } float sumPP=0; for(i=1;i<M;i++) { sumPP += sumP[T-1][i]; } cout<<"使用前向算法算出。觀察序列的出現概率為"<<sumPP<<endl; } int main() { initHMM(); viterbi(); forward(); system("pause"); } /* 0.33333 0.33333 0.33333 0.33333 0.33333 0.33333 0.33333 0.33333 0.33333 0.75 0.25 0.4 0.6 0.25 0.75 0.5 0.3 0.2 0 0 1 0 1 */
五、執行結果:
0.33333 0.33333 0.33333
0.33333 0.33333 0.33333
0.33333 0.33333 0.33333
0.75 0.25
0.4 0.6
0.25 0.75
0.5 0.3 0.2
0 0 1 0 1
最大的概率為:0.00146479
全部路徑中,出現觀察序列概率的最大的天氣路徑為:
2 0 2 0 0
使用前向算法算出,觀察序列的出現概率為0.0284842
HMM條件下的 前向算法 和 維特比解碼