首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >隐马尔可夫模型

隐马尔可夫模型

作者头像
贺公子之数据科学与艺术
发布2025-12-17 13:59:15
发布2025-12-17 13:59:15
2460
举报
理解隐马尔可夫模型:从罐子问题说起

隐马尔可夫模型(Hidden Markov Model, HMM)是一种经典的统计模型,常用于处理时序数据,如语音识别、自然语言处理和生物信息学等领域。通过一个简单的罐子问题,可以直观地理解HMM的核心思想。

罐子问题的场景

假设有一个房间,里面有3个罐子(

X1,X2,X3X_1, X_2, X_3

),每个罐子装有4种不同标签的球(

y1,y2,y3,y4y_1, y_2, y_3, y_4

)。房间外有一个观察者,无法直接看到罐子,但能看到每次从罐子里抽出的球。控制者按一定规则选择罐子并抽取球,每次抽取后补充一个相同的球,保持罐子中球的分布不变。

在这个模型中,罐子代表隐藏状态(state),球代表观测结果(observation)。观察者只能看到球的序列(观测序列),而无法知道每次抽取时具体是哪个罐子(状态序列)。

隐马尔可夫模型的基本假设

HMM 基于两个关键假设:

  1. 齐次马尔可夫性(Homogeneous Markov Property) 当前状态仅依赖于前一个状态,与其他历史状态无关。例如,若当前状态是
X3X_3

,则前一个状态只能是

X2X_2

,而不能直接由

X1X_1

跳转而来。

  1. 观测独立性(Observation Independence) 当前观测仅依赖于当前状态,与其他状态和观测无关。例如,从
X2X_2

抽取球

y3y_3

的概率仅与

X2X_2

的球分布有关,与之前或之后的抽取无关。

HMM 的数学表示

HMM 由以下三组参数定义:

  1. 初始状态概率向量
π\boldsymbol \pi
πi=P(i1=qi)\pi_i = P(i_1 = q_i)

,表示初始时刻选择状态

qiq_i

的概率。

  1. 状态转移概率矩阵
A\bf A
aij=P(it+1=qj∣it=qi)a_{ij} = P(i_{t+1} = q_j | i_t = q_i)

,表示从状态

qiq_i

转移到

qjq_j

的概率。

  1. 观测概率矩阵
B\bf B
bj(k)=P(ot=vk∣it=qj)b_j(k) = P(o_t = v_k | i_t = q_j)

,表示在状态

qjq_j

下生成观测

vkv_k

的概率。

这三组参数共同定义了 HMM 的结构和行为。

应用与扩展
  1. 序列预测 给定观测序列,可以预测最可能的状态序列(如语音识别中的音素标注)。
  2. 参数学习 通过观测数据,利用 Baum-Welch 算法(EM 算法的变种)估计 HMM 的参数。
  3. 生成模型 可以模拟 HMM 生成新的观测序列,用于数据增强或测试。

HMM 的局限性在于其严格的马尔可夫假设,而现实问题中可能存在更复杂的依赖关系。因此,现代机器学习中,HMM 常与其他模型(如神经网络)结合使用。

隐马尔可夫模型(HMM)代码实践

隐马尔可夫模型是一种统计模型,用于描述含有隐含未知参数的马尔可夫过程。以下是基于Python的实现示例,使用了numpy库进行矩阵运算。

初始化参数

定义HMM的初始状态概率、状态转移矩阵和观测概率矩阵:

代码语言:javascript
复制
import numpy as np

# 初始状态概率 (pi)
pi = np.array([0.6, 0.4])  # 假设有2个隐藏状态

# 状态转移矩阵 (A)
A = np.array([[0.7, 0.3],   # 状态1转移到状态1和状态2的概率
              [0.4, 0.6]])  # 状态2转移到状态1和状态2的概率

# 观测概率矩阵 (B)
B = np.array([[0.1, 0.4, 0.5],  # 状态1生成观测1、2、3的概率
              [0.6, 0.3, 0.1]]) # 状态2生成观测1、2、3的概率
前向算法(Forward Algorithm)

计算观测序列的概率:

代码语言:javascript
复制
def forward_algorithm(obs_seq, pi, A, B):
    T = len(obs_seq)
    N = len(pi)
    alpha = np.zeros((T, N))
    
    # 初始化
    alpha[0, :] = pi * B[:, obs_seq[0]]
    
    # 递推
    for t in range(1, T):
        for j in range(N):
            alpha[t, j] = np.sum(alpha[t-1, :] * A[:, j]) * B[j, obs_seq[t]]
    
    # 终止
    return np.sum(alpha[-1, :])

# 示例观测序列(假设观测值为0, 1, 2)
obs_seq = [0, 1, 2]
prob = forward_algorithm(obs_seq, pi, A, B)
print("观测序列概率:", prob)
维特比算法(Viterbi Algorithm)

解码最可能的隐藏状态序列:

代码语言:javascript
复制
def viterbi_algorithm(obs_seq, pi, A, B):
    T = len(obs_seq)
    N = len(pi)
    delta = np.zeros((T, N))
    psi = np.zeros((T, N), dtype=int)
    
    # 初始化
    delta[0, :] = pi * B[:, obs_seq[0]]
    
    # 递推
    for t in range(1, T):
        for j in range(N):
            temp = delta[t-1, :] * A[:, j]
            delta[t, j] = np.max(temp) * B[j, obs_seq[t]]
            psi[t, j] = np.argmax(temp)
    
    # 回溯
    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

# 解码观测序列
path = viterbi_algorithm(obs_seq, pi, A, B)
print("最可能隐藏状态序列:", path)
鲍姆-韦尔奇算法(Baum-Welch Algorithm)

用于参数学习(无监督学习):

代码语言:javascript
复制
def baum_welch_algorithm(obs_seq, N, M, max_iter=100):
    T = len(obs_seq)
    pi = np.random.rand(N)
    pi /= np.sum(pi)
    A = np.random.rand(N, N)
    A /= np.sum(A, axis=1, keepdims=True)
    B = np.random.rand(N, M)
    B /= np.sum(B, axis=1, keepdims=True)
    
    for _ in range(max_iter):
        # E-step: 计算alpha, beta, gamma, xi
        alpha = np.zeros((T, N))
        alpha[0, :] = pi * B[:, obs_seq[0]]
        for t in range(1, T):
            for j in range(N):
                alpha[t, j] = np.sum(alpha[t-1, :] * A[:, j]) * B[j, obs_seq[t]]
        
        beta = np.zeros((T, N))
        beta[-1, :] = 1
        for t in range(T-2, -1, -1):
            for i in range(N):
                beta[t, i] = np.sum(A[i, :] * B[:, obs_seq[t+1]] * beta[t+1, :])
        
        gamma = alpha * beta
        gamma /= np.sum(gamma, axis=1, keepdims=True)
        
        xi = np.zeros((T-1, N, N))
        for t in range(T-1):
            for i in range(N):
                for j in range(N):
                    xi[t, i, j] = alpha[t, i] * A[i, j] * B[j, obs_seq[t+1]] * beta[t+1, j]
            xi[t, :, :] /= np.sum(xi[t, :, :])
        
        # M-step: 更新参数
        pi = gamma[0, :]
        A = np.sum(xi, axis=0) / np.sum(gamma[:-1, :], axis=0, keepdims=True).T
        for j in range(N):
            for k in range(M):
                B[j, k] = np.sum(gamma[obs_seq == k, j]) / np.sum(gamma[:, j])
    
    return pi, A, B

# 示例观测序列和参数
obs_seq = [0, 1, 2, 0, 1, 2]
N = 2  # 隐藏状态数
M = 3  # 观测状态数
pi_learned, A_learned, B_learned = baum_welch_algorithm(obs_seq, N, M)
print("学习后的初始概率:", pi_learned)
print("学习后的转移矩阵:", A_learned)
print("学习后的观测矩阵:", B_learned)
注意事项
  • 观测序列的输入应为整数索引(例如,0表示第一个观测值)。
  • 实际应用中需处理数值下溢问题(通常使用对数概率)。
  • 对于大规模数据集,建议使用优化库(如hmmlearn)。
总结

隐马尔可夫模型通过隐藏状态和观测序列的关系,为时序数据分析提供了强大的工具。从罐子问题出发,可以直观理解其核心概念,而数学上的严格定义使其能够广泛应用于实际任务。理解 HMM 不仅有助于掌握经典的概率图模型,也为学习更复杂的时序模型(如循环神经网络)奠定了基础。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解隐马尔可夫模型:从罐子问题说起
    • 罐子问题的场景
    • 隐马尔可夫模型的基本假设
    • HMM 的数学表示
    • 应用与扩展
  • 隐马尔可夫模型(HMM)代码实践
    • 初始化参数
    • 前向算法(Forward Algorithm)
    • 维特比算法(Viterbi Algorithm)
    • 鲍姆-韦尔奇算法(Baum-Welch Algorithm)
    • 注意事项
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档