HMM的学习笔记1:前向算法

HMM的学习笔记

HMM是关于时序的概率模型。描写叙述由一个隐藏的马尔科夫链随机生成不可观測的状态随机序列,再由各个状态生成不可观測的状态随机序列,再由各个状态生成一个观測而产生观測的随机过程。

HMM由两个状态和三个集合构成。他们各自是观測状态序列。隐藏状态序列。转移概率,初始概率和混淆矩阵(观察值概率矩阵)。

HMM三个如果

1、有限历史性如果,p(si|si-1,si-2,...,s1) = p(si|si-1)

2、齐次性如果,(状态与详细时间无关)。P(si+1|si)=p(sj+1,sj)

3、输出独立性如果,输出仅与当前状态有关。P(o1,...ot|s1,...st) = P(ot|qt)

HMM须要解决三个问题:

1:评估问题,也就是给定一个观測序列。求它的概率。

2:解码问题,通过维特比算法来做解码,求概率最大的隐藏概率;

3:学习问题,通过观測序列求參数。

如今针对第一个评估问题,通常我们採用前项算法来计算观測序列的概率;



为了解决这个时间复杂度比价高的问题,首先定义一个前向变量,便是从1到t,输出符号O序列,t时刻处于状态i的累计输出概率。


这里每一次的at(i)。我们是通过at(ij-1)来计算的,这样避免了反复计算。

 状态转移概率矩阵


混淆概率矩阵

另一个初始概率矩阵我们设为(1,0, 0)吧。

有了他们我们就能够计算at(i)。

 

这个过程说白了就是从某个点開始。几次计算到下一个点的概率。然后累加到下一个点上去。这里要注意的一点是初始的那个点计算,仅仅是初始矩阵和混淆矩阵的运算(不涉及转移的过程)。

代码实现了一下前项算法:

和我们手工的计算一样

 

int get_index(char sz)
{
	if ( 'a' == sz)
	{
		return 0;
	} 
	else
	{
		return 1;
	}
}

void testa()
{
	ifstream in_a("A.txt");

	double start[3] = {1, 0, 0};
	double A[3][3] = {0};
	double B[3][2] = {0};
	double C[3][4] = {0};
	char sz_array[] = "abab";
	int i, j, k;

	double (*p)[3];
	(p) = A;

	int row, col;
	in_a >> row >> col;
	for (i = 0; i < row; ++i)
	{
		for (j = 0; j < col; ++j)
		{
			in_a >> A[i][j];
		}
	}

	in_a >> row >> col;
	for (i = 0; i < row; ++i)
	{
		for (j = 0; j < col; ++j)
		{
			in_a >> B[i][j];
		}
	}

	in_a >> row >> col;
	for (i = 0; i < 3; ++i)
	{
		for (j = 0; j < 4; ++j)
		{
			in_a >> C[i][j];
		}
	}

	//
	// 初始化
	//
	for (i = 0; i < 3; ++i)
	{
		C[i][0] = B[i][get_index(sz_array[0])] * start[i];
	}

	for (i = 1; i < 4; ++i)
	{
		for (j = 0; j < 3; ++j)
		{
			for (k = 0; k < 3; ++k)
			{
				C[k][i] += C[j][i-1] * A[j][k] * B[k][get_index(sz_array[i])];
			}
		}
	}

	for (int m = 0; m < 3; ++m)
	{
		for (int n = 0; n < 4; ++n)
		{
			cout << C[m][n] << " ";
		}

		cout << endl;
	}

	in_a.close();
}

原文地址:https://www.cnblogs.com/mfrbuaa/p/5237838.html