什么是隐马尔可夫模型(HMM)?
目录
前言废话
做AI相关的人肯定对HMM(Hidden Markov Model,隐马尔可夫模型)绝不会陌生:
-
20 世纪 70 年代起它就统治了语音识别;
-
90 年代成为分词、词性标注的“黄金标准”;
-
今天,虽然深度学习大行其道,HMM 依旧凭借可解释性强、训练速度快、数据要求低三大优点,在工业界中小规模场景下频频露脸。
介绍
说到HMM,不得不提起马尔科夫模型(Markov Model),这部分可以参考这篇文章https://blog.csdn.net/CO_ocola/article/details/154994092?fromshare=blogdetail&sharetype=blogdetail&sharerId=154994092&sharerefer=PC&sharesource=CO_ocola&sharefrom=from_link
HMM 是含有隐含(看不见)状态的概率图模型,用来描述观测序列背后那个“看不见”的状态序列的演化规律。
一句话通俗解释就是:从“看得见”的线索里,把“看不见”的变化过程猜个八九不离十。
| 名称 | 符号 | 维度 | 含义 |
|---|---|---|---|
| 隐含状态序列 | Z = z₁…z_T | T | 真正驱动系统的“内因”,我们看不到 |
| 观测序列 | X = x₁…x_T | T | 我们能拿到的“外因” |
| 初始概率 | π | N×1 | 第一个隐状态是 i 的概率 π_i |
| 转移矩阵 | A | N×N | 从隐状态 i → j 的概率 a_{ij} |
| 发射矩阵(观测概率) | B | N×M | 在隐状态 i 下观测到符号 k 的概率 b_i(k) |
其中 N = 隐状态种类数,M = 观测符号种类数。
两个核心假设
-
齐次马尔可夫假设:当前隐状态 z_t 只与上一隐状态 z_{t-1} 有关,与更早无关。
-
观测独立性假设:当前观测 x_t 只与当前隐状态 z_t 有关,与别的不相干。
HMM能干什么?
-
评估(Evaluation)
给定模型 λ=(π,A,B) 和观测序列 X,求 P(X|λ)。
用途:异常检测、置信度打分。
算法:前向(Forward)或后向(Backward),O(TN²)。 -
解码(Decoding)
给定模型 λ 和观测 X,求最可能对应的隐状态序列 Z*。
用途:分词、词性标注、语音识别对齐。
算法:Viterbi,O(TN²)。 -
学习(Learning)
只有一堆观测 X,要反推出模型参数 λ=(π,A,B)。
用途:无监督训练、领域自适应。
算法:Baum-Welch(EM),迭代直至收敛。
原理
1 前向算法——高效算 P(X|λ)
定义前向概率
α_t(i) = P(x₁…x_t, z_t = i | λ)
递推:
α₁(i) = π_i · b_i(x₁)
α_{t+1}(j) = [Σ_i α_t(i)·a_{ij}] · b_j(x_{t+1})
最终:
P(X|λ) = Σ_i α_T(i)
2 Viterbi——求最优隐状态路径
定义
δ_t(i) = max_{z₁…z_{t-1}} P(z₁…z_{t-1}, z_t=i, x₁…x_t | λ)
递推:
δ₁(i) = π_i · b_i(x₁)
δ_t(j) = max_i [δ_{t-1}(i)·a_{ij}] · b_j(x_t)
同时记录指针 ψ_t(j) = argmax_i [δ_{t-1}(i)·a_{ij}],最后回溯即得最优路径 Z*。
3 Baum-Welch——无监督训练
E 步:用前-后向算期望计数
M 步:按期望计数重新估计 π、A、B
迭代至对数似然增量 < ε。
代码演示
import numpy as np
# 真实模型参数
pi = np.array([0.6, 0.4]) # 初始
A = np.array([[0.7, 0.3],
[0.4, 0.6]]) # 转移
B = np.array([[0.9, 0.1], # 发射(状态0下观测0概率0.9)
[0.2, 0.8]]) # 状态1下观测0概率0.2
# 1. 随机生成一条观测序列
T = 30
z = np.zeros(T, dtype=int)
x = np.zeros(T, dtype=int)
z[0] = np.random.choice(2, p=pi)
x[0] = np.random.choice(2, p=B[z[0]])
for t in range(1, T):
z[t] = np.random.choice(2, p=A[z[t-1]])
x[t] = np.random.choice(2, p=B[z[t]])
# 2. Viterbi 解码
def viterbi(pi, A, B, x):
T = len(x)
N = len(pi)
delta = np.zeros((T, N))
psi = np.zeros((T, N), dtype=int)
delta[0] = pi * B[:, x[0]]
for t in range(1, T):
for j in range(N):
tmp = delta[t-1] * A[:, j]
psi[t, j] = np.argmax(tmp)
delta[t, j] = tmp[psi[t, j]] * B[j, x[t]]
# 回溯
path = np.zeros(T, dtype=int)
path[-1] = np.argmax(delta[-1])
for t in range(T-2, -1, -1):
path[t] = psi[t+1, path[t+1]]
return path
z_hat = viterbi(pi, A, B, x)
print("真实状态:", z)
print("解码状态:", z_hat)
print("准确率 :", (z == z_hat).mean())

30个时间步达到93%准确率,可见HMM解码很靠谱。
结语
-
在数据量小、算力有限、需要可解释的场景,HMM 依旧是最具性价比的方案之一。
-
在深度学习时代,HMM 常作为 baseline、预处理模块,或与神经网络混搭(如 CTC + HMM、Transformer + 隐结构)。
掌握 HMM,你不仅收获一个“老而弥坚”的算法,更能深刻理解序列建模的本质:
“看不见”的隐变量驱动“看得见”的观测,我们所有建模努力,不过是在猜测造物主手里的那枚骰子。
更多推荐


所有评论(0)