news 2026/10/27 2:19:26

从模式识别到隐马尔可夫模型:序列建模与转移概率矩阵解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从模式识别到隐马尔可夫模型:序列建模与转移概率矩阵解析

简介:这份模式识别主题课件面向模式识别、机器学习与人工智能方向的初学者及课程复习者,重点梳理隐马尔可夫模型相关知识,帮助读者建立从马尔可夫性、马尔科夫链到HMM应用的系统理解。压缩包内共1个PPT文件,整体约5.79MB,以讲义式页面组织概念、公式、转移概率矩阵示例及HMM经典抽球实验,便于课堂演示或自学翻阅。内容覆盖马尔科夫链与马尔科夫过程、齐次链转移概率矩阵、隐马尔可夫模型的状态与观察值、转移概率和观察值概率,并延伸到语音识别、图像识别、自然语言处理与生物信息学等应用场景。已有1592人学习,适合快速抓取HMM核心概念、对照实例理解双重随机过程,并为后续算法推导和课程作业提供线索。

1. 模式识别到底在识别什么:从“看一眼就认出来”说起

早上出门扫一眼天色,你大概能判断要不要带伞;听到楼道里的脚步声,你能分辨是不是同屋的人回来了;手机相册几千张照片,它自己就能按人脸归成一堆。这些事人做起来毫不费力,换成机器却难得多。模式识别要解决的就是这件事:让机器从数据里找出规律,再依据规律判断新数据属于哪一类、对应哪种情况。这里的“模式”并不神秘,可以是一张图的纹理、一段语音的波形,也可以是一串按时间排好的观测值。搞懂它的价值在于,许多看起来“机器怎么可能做到”的事情,拆开看都是同一套思路。这份资料着重讲的是其中专门处理序列的一支:马尔可夫模型与隐马尔可夫模型。

2. 马尔可夫性:为什么“将来只依赖现在”

2.1 一句话说清马尔可夫性

如果一件事的“将来”只和“现在”有关,和“过去”怎么走到现在无关,我们就说这个过程具有马尔可夫性,也叫无后效性。用一句公式写出来就是 X(t+1) = f(X(t)):下一时刻的状态,是当前状态的函数。

打个比方,下班开车回家选路线。你今天走哪条路,主要取决于此刻车在哪个路口、当前哪条路堵,而不需要把过去一周每天走过的路线在脑子里重放一遍。当前路口就是“现在”,过去一周的行车记录就是“过去”,路况判断只用到“现在”,这就是马尔可夫性的味道。

反过来说,什么事情不满足它?累计得分是个典型:一支球队本赛季的总积分,等于过去每一场得分之和,光看“当前积分”没法知道下一场之后变成多少,必须把历史累加进来。再比如一段长文本的语义,往往要回看很远的前文,这也不符合“只看现在”的假设。

这个假设之所以重要,是因为它把问题变小了。一个系统可能有成千上万种历史组合,如果每种历史都要记住,模型会大到没法算;只保留“当前处于什么状态”,参数量就压下来了,工程上才算得动。

提示:无后效性是一种建模假设,不是对世界的断言。现实里的过程多少带点历史惯性,假设它成立,换来的是可计算性。

2.2 马尔可夫链:把时间和状态都切成格子

把马尔可夫性放到离散场景里,就得到马尔可夫链。它要求两件事都离散:时间是一格一格的(第 0 步、第 1 步、第 2 步……),状态也是可数的(晴、阴、雨,或者状态 a1、a2、a3……)。把相继观察的结果记成 {Xn = X(n), n = 0,1,2,…},状态空间记作 I = {a1, a2, …}。

核心参数是转移概率:Pij(m, m+n) = P{Xm+n = aj | Xm = ai},意思是“在时刻 m 处于状态 ai 的条件下,到时刻 m+n 转移到状态 aj 的概率”。竖线后面是条件,读作“已知”。

拿天气做例子,状态只有三个:晴天、阴天、下雨。根据历史统计,可以得到一张一步转移表:

从 \ 到晴天阴天下雨
晴天0.500.250.25
阴天0.3750.250.375
下雨0.250.1250.625

读法是:如果今天是晴天,明天仍是晴天的概率是 0.50,转阴天 0.25,转下雨 0.25。三列加起来正好是 1,因为明天总要落在三种天气之一。这不是巧合,而是转移概率的硬性约束:从任何一个状态出发,转移到所有可能状态的 Ham 概率之和必须为 1。

当 Pij(m, m+n) 与起始时刻 m 无关时,这条链叫齐次马尔可夫链。通俗地说,就是“转移规则不随日期变化”,今天从晴天转阴天的概率,和下个月从晴天转阴天的概率一样。平时说马尔可夫链,默认都是齐次的,否则每个时刻都要单独估一套参数,数据根本不够用。

2.3 转移概率矩阵:一张表把“下一步”写清楚

把上面的表写成矩阵,就是转移概率矩阵 A。第 i 行第 j 列的元素 A[i][j] 表示从状态 i 转到状态 j 的概率。它有两个必须满足的性质:每个元素都在 0 到 1 之间;每一行的和等于 1。

有了矩阵,就可以做模拟。下面这段代码按转移矩阵生成一条天气序列:

import random # 状态顺序固定为:0=晴,1=阴,2=雨 states = ["晴", "阴", "雨"] # 转移概率矩阵:第 i 行第 j 列 = 从状态 i 转到状态 j 的概率 A = [ [0.500, 0.250, 0.250], [0.375, 0.250, 0.375], [0.250, 0.125, 0.625], ] def next_state(current): r = random.random() # 生成 [0, 1) 之间的随机数 acc = 0.0 for j, p in enumerate(A[current]): acc += p # 按行累加,看随机数落在哪个区间 if r < acc: return j return len(A[current]) - 1 # 浮点误差兜底,返回最后一个状态 random.seed(7) # 固定随机种子,保证每次运行结果一致 cur = 0 # 从晴天开始 path = [states[cur]] for _ in range(9): cur = next_state(cur) path.append(states[cur]) print(" -> ".join(path))

这段代码做了一件很朴素的事:生成一个 0 到 1 的随机数,按行内概率累加,随机数落在哪个区间就跳到哪个状态。A是转移矩阵,改它就能改系统的“性格”;random.seed只是让结果可复现,实际使用中可以去掉;current是当前状态的下标,必须是 0 到 2 之间的整数。

如果要算“从晴天出发,三步之后是雨天的概率”,不用模拟,直接做矩阵乘法:A 的三次方,取第 0 行第 2 列。n 步转移概率就是 A 的 n 次幂,这是马尔可夫链最实用的性质之一。模拟一千次取频率也能得到近似值,但矩阵乘法给的是精确值。

注意:改矩阵时一定要重新检查每行是否仍然等于 1。手工调参最常见的翻车,就是改了某个元素忘了配平同行其他元素,结果概率凭空多出来或者少掉一块。

3. 隐马尔可夫模型:看不见的状态怎么被“猜”出来

3.1 “隐”在哪里:状态不直接露脸

马尔可夫链有个前提,状态是能直接看到的:晴天就是晴天,你抬头就知道。可现实里大量场景不是这样。你在屋里听到外面有动静,能判断大概在下雨,但“雨下得多大”这个状态本身你并没有直接测量,你测到的是声音、湿度、窗户上的水痕。

隐马尔可夫模型(HMM)处理的正是这类问题:状态不确定或者不可见,只能通过一个观测序列的随机过程表现出来。观察到的事件和状态之间不是一一对应,而是靠一组概率分布联系。换句话说,你看到的每一个观测值,都只是状态发出的“信号”,信号有概率偏差,不能反推得那么干脆。

这份资料里反复强调的一句话是:HMM 的状态是不确定或不可见的。注意“不确定”和“不可见”是两个层面,前者是说哪怕理论上能看到,你也没测准;后者是说这个状态压根不在观测里。两种情况下,能拿到手的都只有观测序列。

举个日常例子。假设有个朋友每天的活动只有三类:散步、购物、打扫。他的活动受天气影响:晴天更可能散步,雨天更可能打扫,但晴天也可能打扫,雨天也可能硬着头皮购物。你不在他身边,只能看到他每天发了什么动态,想据此推断这周有几天晴、几天雨。天气就是隐藏状态,动态就是观测值,这就是一个标准的 HMM 场景。

3.2 缸和彩球的实验:一个能动手推演的 HMM

资料里用了一个很经典的实验来把 HMM 讲具体。设有 N 个缸,每个缸里装有很多彩球,球的颜色由一组概率分布描述——也就是每个缸里红球、蓝球、绿球的比例不同。实验这样进行:

先根据初始概率分布,随机选中 N 个缸中的一个开始;然后根据这个缸里球颜色的概率分布,随机摸一个球,记下颜色 O1,再把球放回缸中;接着根据缸与缸之间的转移概率分布,随机选择下一口缸,重复摸球、记录、换缸的过程。最后得到一个颜色序列 O1, O2, …,称为观察值序列 O。

这个实验的精髓在于三条约束。第一,缸间的转移不能被直接观察,你只看见球的颜色,看不见实验者的手伸进了哪口缸。第二,从缸中选出的球的颜色和缸并不是一一对应的,同一个颜色的球可能在好几个缸里都有,只是比例不同。第三,每次选哪口缸由一组转移概率决定,不是随意乱换,也不是固定不动。

把这三条翻译成建模语言:缸是隐藏状态,球的颜色是观测值,缸之间的切换由马尔可夫链描述,缸内颜色分布由观测概率描述。你可以拿三个缸、两种颜色、一张 3×3 的转移表,手算一条长度为 3 的观测序列出现的概率,算完会对“双重随机”有完全不同的体感。

提示:手算一次比看十遍定义管用。哪怕只算两条路径,也能立刻明白为什么观测序列的概率要把所有可能的状态路径都累加进去。

3.3 双重随机过程:一条链管状态,一条链管观测

HMM 之所以叫“双重随机过程”,是因为它内部同时跑着两个随机机制。第一个是马尔可夫链,描述状态的转移,用转移概率描述;第二个是一般随机过程,描述状态与观察序列之间的关系,用观察值概率描述。前者决定“内部怎么变”,后者决定“内部状态怎么表现成你能看到的东西”。

完整的 HMM 用一组参数来刻画,通常记作 λ = (N, M, π, A, B)。N 是状态数,M 是每个状态可能产生的观测值个数,π 是初始状态概率分布,A 是状态转移概率矩阵,B 是观测值概率矩阵。这五个符号在资料里会反复出现,先把它们认全,后面读公式会顺很多。

围绕这组参数,有三个基本问题:给定模型和观测序列,怎么算这条序列出现的概率(评估);给定模型和观测序列,怎么反推最可能的状态序列(解码);给定观测序列,怎么把模型参数估出来(学习)。这三个问题分别对应不同的算法,也是这份资料后面展开的主线。评估和解码是“用模型”,学习是“建模型”,顺序不能颠倒着理解。

4. 转移概率矩阵与观察值概率:两个矩阵撑起一个模型

4.1 A 矩阵:状态怎么走

A 矩阵就是第 2 章讲的转移概率矩阵,只不过在 HMM 里它描述的是隐藏状态的转移。它的每一行对应一个状态,每一列对应该状态下一步可能去往的状态,行和为 1。

以三个隐藏状态为例,A 可以长这样:

从 \ 到状态 1状态 2状态 3
状态 10.60.30.1
状态 20.30.40.3
状态 30.20.30.5

读法和天气矩阵一样:从状态 1 出发,下一步留在状态 1 的概率是 0.6,去状态 2 是 0.3,去状态 3 是 0.1。A 决定了隐藏状态序列的“形状”,比如状态 3 的对角线元素是 0.5,说明它比较“黏”,一旦进去就不太容易出来。

A 矩阵的估计通常来自带标注的数据,或者用学习算法从观测序列里迭代出来。它的规模是 N×N,N 一般不会太大,因为状态数每增加一个,参数量是平方级增长的,数据不够就会估得很飘。

4.2 B 矩阵:状态怎么“说话”

如果只有 A,模型只知道自己内部怎么转,外界什么也看不到。B 矩阵负责把隐藏状态翻译成观测值:第 i 行第 k 列的元素,表示处于状态 i 时产生观测值 k 的概率。

还是用朋友的活动举例,假设状态是晴、阴、雨,观测值是散步、购物:

状态 \ 观测散步购物
晴0.70.3
阴0.40.6
雨0.20.8

这张表说明:晴天更可能散步,雨天更可能购物,但没有哪个状态是“只能”对应某个观测的。这正是 3.2 节那条约束的数值化表达——观测值和状态不是一一对应,而是概率对应。也正因为如此,看到“购物”不能立刻断定是雨天,还要结合转移概率和整条序列一起看。

B 矩阵的规模是 N×M。M 是观测值种类数,在语音里可能是几十个音素,在文本里可能是几千个词,M 一大,B 就变得很宽,参数估计也更吃数据。

4.3 π 与齐次性:起点和规则

π 是初始状态概率分布,长度等于 N,加起来等于 1。它回答的是“序列开始时,系统最可能处在哪个状态”。如果观测序列很短,π 的影响会很明显;序列一长,前面的初始影响会被转移过程逐渐稀释。

把这几个参数放在一起,就是一张完整的参数表:

符号含义形状与约束
N隐藏状态个数正整数
M每个状态可产生的观测值个数正整数
π初始状态概率长度 N,和为 1
A状态转移概率N×N,每行和为 1
B观测值概率N×M,每行和为 1

齐次性在这里的含义是:A、B、π 都不随时刻变化。为什么通常这么假设?一是参数少、估得动;二是有现成的学习算法可以迭代收敛;三是很多实际过程的统计规律在观察窗口内确实变化不大。如果规律明显随时间漂移,比如设备从新到旧的退化过程,那就要分段建模,或者把时间因素显式加进去,不能再套一个固定的 A。

下面这段代码用一个迷你 HMM,穷举所有状态路径来算一条观测序列的概率:

import itertools states = ["晴", "阴", "雨"] obs = ["散步", "购物"] pi = [0.4, 0.3, 0.3] # 初始状态概率 A = [[0.6, 0.3, 0.1], [0.3, 0.4, 0.3], [0.2, 0.3, 0.5]] # 状态转移矩阵 B = [[0.7, 0.3], [0.4, 0.6], [0.2, 0.8]] # 各状态下产生观测值的概率 def prob_of(seq): total = 0.0 # 枚举所有可能的状态路径,长度为序列长度 for path in itertools.product(range(3), repeat=len(seq)): p = pi[path[0]] * B[path[0]][obs.index(seq[0])] for t in range(1, len(seq)): p *= A[path[t - 1]][path[t]] * B[path[t]][obs.index(seq[t])] total += p return total print(prob_of(["散步", "购物", "散步"]))

这段代码把“所有可能的状态路径”都列出来,每条路径算一个概率,最后累加。pi管起点,A管状态之间的跳转,B管每个状态发出观测值的概率,obs.index把观测值名字换成矩阵列下标。逻辑很直白,但复杂度是指数级的:路径数是 N 的 T 次方,T 稍微长一点就算不动。这正是后面要引入前向算法的原因,它用递推把这笔账从指数级压到平方级。改参数时只要保证 π 和为 1、A 每行和为 1、B 每行和为 1,结果就仍然是一个合法概率。

5. 常见误区与易混概念:别把三个东西混成一锅

5.1 误区一:马尔可夫链和隐马尔可夫模型是一回事

易混点:两个名字里都有“马尔可夫”,教材又常把它们放在同一章,很容易读成“同一个东西的两种叫法”。

为什么混:HMM 内部确实包含一条马尔可夫链,描述隐藏状态的转移,所以从结构上看,说“HMM 里有个马尔可夫链”没错。但反过来把 HMM 叫成马尔可夫链,就丢掉了最关键的一半。

怎么区分:问一句“状态能不能直接看到”。马尔可夫链的状态直接可见,观测就是状态本身,转移矩阵 A 一乘就能推演;HMM 的状态不可见,可见的是观测值,必须同时有 A 和 B 两个矩阵,还要靠观测序列反推状态。一句话记:马尔可夫链是“看得见的状态在走”,HMM 是“看不见的状态在走,看得见的是它留下的影子”。

5.2 误区二:“隐”是指数据缺失或者噪声大

易混点:日常语境里“隐藏”约等于“没测到”“被干扰了”,于是把 HMM 的“隐”理解成传感器坏了、数据有缺口。

为什么混:这两个问题在表现上确实像——你拿不到想要的那一层信息。但成因完全不同。

怎么区分:数据缺失是采集环节的问题,补数据、换传感器、做插值都可能解决;HMM 的“隐”是模型结构决定的,状态本来就不在观测空间里,哪怕传感器完美、数据一个不缺,状态依然不可见。举个反例:朋友的活动记录一天不落,天气依然只能推断,不能直接读到。噪声是观测值本身带误差,属于 B 矩阵要吸收的东西;隐是“状态和观测分属两个空间”,属于模型的定义。把这两件事混在一起,调参时会一直找错方向。

5.3 误区三:观测值和状态是一一对应的

易混点:看到某个观测值,就直接断定处于某个状态,把 B 矩阵当成了查表。

为什么混:很多入门例子里,某个观测值在某个状态下的概率特别高,看起来像是“看到它就等于它”。加上人脑喜欢确定性,很容易滑向一一对应。

怎么区分:B 矩阵的每一行是一个概率分布,不是单位向量。晴天也可能购物,雨天也可能散步,只是概率高低不同。真正推断状态时,要看整条观测序列:某个观测单独看更支持状态 2,但结合前后观测和转移概率,最可能的路径可能落在状态 1。解码算法找的是整条路径的联合概率最大,不是逐帧取最大值。这一点在序列短的时候差别不明显,序列一长,逐帧贪心经常翻车。

5.4 误区四:HMM 只能做语音识别

易混点:翻教程,十个例子里八个是语音,于是形成“HMM 等于语音识别工具”的印象。

为什么混:语音识别确实是 HMM 最早大规模落地的场景之一,历史资料多,例子也顺手,先入为主很正常。

怎么区分:判断标准不是“是不是语音”,而是三条:有没有一串按时间排好的观测;观测背后有没有一个看不见、但会随 time 演变的状态;状态转移是否大致只依赖当前状态。三条都满足,就可以考虑 HMM。手写识别里,笔画序列是观测,字符是隐藏状态;设备监测里,振动信号是观测,健康/退化状态是隐藏状态;生物序列分析里,碱基序列是观测,功能片段是隐藏状态。反过来,如果数据本身没有顺序,或者状态完全可见,硬套 HMM 只会把简单问题复杂化。

6. 什么时候该用、什么时候别用

判断要不要上 HMM,我习惯先问三个问题,顺序不能乱。

第一个问题:这批数据有没有顺序?如果样本之间可以随意打乱,打乱之后结论不变,那它大概率不是序列问题,用普通分类器更直接。第二个问题:有没有一个看不见、但确实在影响观测的状态?如果所有关键量都能测到,那用马尔可夫链或者普通状态机就够了,不需要“隐”。第三个问题:状态转移是不是大致只依赖当前状态?如果下一步强烈依赖很久以前发生的事,一阶马尔可夫假设就不够用,得换能处理长程依赖的模型。

三个问题都过了,再看数据量。A 是 N×N,B 是 N×M,参数不算多,但要让学习算法收敛到靠谱的值,观测序列得有一定长度。数据太少时,B 矩阵会估出一堆接近 0 或 1 的极端值,看似干净,实际一遇到没见过的组合就失效。

场景特征更适合的做法
样本独立、无时间顺序普通分类器
状态完全可观测、只需推演转移马尔可夫链
有隐藏状态、观测按时间排列、转移近似一阶隐马尔可夫模型
隐藏状态之间存在很强的长程依赖需要能建模更长历史的序列模型
观测维度极高且连续、B 难以估计先做特征降维,或考虑其他建模范式

我踩过一次很典型的坑。早些年做一个小型的设备状态监测 Demo,拿到一段振动信号,我把它切成一个个独立样本,直接喂给分类器,准确率看着还行,一上线就崩。后来才想明白,设备的磨损是一个连续演变的过程,前后时刻的状态高度相关,把它当独立样本,等于把时间信息全扔了。那次之后我改成分段建模,先确认“状态看不看得见、顺序有没有意义、转移是不是只看当前”,再决定用哪套方法,误差立刻降下来。从那以后,我每次拿到带时间戳的数据,都强制自己先走一遍这三个问题,不再急着调模型。希望帮到你。

这份资料把马尔可夫链、转移概率矩阵、HMM 的缸球实验和那几条约束都收在了一起,推导和例子是连着排的,适合放在手边对照着看。遇到上面那几个易混点犯迷糊的时候,翻回去把矩阵和实验重新推一遍,比反复读定义管用得多。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 2:19:20

FFmpeg shared 版 DLL/PATH 与 0xc000007b 排错

简介&#xff1a;这份预编译 FFmpeg 4.4 完整包面向需要在 Windows 上快速处理音视频的开发者与个人用户&#xff0c;省去从源码配置、编译和链接依赖的繁琐流程&#xff0c;可直接调用命令行工具&#xff0c;也可将库文件集成到自有项目中。压缩包共 201 个文件&#xff0c;约…

作者头像 李华
网站建设 2026/10/27 2:19:18

机器视觉测试工程师的底层能力:从算法到寄存器的全栈验证

简介&#xff1a;本资源是上海柏楚电子科技2024秋季校招「机器视觉测试工程师」岗位的笔试真题汇编&#xff0c;面向计算机视觉、自动化、测控技术等专业应届生及转岗求职者&#xff0c;聚焦工业视觉系统测试能力的实战考查。内容覆盖白盒测试方法、2D几何变换、相机成像模型&a…

作者头像 李华
网站建设 2026/10/27 2:19:18

SQL Server教室信息管理系统:数据库层冲突检测与并发控制

简介&#xff1a;面向高校数据库课程设计与SQL Server入门实践的教室信息管理系统脚本包&#xff0c;聚焦教室设备报修登记、教室使用计划与课程安排关联等常见管理问题&#xff0c;适合计算机专业学生、数据库初学者及需要课程设计选题参考的读者。压缩包共6个SQL文件&#xf…

作者头像 李华
网站建设 2026/10/27 2:19:12

基于CNN的花卉枯萎识别智能解决方案

1. 项目概述&#xff1a;花卉枯萎识别的智能解决方案在农业种植和园艺养护领域&#xff0c;花卉健康状态监测一直是个耗时费力的工作。传统的人工巡检方式不仅效率低下&#xff0c;而且受主观判断影响较大。这个毕业设计项目正是为了解决这个问题——通过Python搭建CNN卷积神经…

作者头像 李华
网站建设 2026/10/27 2:18:54

LabVIEW调用SQLite实战:DLL直连方案与本地数据库工程化应用

简介&#xff1a;本资源是一套面向LabVIEW工程师与自动化开发者的SQLite数据库集成解决方案&#xff0c;专为解决LabVIEW原生数据库操作能力薄弱、建库繁琐、缓存难清理等痛点而设计。资源提供全自动建库、表格化批量插入、运行时缓存清空等核心功能&#xff0c;显著降低数据库…

作者头像 李华