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();
}
时间: 2024-10-14 00:13:09

HMM的学习笔记1:前向算法的相关文章

机器学习---HMM模型学习笔记

HMM算法想必大家已经听说了好多次了,完全看公式一头雾水.但是HMM的基本理论其实很简单.因为HMM是马尔科夫链中的一种,只是它的状态不能直接被观察到,但是可以通过观察向量间接的反映出来,即每一个观察向量由一个具有相应概率密度分布的状态序列产生,又由于每一个状态也是随机分布的,所以HMM是一个双重随机过程. HMM是语音识别,人体行为识别,文字识别等领域应用非常广泛. 一个HMM模型可以用5个元素来描述,包过2个状态集合和3个概率矩阵.其分别为 隐含状态S,可观测状态O,初始状态概率矩阵π,隐含

【视频编解码&#183;学习笔记】8. 熵编码算法:基本算法列举 &amp; 指数哥伦布编码

一.H.264中的熵编码基本方法: 熵编码具有消除数据之间统计冗余的功能,在编码端作为最后一道工序,将语法元素写入输出码流 熵解码作为解码过程的第一步,将码流解析出语法元素供后续步骤重建图像使用 在H.264的标准协议中,不同的语法元素指定了不同的熵编码方法.在协议文档中共指定了10种语法元素的描述符,这些描述符表达了码流解析为语法元素值的方法,其中包含了H.264标准所支持的所有熵编码方法: 语法元素描述符 编码方法 b(8) 8位二进制比特位串,用于描述rbsp_byte() f(n) n位

《机器学习实战》学习笔记:k-近邻算法实现

上一学期主要的学习和研究任务是模式识别.信号理论和图像处理,实际上这些领域都与机器学习有或多或少的交集.因此,仍在继续深入阅读<机器学习>.观看斯坦福大学的机器学习课程.在此过程中因为未来课题组项目的要求,需要接触Python,因此选择了<机器学习实战>这本书,同时参考教材和视频一起学习.事实上该书的理论研究不够深入,只能算是练习Python并验证一些著名的机器学习算法的工具书了. 在介绍k-近邻算法之前,对机器学习算法进行简单的分类和梳理:简单来说,机器学习主要分为两大类,有监督

《机器学习实战》学习笔记一K邻近算法

 一. K邻近算法思想:存在一个样本数据集合,称为训练样本集,并且每个数据都存在标签,即我们知道样本集中每一数据(这里的数据是一组数据,可以是n维向量)与所属分类的对应关系.输入没有标签的新数据后,将新数据的每个特征(向量的每个元素)与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似的的分类标签.由于样本集可以很大,我们选取前k个最相似数据,然后统计k个数据中出现频率最高的标签为新数据的标签. K邻近算法的一般流程: (1)收集数据:可以是本地数据,也可以从网页抓取. (2)准备数

【算法学习笔记】33.在线算法 SJTU OJ 1006 求和游戏

1006. 求和游戏 Description 石柱上有一排石头键盘,每个键上有一个整数.请你在键盘上选择两个键,使这两个键及其之间的键上的数字和最大.如果这个最大的和不为正,则输出“Game Over". Input Format 第1行:键的个数n. 第2..n+1行:键上的数字整数 ai. −100≤ai≤100 对于70%的数据,2≤n≤1,000 对于100%的数据,2≤n≤1,000,000 Output Format 一行,最大和或者”Game Over". Sample

STL学习笔记(非变动性算法)

辅助函数 本节跟以后几节将对所有STL算法逐一详细讨论.为了简化这些例子,我们使用了一些辅助函数,分别用于对容器进行输出跟插入操作. for_each()算法 for_each()算法非常灵活,它可以以不同的方式存取.处理.修改每一个元素 UnaryProc for_each(InputIterator beg,InputIterator end,UnaryProc op); 1.对与区间[beg,end)中的每一个元素调用:op(elem) 2.返回op(已在算法内部被变动过)的一个副本 3.

Spring学习笔记-AOP前传之动态代理

假设有如下需求: 写一个计算器类,里面包含加减乘除四个方法.在每个方法开始前打印出该方法开始的消息,在每个方法结束前打印出该方法结束的消息和计算的结果. 普通方法,先写一个借口,然后在接口里实现四个方法.在每个方法里加上要打印的语句.实现代码如下. ArithmeticCalculator接口 package com.spring.aop.helloworld; public interface ArithmeticCalculator { int add(int i, int j); int 

【算法学习笔记】-二分查找算法

二分搜索是一种常用的搜索方法,它要求数组中的元素必须是有序存放的.不失一般性,我们假定数组元素按升序存放.二分搜索方法首先将关键字与位于数组中央的元素进行比较,比较结果有三种情况: 1)如果关键字小于中央元素,我们只需要继续在数组的前半部分进行搜索. 2)如果关键字与中央元素相等,则搜索结束,找到匹配元素. 3)如果关键字大于中央元素,我们只需要继续在数组的后半部分进行搜索. 二分搜索的代码如下: #include <iostream> using namespace std; int bin

(转)《深入理解java虚拟机》学习笔记3——垃圾回收算法

Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构确定下来时就已知的,因此这三个区域的内存分配和回收都具有确定性.垃圾回收重点关注的是堆和方法区部分的内存. 常用的垃圾回收算法有: (1).引用计数算法: 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不再被使用的,垃