简介这份模式识别主题课件面向模式识别、机器学习与人工智能方向的初学者及课程复习者重点梳理隐马尔可夫模型相关知识帮助读者建立从马尔可夫性、马尔科夫链到HMM应用的系统理解。压缩包内共1个PPT文件整体约5.79MB以讲义式页面组织概念、公式、转移概率矩阵示例及HMM经典抽球实验便于课堂演示或自学翻阅。内容覆盖马尔科夫链与马尔科夫过程、齐次链转移概率矩阵、隐马尔可夫模型的状态与观察值、转移概率和观察值概率并延伸到语音识别、图像识别、自然语言处理与生物信息学等应用场景。已有1592人学习适合快速抓取HMM核心概念、对照实例理解双重随机过程并为后续算法推导和课程作业提供线索。1. 模式识别到底在识别什么从“看一眼就认出来”说起早上出门扫一眼天色你大概能判断要不要带伞听到楼道里的脚步声你能分辨是不是同屋的人回来了手机相册几千张照片它自己就能按人脸归成一堆。这些事人做起来毫不费力换成机器却难得多。模式识别要解决的就是这件事让机器从数据里找出规律再依据规律判断新数据属于哪一类、对应哪种情况。这里的“模式”并不神秘可以是一张图的纹理、一段语音的波形也可以是一串按时间排好的观测值。搞懂它的价值在于许多看起来“机器怎么可能做到”的事情拆开看都是同一套思路。这份资料着重讲的是其中专门处理序列的一支马尔可夫模型与隐马尔可夫模型。2. 马尔可夫性为什么“将来只依赖现在”2.1 一句话说清马尔可夫性如果一件事的“将来”只和“现在”有关和“过去”怎么走到现在无关我们就说这个过程具有马尔可夫性也叫无后效性。用一句公式写出来就是 X(t1) f(X(t))下一时刻的状态是当前状态的函数。打个比方下班开车回家选路线。你今天走哪条路主要取决于此刻车在哪个路口、当前哪条路堵而不需要把过去一周每天走过的路线在脑子里重放一遍。当前路口就是“现在”过去一周的行车记录就是“过去”路况判断只用到“现在”这就是马尔可夫性的味道。反过来说什么事情不满足它累计得分是个典型一支球队本赛季的总积分等于过去每一场得分之和光看“当前积分”没法知道下一场之后变成多少必须把历史累加进来。再比如一段长文本的语义往往要回看很远的前文这也不符合“只看现在”的假设。这个假设之所以重要是因为它把问题变小了。一个系统可能有成千上万种历史组合如果每种历史都要记住模型会大到没法算只保留“当前处于什么状态”参数量就压下来了工程上才算得动。提示无后效性是一种建模假设不是对世界的断言。现实里的过程多少带点历史惯性假设它成立换来的是可计算性。2.2 马尔可夫链把时间和状态都切成格子把马尔可夫性放到离散场景里就得到马尔可夫链。它要求两件事都离散时间是一格一格的第 0 步、第 1 步、第 2 步……状态也是可数的晴、阴、雨或者状态 a1、a2、a3……。把相继观察的结果记成 {Xn X(n), n 0,1,2,…}状态空间记作 I {a1, a2, …}。核心参数是转移概率Pij(m, mn) P{Xmn aj | Xm ai}意思是“在时刻 m 处于状态 ai 的条件下到时刻 mn 转移到状态 aj 的概率”。竖线后面是条件读作“已知”。拿天气做例子状态只有三个晴天、阴天、下雨。根据历史统计可以得到一张一步转移表从 \ 到晴天阴天下雨晴天0.500.250.25阴天0.3750.250.375下雨0.250.1250.625读法是如果今天是晴天明天仍是晴天的概率是 0.50转阴天 0.25转下雨 0.25。三列加起来正好是 1因为明天总要落在三种天气之一。这不是巧合而是转移概率的硬性约束从任何一个状态出发转移到所有可能状态的 Ham 概率之和必须为 1。当 Pij(m, mn) 与起始时刻 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×NN 一般不会太大因为状态数每增加一个参数量是平方级增长的数据不够就会估得很飘。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和为 1A状态转移概率N×N每行和为 1B观测值概率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), repeatlen(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×NB 是 N×M参数不算多但要让学习算法收敛到靠谱的值观测序列得有一定长度。数据太少时B 矩阵会估出一堆接近 0 或 1 的极端值看似干净实际一遇到没见过的组合就失效。场景特征更适合的做法样本独立、无时间顺序普通分类器状态完全可观测、只需推演转移马尔可夫链有隐藏状态、观测按时间排列、转移近似一阶隐马尔可夫模型隐藏状态之间存在很强的长程依赖需要能建模更长历史的序列模型观测维度极高且连续、B 难以估计先做特征降维或考虑其他建模范式我踩过一次很典型的坑。早些年做一个小型的设备状态监测 Demo拿到一段振动信号我把它切成一个个独立样本直接喂给分类器准确率看着还行一上线就崩。后来才想明白设备的磨损是一个连续演变的过程前后时刻的状态高度相关把它当独立样本等于把时间信息全扔了。那次之后我改成分段建模先确认“状态看不看得见、顺序有没有意义、转移是不是只看当前”再决定用哪套方法误差立刻降下来。从那以后我每次拿到带时间戳的数据都强制自己先走一遍这三个问题不再急着调模型。希望帮到你。这份资料把马尔可夫链、转移概率矩阵、HMM 的缸球实验和那几条约束都收在了一起推导和例子是连着排的适合放在手边对照着看。遇到上面那几个易混点犯迷糊的时候翻回去把矩阵和实验重新推一遍比反复读定义管用得多。本文还有配套的精品资源点击获取