AI算法工程师 | 09机器学习-概率图模型(三)隐马尔可夫模型 HMM

机器学习 - 概率图模型 之 隐马尔可夫模型 HMM

一、马尔科夫链

回顾:概率图模型的分类

概率图模型

  • HMM(隐马尔可夫模型)属于贝叶斯网络(有向图模型)的一种——是最简单的动态贝叶斯网络。

马尔可夫过程(Markov Processes)

马尔科夫过程

  • 定义:假设一个随机过程中, t n t_n tn 时刻的状态 s n s_n sn 的条件分布,仅仅与其前一个状态 s n − 1 s_{n-1} sn1 有关,即 P ( s n ∣ s 1 , s 2 , … , s n − 1 ) = P ( s n ∣ s n − 1 ) P(s_n|s_1,s_2,\ldots,s_{n-1})=P(s_n|s_{n-1}) P(sns1,s2,,sn1)=P(snsn1) ,则将其称为马尔可夫过程。

  • 特性:在已知系统当前状态的条件下,它未来的演变不依赖于过去的演变。

    • 也就是说,一个马尔可夫过程可以表示为:系统在状态转移过程中,第 t+1 次结果只受第 t 次结果的影响,即只与当前状态有关,而与过去状态(系统的初始状态和此次转移前的所有状态)无关。
  • 注意:马尔可夫过程其原始模型是马尔可夫链。

马尔科夫链(Markov Chain)
马尔可夫链

  • 定义:时间、状态都是离散的马尔可夫过程称为马尔可夫链。
  • 注意:隐马尔可夫模型是对含有未知参数(隐变量)的马尔科夫链进行建模的生成模型。

二、HMM 的基本概念

1、HMM 背景与定义

提出背景
背景

HMM 的定义

HMM 的定义

  • 隐马尔可夫模型(Hidden Markov Model, HMM)描述由隐藏的马尔科夫链生成观测序列的过程:

    • 一条隐藏的马尔可夫链随机生成了一个不可观测的状态序列(state sequence);
    • 然后每个状态又对应生成了一个观测结果,这些观测值按照时序排列后就成了观测序列(observation sequence)。
    • 这两个序列(状态序列、观测序列)是一一对应的,每个对应的位置又对应着一个时刻。
  • HMM 是一个关于时序的概率模型,它的变量分为两组:

    • ① 状态变量 s 1 , s 2 , . . . , s n {s_1,s_2,...,s_n} s1,s2,...,sn,如: s t s_t st 表示 t t t 时刻的系统状态;
    • ② 观测变量 o 1 , o 2 , . . . , o n {o_1,o_2,...,o_n} o1,o2,...,on,如: o t o_t ot 表示 t t t 时刻的观测值。
    • 状态变量和观测变量各自都是一个时间序列,每个状态/观测值都和一个时刻相对应。
  • HMM(Hidden Markov Model)各字母的含义:

    • 一般假定状态序列是隐藏的,不能被观测到的,因此状态变量是隐变量,这就是 HMM 中的 H(Hidden)的来源。
    • 这个隐藏的,不可观测的状态序列是由一个马尔可夫链随机生成的,这是 HMM 中的第一个 M(Markov)的含义。
  • 状态变量与观测变量的取值:

    • 一般而言,HMM 的状态变量取值是离散的;而观测变量的取值,则可以是离散的,也可以是连续的。
    • 不过为了方便讨论,也因为在大多数应用中观测变量也是离散的,因此,我们下面仅讨论状态变量和观测变量都是离散的情况。

2、HMM 的两个基本假设

两个假设:① 齐次马尔可夫假设、② 观测独立性假设

两个假设

3、确定 HMM 的两个空间和三组参数

两个空间:① 状态空间 Q、② 观测空间 V

两个空间

三组参数:① 状态初始概率分布 π、② 状态转移矩阵 A、③ 观测概率矩阵 B(又称:发射概率矩阵、混淆矩阵)

三组参数

三、HMM 三个基本问题 | 导图

三个基本问题:① 概率计算问题、② 预测问题、③ 学习问题

导图:
三个基本问题

四、HMM 相关算法

下面通过一个示例,分别使用前向算法求观测序列的概率、用维特比算法处理预测问题——目的:了解前向算法、维特比算法的思想

示例

1、前向算法

导图:前向算法的流程梳理
前向算法的流程

示例:使用前向算法求 HMM 观测序列的概率

示例
1
2
3
4

2、维特比(Viterbi)算法

导图:维特比算法的流程梳理
维特比算法的流程

示例:维特比算法解码隐藏状态序列(预测问题)

示例
思路

时刻1
时刻2
时刻3
结果

五、案例:Viterbi 算法的代码实现

案例分析
案例分析1
案例分析2

代码实现:( 工具:PyCharm,基于:python3)

"""
维特比(Viterbi)算法处理预测问题
⭐ 学习时间:2023.1.27
"""


def viterbi(obs, states, start_p, trans_p, emit_p):
    """
    :param obs:观测序列
    :param states:隐状态
    :param start_p:初始概率(隐状态)
    :param trans_p:转移概率(隐状态)
    :param emit_p: 发射概率 (隐状态表现为显状态的概率)
    :return:
    """
    
    V = [{}]  # 路径概率表 V[时间][隐状态] = 概率
    path = {}  # 一个中间变量,代表当前状态是哪个隐状态

    # ------ 初始化初始状态 (t == 0) ------ 
    for y in states:
        V[0][y] = start_p[y] * emit_p[y][obs[0]]
        path[y] = [y]
    print(V[0])
    print(path)

    # ------ 对 t > 0 跑一遍维特比算法 ------ 
    for t in range(1, len(obs)):
        V.append({})
        newpath = {}

        for y in states:
            # 概率 隐状态 =    前状态是y0的概率 * y0转移到y的概率 * y表现为当前状态的概率。注:下面包含了一个列表生成式
            (prob, state) = max([(V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0)
                                 for y0 in states])

            V[t][y] = prob  # 记录最大概率
            newpath[y] = path[state] + [y]  # 记录路径

        print(V[t])

        path = newpath  # 不需要保留旧路径
        print(path)
        
    (prob, state) = max([(V[len(obs) - 1][y], y) for y in states])
    return prob, path[state]


if __name__ == '__main__':
    states = ('Rainy', 'Sunny')  # 隐状态
    observations = ('walk', 'shop', 'clean')  # 观测序列
    start_probability = {'Rainy': 0.6, 'Sunny': 0.4}  # 状态初始概率分布 π
    # 状态转移矩阵 A
    transition_probability = {
        'Rainy': {'Rainy': 0.7, 'Sunny': 0.3},
        'Sunny': {'Rainy': 0.4, 'Sunny': 0.6},
    }
    # 观测概率矩阵 B(又称:发射概率矩阵、混淆矩阵)
    emission_probability = {
        'Rainy': {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
        'Sunny': {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
    }

    result = viterbi(observations,
                     states,
                     start_probability,
                     transition_probability,
                     emission_probability)

    print(result)

运行结果:

运行结果

补充:下面是上述代码中涉及的部分 python 知识点梳理

  • 在 viterbi 函数中,(prob, state) = max([(V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states]) 包含了 python 的列表生成式
    • 含义:
      # 概率 隐状态 =   前状态是y0的概率 * y0转移到y的概率 * y表现为当前状态的概率。
      (prob, state) = max([(V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0)
                               for y0 in states])
      """ 
      代码解析:(结合完整代码进行理解)
      ① 列表生成式: [(V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states]
      	—— 循环获取 states 中的每个状态,计算概率,并分别以 (概率,前状态) 元组的形式呈现,然后用列表依次装着这些元组;
      ② max(...) 对列表中的元组取最大值,元组是逐位比较大小的:
      	—— 将第一个元组的第一项与第二元组的第一项进行比较,若它们不相等(即第一个大于或小于第二个)那么这就是比较的结果。否则考虑第二项,然后是第三项,依此类推。
      ③ 将最终得到的元组 如 (0.01344, 'Rainy') 中的元素值分别对应赋值给 prob、state ,即:prob=0.01344、state='Rainy'。
      """
      
    • 示例:列表生成式
      示例

—— 说明:本文写于 2023.1.27~1.29,文中内容基于 python3,使用工具 PyCharm 编写的代码

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
HMM是一种常见的统计模型,用于描述随机生成的序列。Viterbi算法是一种在HMM中进行解码的动态规划算法,用于寻找最可能的隐藏状态序列。下面是HMM的MATLAB实现,包括Viterbi算法。 首先,我们需要定义一个HMM模型。我们假设这个模型有3个隐藏状态和2个可见状态。我们使用矩阵A表示隐藏状态之间的转移概率,矩阵B表示每个隐藏状态生成每个可见状态的概率,向量pi表示初始隐藏状态的概率分布。 ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; ``` 接下来,我们需要生成一个可见序列。我们使用HMM模型中的随机过程生成一个长度为10的可见序列。 ```matlab % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end ``` 接下来,我们使用Viterbi算法解码这个可见序列,得到最可能的隐藏状态序列。我们定义一个矩阵V表示每个时间步的最大概率,以及一个矩阵path表示每个时间步的最大概率对应的前一个状态。 ```matlab % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end ``` 最后,我们找到最可能的隐藏状态序列。我们首先找到最后一个时间步的最大概率对应的隐藏状态,然后从后往前依次寻找每个时间步的最大概率对应的隐藏状态,最终得到整个隐藏状态序列。 ```matlab % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ``` 完整代码如下: ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值