my HMM

HMM 模型

本节对隐马尔可夫模型进行了详细的公式推导,并实现了 HMM 模型中涉及到的三个经典问题。

公式推导

HMM 模型涉及到大量公式,本文以《统计学习方法》为基础对其中的公式进行了推导,为方便起见,以手写的形式进行了记录,字丑莫怪。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

HMM 代码实现

本部分对上述公式进行了实现,涉及到了 HMM 模型中的前向算法、后向算法、baumwelch算法和viterbi算法,即分别对应第一部分中的概率计算、学习和预测。

import numpy as np


class HMM:
    def __init__(self, pi, A, B):
        self.pi = pi  # 初始隐状态概率矩阵
        self.A = A  # 转移概率矩阵
        self.B = B  # 发射概率矩阵
        self.alpha = None
        self.beta = None

    def forward(self, O):
        T = len(O)  # 观测序列长度
        N = len(self.A)  # 状态数
        alpha = np.zeros([T, N])  # 初始化alpha矩阵

        # alpha_1(i)=p_i*b_i(o_1)
        alpha[0, :] = self.pi * self.B[:, O[0]]
        for t in range(1, T):
            # alpha_t+1(i)=\sum_j{alpha_t(j)*a_ji}*b_i(o_t+1)
            alpha[t, :] = np.sum(alpha[t - 1, :] * self.A.T, axis=1) * self.B[:, O[t]]
        # print(alpha)
        self.alpha = alpha  # shape: N * T

        return np.sum(alpha[-1, :])

    def backward(self, O):
        T = len(O)  # 观测序列长度
        N = len(self.A)  # 状态数
        beta = np.zeros([T, N])  # 初始化beta矩阵

        # beta_T=1
        beta[-1, :] = 1
        for t in range(T - 2, -1, -1):
            # beta_t(i)=\sum_j{beta_t+1(j)*a_ij*b_j(o_t+1)}
            beta[t, :] = np.sum(beta[t + 1, :] * self.A * self.B[:, O[t + 1]], axis=1)
        # print(beta)
        self.beta = beta  # shape: N * T

        # \sum_i{pi_i*b_i(o_1)*beta_1(i}
        return np.sum(self.pi * self.B[:, O[0]] * beta[0, :])

    def baumwelch(self, O, criterion=0.001):
        T = len(O)
        N = len(self.A)
        while True:
            self.forward(O)
            self.backward(O)

            # 求gamma, shape: T * N
            molecular1 = self.alpha * self.beta
            denominator1 = np.sum(molecular1, axis=1).reshape(-1, 1)
            gamma = molecular1 / denominator1

            # 求xi, shape: T * N * N
            xi = np.zeros([T - 1, N, N])
            for t in range(T - 1):
                molecular2 = self.alpha[t, :].reshape(1, -1) * self.A.T * self.B[:, O[t + 1]].reshape(-1,
                                                                                                      1) * self.beta[
                                                                                                           t + 1,
                                                                                                           :].reshape(
                    -1, 1)
                denominator2 = np.sum(molecular2)
                xi[t, :, :] = molecular2.T / denominator2

            # 递推
            newpi = gamma[0, :]
            newA = np.sum(xi, axis=0) / np.sum(gamma[:-1, :], axis=0).reshape(-1, 1)
            newB = np.zeros(self.B.shape)
            for k in range(self.B.shape[1]):
                mask = (O == k)
                newB[:, k] = np.sum(gamma[mask, :], axis=0) / np.sum(gamma, axis=0)

            # 终止
            if np.max(abs(self.pi - newpi)) < criterion and \
                    np.max(abs(self.A - newA)) < criterion and \
                    np.max(abs(self.B - newB)) < criterion:
                break

            self.A, self.B, self.pi = newA, newB, newpi

    def viterbi(self, O):
        # 初始化T1表、T2表
        T, N = len(O), len(self.A)
        T1_table = np.zeros([N, T])
        T2_table = np.zeros([N, T])

        # 时刻1
        T1_table[:, 0] = self.pi * self.B[:, O[0]]
        T2_table[:, 0] = np.nan

        for i in range(1, T):
            # 时刻t
            curr_score = T1_table[:, i - 1].reshape(1, -1) * self.A.T * self.B[:, O[i]].reshape(-1, 1)

            # 存入T1 T2中
            T1_table[:, i] = np.max(curr_score, axis=-1)
            T2_table[:, i] = np.argmax(curr_score, axis=-1)

        # 回溯
        best_tag_id = int(np.argmax(T1_table[:, -1]))
        best_tags = [best_tag_id]
        for i in range(T - 1, 0, -1):
            best_tag_id = int(T2_table[best_tag_id, i])
            best_tags.append(best_tag_id)
        return list(reversed(best_tags))

参考资料

《统计学习方法》
https://cloud.tencent.com/developer/article/1526748
https://www.bilibili.com/video/BV1aE411o7qd?p=82

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值