概述

隐马尔可夫模型(Hidden Markov Model,HMM)是一种统计模型,用于描述一个含有隐含未知参数的马尔可夫过程。1

HMM的核心思想是:系统状态不可直接观测,只能通过观测序列间接推断。

经典应用场景

领域应用
语音识别将声学信号转为文字
自然语言处理词性标注、命名实体识别
生物信息学基因序列分析
金融市场状态预测(牛市/熊市)
手势识别从视频序列中识别动作

HMM的基本结构

一个直观的例子

问题:根据多年树木年轮的尺寸(观察值),推断过去的气温状态(隐藏状态)。

隐藏状态(不可观测):  炎热(H) → 炎热(H) → 寒冷(C) → 炎热(H)
                          ↓         ↓         ↓         ↓
观察值(可观测):      小(S)     中(M)     小(S)     大(L)

五元组定义

符号含义说明
状态数隐藏状态的个数
观测符号数可能的观测值个数
转移概率矩阵
观测概率矩阵
初始状态分布

HMM通常记作


HMM的三个基本问题

问题一:评估问题(Evaluation)

给定:模型 和观测序列

求解:计算 ,即观测序列出现的概率

问题二:解码问题(Decoding)

给定:模型 和观测序列

求解:找到最可能的状态序列

问题三:学习问题(Learning)

给定:观测序列

求解:调整参数 使得 最大


问题一:Forward算法

朴素方法的困境

直接计算 需要对所有可能的状态序列求和:

对于长度为 的序列,状态数为 ,则需要计算 种可能,这在实际中是不可行的。

α-pass递归

定义前向变量

递归步骤

  1. 初始化):
  1. 递归):
  1. 终止

时间复杂度

方法时间复杂度
朴素方法
Forward算法

问题二:Viterbi算法

动态规划思想

Viterbi算法使用动态规划找到最可能的状态序列。核心思想是:保留到达每个状态的最优路径。

δ-ψ变量

定义:

  • :时刻 ,状态为 的所有路径中,最大概率值
  • :时刻 ,状态为 的最优路径的前驱状态

算法步骤

  1. 初始化
  1. 递归):
  1. 终止
  1. 回溯

下溢问题

由于概率连乘会导致数值下溢,实际中通常使用对数概率


问题三:Baum-Welch算法(EM算法)

后向变量

定义后向变量

递归步骤

  1. 初始化):
  1. 递归):

γ和ξ变量

γ变量(单状态概率):

ξ变量(双状态概率):

参数重估计

  1. 更新初始分布
  1. 更新转移概率
  1. 更新观测概率

算法流程

输入: 观测序列 O, 初始参数估计
输出: 最优参数 λ*

重复:
    1. E步: 计算 γ_t(i) 和 ξ_t(i,j)
    2. M步: 用公式更新 A, B, π
    3. 计算 log P(O|λ)
直到 log P(O|λ) 收敛

Python实现

Forward算法实现

import numpy as np
 
def forward(obs, A, B, pi):
    """
    Forward算法计算观测概率
    
    参数:
        obs: 观测序列 (T,)
        A: 转移概率矩阵 (N, N)
        B: 观测概率矩阵 (N, M)
        pi: 初始分布 (N,)
    
    返回:
        prob: 观测序列的概率
        alpha: 前向变量 (T, N)
    """
    T = len(obs)
    N = len(pi)
    
    # 缩放因子,防止下溢
    scale = np.zeros(T)
    
    # 初始化
    alpha = np.zeros((T, N))
    alpha[0] = pi * B[:, obs[0]]
    scale[0] = np.sum(alpha[0])
    alpha[0] /= scale[0]
    
    # 递归
    for t in range(1, T):
        for j in range(N):
            alpha[t, j] = np.dot(alpha[t-1], A[:, j]) * B[j, obs[t]]
        scale[t] = np.sum(alpha[t])
        alpha[t] /= scale[t]
    
    # 计算对数概率
    prob = -np.sum(np.log(scale))
    
    return np.exp(prob), alpha
 
# 示例:天气模型
# 状态:0=晴, 1=雨
# 观测:0=散步, 1=购物, 2=打扫
 
A = np.array([[0.7, 0.3],
              [0.4, 0.6]])  # 转移概率
 
B = np.array([[0.5, 0.2, 0.3],
              [0.1, 0.6, 0.3]])  # 观测概率
 
pi = np.array([0.6, 0.4])  # 初始分布
 
obs = np.array([0, 2, 1])  # 观测序列:散步→打扫→购物
prob, alpha = forward(obs, A, B, pi)
print(f"观测概率: {prob:.6f}")

Viterbi算法实现

def viterbi(obs, A, B, pi):
    """
    Viterbi算法求解最优状态序列
    
    返回:
        path: 最优状态序列
        prob: 最优路径的概率
    """
    T = len(obs)
    N = len(pi)
    
    # 初始化
    delta = np.zeros((T, N))
    psi = np.zeros((T, N), dtype=int)
    
    delta[0] = np.log(pi) + np.log(B[:, obs[0]])
    psi[0] = 0
    
    # 递归
    for t in range(1, T):
        for j in range(N):
            prob = delta[t-1] + np.log(A[:, j])
            psi[t, j] = np.argmax(prob)
            delta[t, j] = np.max(prob) + np.log(B[j, obs[t]])
    
    # 回溯
    path = np.zeros(T, dtype=int)
    path[T-1] = np.argmax(delta[T-1])
    for t in range(T-2, -1, -1):
        path[t] = psi[t+1, path[t+1]]
    
    return path, np.exp(np.max(delta[T-1]))
 
# 测试
path, prob = viterbi(obs, A, B, pi)
state_names = ['晴', '雨']
print(f"最优状态序列: {[state_names[i] for i in path]}")
print(f"概率: {prob:.6f}")

实际应用:词性标注

问题背景

给定一个句子,为每个词标注词性(如名词、动词、形容词等)。

HMM建模

  • 隐藏状态:词性标签(NN, VB, DT等)
  • 观测序列:句子中的词
  • 转移概率
  • 发射概率

示例

句子: "The cat sits on the mat"
观测:  The  cat  sits  on   the  mat
标签:  DT   NN   VBZ   IN   DT   NN

使用Viterbi算法找到最可能的标签序列。


HMM的局限性与扩展

HMM的局限

  1. 观测独立性假设:假设观测只与当前状态有关
  2. 一阶马尔可夫假设:假设状态只与前一状态有关
  3. 表达能力有限:难以建模复杂的序列依赖

扩展方向

模型改进
高阶HMM状态依赖前多个状态
条件随机场(CRF)放松观测独立性假设
双向LSTM建模长距离依赖

详见 Transformer与注意力机制


参考

Footnotes

  1. L. R. Rabiner, “A Tutorial on Hidden Markov Models and Selected Applications in Speech Recognition”, Proceedings of the IEEE, 1989