查看全课大纲(第 57 / 82 节)
- 1.函数与数据泛化
- 2.向量:从几何直觉到高维空间
- 3.矩阵与张量
- 4.特征值与特征向量:矩阵变换的不动方向
- 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
- 6.概率与统计:机器学习的数学基础
- 7.独立性与随机变量:贝叶斯公式与二项分布
- 8.期望、方差与协方差:随机变量的数字画像
- 9.联合概率:当一条轴不够用的时候
- 10.概率分布(一):从伯努利到伽马函数
- 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
- 12.机器学习的模型:找输入与输出的关系
- 13.机器学习的应用
- 14.过拟合
- 15.机器学习的分类
- 16.有监督学习:从房价预测说起
- 17.损失函数
- 18.梯度下降(上):更新规则与学习速率
- 19.梯度下降(2)
- 20.牛顿方法
- 21.KNN简介
- 22.距离测算
- 23.朴素贝叶斯
- 24.朴素贝叶斯的实际应用
- 25.信息熵:决策树构建的度量基础
- 26.信息增益与决策树的构建
- 27.ID3算法
- 28.决策树节点的划分
- 29.CART树
- 30.Bagging
- 31.Boosting:自适应提升算法
- 32.Gradient Boosting
- 33.线性模型:回归与分类的同一副骨架
- 34.最小二乘:把最优参数直接解出来
- 35.最小二乘法的几何与概率视角
- 36.极大似然:给最小二乘一个概率出身
- 37.逻辑回归(1):把线性模型接到分类上
- 38.逻辑回归(2):损失函数与多分类
- 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
- 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
- 41.优化方法(1):坐标下降与前向选择
- 42.优化方法(2):前向策略与最小角回归
- 43.拉格朗日乘子法(1):从无约束到等式约束
- 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
- 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
- 46.最大间隔:把分类问题变成优化问题
- 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
- 48.支持向量:边界上的少数派
- 49.SVM 计算过程:一笔到底算完,再走进核方法
- 50.贝叶斯公式:概率即信念
- 51.隐含变量和概率模型:给看不见的原因建模
- 52.EM 算法:期望与最大化的迭代
- 53.琴生不等式:EM 的数学钥匙
- 54.三个硬币问题:EM 的复盘与衔接
- 55.高斯混合模型:用隐变量解释双峰数据
- 56.隐马尔可夫模型
- 57.隐马尔可夫模型(2):前向算法与动态混合模型
- 58.隐马尔可夫模型在 NLP 中的运用
- 59.EM 算法:把「为什么收敛」推到底
- 60.HMM 在 NLP 中的运用:从分词到机器翻译
- 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
- 62.高维下的高斯模型
- 63.主题模型:从词袋到隐含主题
- 64.Dirichlet 分布(1)
- 65.Dirichlet 分布(2)
- 66.统计学习内容回顾
- 67.K-means 算法
- 68.PCA 降维
- 69.SVD 降维
- 70.从聚类到流形
- 71.局部线性嵌入
- 72.随机邻域嵌入:SNE 与 t-SNE
- 73.无参模型:让数据自己说话
- 74.高斯过程:函数空间里的正态分布
- 75.高斯过程(2):噪声、正则化与核的线性组合
- 76.神经网络简介:从感知器到自编码器
- 77.反向传播:把误差一层层传回去
- 78.卷积神经网络(CNN):让特征自己学出来
- 79.循环神经网络(RNN):给网络装上记忆
- 80.深度学习回顾:静态一类,动态一类
- 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
- 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传
隐马尔可夫模型(2):前向算法与动态混合模型
约 33 分钟
小象实战讲义 · 机器学习算法精讲
上一节结尾,盒子-小球例子停在「看到了红、白、红,生成这个序列的概率到底有多大?我怎么去计算?」——这一节讲师接着往下算。状态序列是隐藏的,所以要对所有可能的路径求和;硬算会发现组合太多,「不是(不可)算」的量级。于是引出本节的主角前向算法:引入前向概率 ,一层一层把求和吸收掉。最后讲师给了一个「不是很多人都去讲」的统一视角:HMM 其实是一个动态的混合模型。
💡 核心导读
- 从联合到边缘:——把隐含变量加和掉,是第 12 章起我们一直在做的事。
- 组合爆炸:三个盒子、三个时刻,状态路径有 条,一条条硬算当然算得出来,但路径数随时刻数指数增长。
- 前向概率 :——「到 为止的全部观测且当前状态是 」的联合概率;配对的 管 之后的观测。
- 递推:——想算下一时刻,只需前一时刻的 乘上转移和释放。
- 动态混合模型:三硬币是伯努利混合、男女生身高是高斯混合,HMM 是加了转移矩阵 的动态版——分量会随时间跳来跳去。
目标:算出 P(Y)
上一节我们算过「状态序列已知」时的联合概率 。但现实里 是隐藏的,我们真正想要的是只关于观测的概率 。做法是老套路——讲师开场先点破:「我们从上次课就已经学过了,我们最会做的事情就是把隐含变量做一个加和。」
(把上节的联合概率公式整套搬进求和号,就是把每一条可能的路径的概率加起来。)
先辨析一个容易混的地方:下标是时刻、不是状态。 本身只有三个取值——盒子 1、盒子 2、盒子 3; 里的数字代表的是不同的时刻。任何一个时刻的 都属于这三个盒子之一,三个状态的概率加在一起还是 1。
于是这个求和有多「厚」?以盒子例子(观测红、白、红)为例,三个时刻、每个时刻三种状态,路径组合是:
一共 种组合,把每一种组合代进去算出值再累加。讲师的评价很直白:「你会发现这个呢,不是算(的量级),当然你要硬算呢,当然也是可以算出来的。」——每加一个时刻,路径数乘 3;时刻一多,硬算彻底失去可行性。
把链从中间剪开:α 与 β
换这个问题想想:给定所有的观测数据,我想知道某一时刻的状态——「我知道他 shopping、clean 所有的事情,我想知道他某一天天气到底什么样」「我看了所有小球的颜色,我想知道某一次是从第几个箱子里取出来的」。这相当于对隐含状态做一个估计,用贝叶斯公式写:
但你会发现,这里的 likelihood 部分(尤其是 )非常难计算。所以讲师做了一个变形:把整条马尔可夫链从 时刻剪开,分成前、后两部分。
- 前向部分定义一个函数 :把「 之前的所有观测」和「 时刻的状态」放进一个联合概率:
(构造思路:条件概率乘先验等于联合概率——前半段观测给定 的条件概率,乘上 ,就合成了 。)
- 后向部分定义一个函数 :只管 之后的观测:
两个函数一乘,前后两段拼回整条链,于是那个估计问题变成 。这套东西的名字叫前向-后向算法。本节视频重点推「前向」这一半; 的递推思路与 对称(课件里有完整公式),视频没有展开,按讲师的处理我们先吃透前向。
前向算法:α 的递推
「我可能就没办法给大家讲推全部的公式了,我只给大家推一小半吧——如果全写出来特别复杂。」先摆目标:想找 与 的关系。按定义把 时刻写开:
第一步,把新观测 单拎出来,剩下的部分拆成「条件 先验」:
接下来是讲师口中「稍微有创意性的一步」:在中间引入一个新的隐含变量——对 做加和。 是 时刻的状态,取遍所有盒子:
(讲师板书推到这一带反复自我纠正了好几次——「写晕了」「Sorry,T 又写错了」——变形本身没有新东西,就是联合概率与条件概率的来回改写。)最后把三块认出来: 恰好是 的定义; 就是转移矩阵 ; 就是释放概率 :
用讲师的话说:「你每次想求一个 的时候,可以做的就是把前一时刻的 ,乘上它的转移概率和释放概率。」 如果你现在处于状态 ,有多少种可能转到 的状态、转到之后又要生成什么样的 ,把这些可能累加起来,就得到下一个 。
存在的意义也在这句里:「 所起到的目的,就是把这个公式每一步的加和不断地累加掉。」硬算是把 27 条路径各自算完再总加;前向算法是边走边加——每前进一个时刻,就把那一层的求和吸收进 里。走到最后:
数值走查:盒子-小球的前向表
回到盒子-小球(参数沿用上一节:,、 同前),观测序列红、白、红。
初始化 (第一个观测是红),讲师逐个口算:
三个值加起来:——讲师:「最后就等于一个,我应该是 0.54。」这正是第一个观测是红球的总概率 :所有可能的箱子都有一些概率生成红球,你看到红球的概率就是它们所有的这些累加。
递推到 (第二个观测是白),以 为例——从 的三个 出发,各自乘上「转到盒 1」的转移概率再加和,最后乘上盒 1 出白球的释放概率:
(口播勘误:讲师现场念这一列时说「0.1×0.5、0.16×0.3、0.28×0.2」,把 的这一列读成了第一行——按上一节定稿的转移矩阵,盒 2 转盒 1 是 、盒 3 转盒 1 是 ,本表按矩阵定义为准。)整张表跑完:
# 盒子-小球 HMM(参数同上一节),观测序列:红、白、红
pi = [0.2, 0.4, 0.4]
A = [
[0.5, 0.3, 0.2], # A[i][j]:盒 i → 盒 j 的转移概率
[0.2, 0.5, 0.3],
[0.3, 0.2, 0.5],
]
B = [
[0.5, 0.5], # B[i][k]:盒 i 出(红, 白)的概率
[0.4, 0.6],
[0.7, 0.3],
]
Y = [0, 1, 0] # 0=红,1=白
T = len(Y)
N = len(pi)
alpha = [[0.0] * N for _ in range(T)]
# 初始化:α(q_0 = i) = π_i · B[i][y_0]
for i in range(N):
alpha[0][i] = pi[i] * B[i][Y[0]]
# 递推:α(q_{t+1} = j) = [ Σ_i α(q_t = i) · A[i][j] ] · B[j][y_{t+1}]
for t in range(T - 1):
for j in range(N):
s = sum(alpha[t][i] * A[i][j] for i in range(N))
alpha[t + 1][j] = s * B[j][Y[t + 1]]
# 终止:P(Y) = Σ_j α(q_T = j)
prob = sum(alpha[T - 1])
for t in range(T):
print(f"t={t} 观测={'红白'[Y[t]]}: alpha = [{', '.join(f'{v:.4f}' for v in alpha[t])}]")
print(f"P(红白红) = {prob:.6f}")
print(f"检验:P(y_0=红) = 0.2*0.5 + 0.4*0.4 + 0.4*0.7 = {0.2*0.5 + 0.4*0.4 + 0.4*0.7:.2f}")t=0 观测=红: alpha = [0.1000, 0.1600, 0.2800]
t=1 观测=白: alpha = [0.0830, 0.0996, 0.0624]
t=2 观测=红: alpha = [0.0401, 0.0349, 0.0544]
P(红白红) = 0.129318
检验:P(y_0=红) = 0.2*0.5 + 0.4*0.4 + 0.4*0.7 = 0.54读一遍这张表: 行就是讲师口算的 0.1、0.16、0.28(和为 0.54,检验行复现);每往下一行,只是把上一行的三个数乘上转移概率、加和、再乘释放概率——27 条路径的求和,被三行递推吃掉了。最终 。这就是前向算法:一条硬算的指数级加法题,变成了「一层一层累加」的线性流程。
HMM 是动态的混合模型
本节最后,讲师给了一个统一的理解——「HMM 实际上可以看成是一个 dynamic mixture model(动态混合模型)。这种说法不是很多人都去讲,但是意思是这样子的。」
我们学过的混合模型:三硬币是伯努利混合模型,男女生身高的例子是混合高斯模型。它们都是静态的——每个数据点先用 独立地选一个分量,再从分量里采样。HMM 把「选分量」这件事变成了有记忆的。用三个高斯画个图景:
- 最开始,用 ( 加起来为 1)先选一个高斯——比如第一次选中了橘黄色的那个,就在它的概率密度里选了第一个值;
- 第二次不再独立重抽,而是按转移概率决定下一个状态——可能跳到别的高斯,也可能回到自己——在新状态里再选一个点;
- 之后不断重复:从这个点跳到那个点,每次按 走、按当前高斯的密度取值。
这一串「选哪个高斯」的过程,本身就是一条马尔可夫链。参数的分工: 矩阵描述的就是在不同的 mixture(高斯)之间不断地跳跃; 矩阵就是每个高斯自己的参数——、、,各有各的概率密度(形状各异)。
用代码把「静态」和「动态」的差别算出来(同一组 和 ,对比两条固定路径在两种模型下的概率):
# 动态混合 vs 静态混合:同一条状态路径,两种模型下的概率对比
pi = [0.2, 0.4, 0.4]
A = [
[0.5, 0.3, 0.2],
[0.2, 0.5, 0.3],
[0.3, 0.2, 0.5],
]
def p_static(path):
"""静态混合模型:每一步都独立地按 π 重新选盒子。"""
p = 1.0
for s in path:
p *= pi[s]
return p
def p_dynamic(path):
"""动态混合模型(HMM 状态链):第一步按 π,之后按 A 转移。"""
p = pi[path[0]]
for t in range(1, len(path)):
p *= A[path[t - 1]][path[t]]
return p
path1 = [1, 1, 1, 1, 1] # 一路粘在盒 2
path2 = [1, 2, 0, 2, 1] # 盒2 → 盒3 → 盒1 → 盒3 → 盒2,来回跳
for name, path in [("路径1", path1), ("路径2", path2)]:
print(f"{name} {path}:")
print(f" 静态混合模型概率: {p_static(path):.6f}")
print(f" 动态混合模型概率: {p_dynamic(path):.6f}")路径1 [1, 1, 1, 1, 1]:
静态混合模型概率: 0.010240
动态混合模型概率: 0.025000
路径2 [1, 2, 0, 2, 1]:
静态混合模型概率: 0.005120
动态混合模型概率: 0.001440看两组数的门道:静态模型下,路径概率只数每个状态出现了几次,与顺序无关——路径 1 是清一色的五个盒 2(),路径 2 则是两个盒 2、两个盒 3、一个盒 1(),两条路径静态概率的差别来自状态计数的不同(乘法可交换,顺序重排不改变乘积)。动态模型下,连贯性被转移矩阵放大、跳跃被压低:一路粘住盒 2 的路径 1 概率 0.025,是来回横跳的路径 2 概率 0.00144 的十七倍还多。这就是「记忆」的数学形状。
最后回到最初的硬币例子收束全章:如果每次掷硬币 B 或 C 的状态选择,都跟上一次的结果相关,那就变成了一个完全的隐马尔可夫模型。 这时要估计的参数是 、、——「 其实大家都知道,很好估计了。那 和 这件事怎么估?我们会下节课跟大家去讲完。」(参数怎么从数据里学出来,正是下一章开头要接的问题。)
📝 动手练一练
- 算一算组合账:盒子-小球模型中,若观测序列长度为 (每个时刻有 种状态),状态路径共有多少条?每条路径需要连乘多少个因子(初始、转移、释放各多少个)?当 时路径总数是多少?再对比:前向算法递推 层、每层 次乘加,各是多少?体会一下「指数级」与「线性级」的差距。
👉 点击查看参考答案
路径总数 : 时 条(本节正文枚举过的 到 ); 时 条。每条路径的因子数:初始 个、转移 个、释放 个,共 个—— 时 6 个(正是上一节代码里的六个因子), 时 20 个;硬算总量约 次乘法再加总。
前向算法:初始化 次乘法;递推 层,每层对每个目标状态做 次乘加(共 次乘加),再乘一次释放概率;终止 次加法。总量约 次乘加—— 时也只有 次,与 59049 条路径的硬算完全不在一个量级。路径数随 指数增长,前向算法的工作量只随 线性增长。
- 递推手算:正文的前向表中, 时刻的 为 。请手算 时刻的 (提示:、、,盒 3 出红球概率 ),并与代码输出对照。
👉 点击查看参考答案
按递推公式:
与代码输出 行的第三列 一致。这个值也是三个最终 中最大的一个——第三个观测是红球,而盒 3 恰恰是最「爱出红球」的盒子(0.7),前向表把它标了出来。
本章小结
本节接着上一节的悬念,解决了「状态序列未知时 怎么算」:先把联合概率对所有状态路径求和,发现组合是指数级的;于是引入前向概率 (与管后半段的 配对),推导出递推 ——每前进一个时刻就把一整层求和吸收掉,最后 。盒子-小球例子的走查表(0.1/0.16/0.28 → 0.54 检验 → 完整三行)把这个流程落到了数上。收尾的统一视角:HMM 是动态的混合模型——三硬币、GMM 静态地选分量,HMM 让分量随时间按 跳跃;至于 、、 怎么从数据里估出来,讲师留给了下一章。
📋 行动清单
- 白纸推一遍 的递推:重点是「引入 做加和」那一步为什么合法。
- 把正文代码的观测序列改成其他组合(如白、白、白),跑出新的前向表和 ,观察哪些行变化最大、为什么。
- 带着「 好估、 和 怎么估」的问题进入下一章——想想上一章 EM 的 E/M 两步能不能搬到 HMM 上。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第13章笔记:期望最大化(EM)算法