1. 程式人生 > >HMM條件下的 前向算法 和 維特比解碼

HMM條件下的 前向算法 和 維特比解碼

popu max trac ble -s 序列 最大 可能 content

一、隱馬爾科夫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條件下的 前向算法 和 維特比解碼