HMM隐马尔可夫模型进行中文文本分词

HMM在文本分类中的应用:维特比算法详解
本文详细介绍了如何使用隐马尔可夫模型(HMM)进行文本分类,包括HMM的原理、前向算法和维特比算法的运用。重点讲解了如何通过维特比算法找到最可能的隐藏状态序列,以及在中文分词中的具体实现,如状态转移、混淆矩阵和参数估计。

一、HMM简述

1.引入

民间传说告诉我们水藻的状态与天气状态有一定的概率关系——天气和水藻的状态是紧密相关的。在这个例子中我们有两组状态,观察的状态(水藻的状态)和隐藏的状态(天气的状态)。

​ 现在我们定义一个一阶马尔科夫过程如下:

  • 状态:三个状态——晴天,多云,雨天。

  • pi向量:定义系统初始化时每一个状态的概率。

  • 状态转移矩阵:给定前一天天气情况下的当前天气概率。

    任何一个可以用这种方式描述的系统都是一个马尔科夫过程

​ 除了定义了马尔科夫过程的概率关系,我们还有另一个矩阵,定义为混淆矩阵(confusion matrix),它包含了给定一个隐藏状态后得到的观察状态的概率。对于天气例子,混淆矩阵是:
  weather-b-matrix
  注意矩阵的每一行之和是1。


我们使用一个隐马尔科夫模型(HMM)对这些例子建模。这个模型包含两组状态集合和三组概率集合:

  • 隐藏状态:一个系统的(真实)状态,可以由一个马尔科夫过程进行描述(例如,天气)。
  • 观察状态:在这个过程中‘可视’的状态(例如,海藻的湿度)。
  • pi向量:包含了(隐)模型在时间t=1时一个特殊的隐藏状态的概率(初始概率)。
  • 状态转移矩阵:包含了一个隐藏状态到另一个隐藏状态的概率
  • 混淆矩阵:包含了给定隐马尔科夫模型的某一个特殊的隐藏状态,观察到的某个观察状态的概率。

因此一个隐马尔科夫模型是在一个标准的马尔科夫过程中引入一组观察状态,以及其与隐藏状态间的一些概率关系。

2.隐马尔科夫模型

(1)定义(Definition of a hidden Markov model)

一个隐马尔科夫模型是一个三元组(pi, A, B)。
  Triple_PI:初始化概率向量;
  Triple_A:状态转移矩阵;Triple_A_2
  Triple_B:混淆矩阵;Triple_B_2
  在状态转移矩阵及混淆矩阵中的每一个概率都是时间无关的——也就是说,当系统演化时这些矩阵并不随时间改变。实际上,这是马尔科夫模型关于真实世界最不现实的一个假设。

(2)应用

1. 对于一个观察序列匹配最可能的系统——评估,使用前向算法(forward algorithm)解决;
  2. 对于已生成的一个观察序列,确定最可能的隐藏状态序列——解码,使用Viterbi 算法(Viterbi algorithm)解决;
  3. 对于已生成的观察序列,决定最可能的模型参数——学习,使用前向-后向算法(forward-backward algorithm)解决。

3.前向算法(了解)

4. 维特比算法

寻找最可能的隐藏状态序列(Finding most probable sequence of hidden states)

对于一个特殊的隐马尔科夫模型(HMM)及一个相应的观察序列,我们常常希望能找到生成此序列最可能的隐藏状态序列。

​ 我们使用下面这张网格图片来形象化的说明隐藏状态和观察状态之间的关系:
网格
  我们可以通过列出所有可能的隐藏状态序列并且计算对于每个组合相应的观察序列的概率来找到最可能的隐藏状态序列。最可能的隐藏状态序列是使下面这个概率最大的组合:

​ 给定一个观察序列和一个隐马尔科夫模型(HMM),我们将考虑递归地寻找最有可能的隐藏状态序列。我们首先定义局部概率delta,它是到达网格中的某个特殊的中间状态时的概率。然后,我们将介绍如何在t=1和t=n(>1)时计算这些局部概率。

这些局部概率与前向算法中所计算的局部概率是不同的,因为它们表示的是时刻t时到达某个状态最可能的路径的概率,而不是所有路径概率的总和。

​ 考虑下面这个网格,它显示的是天气状态及对于观察序列干燥,湿润及湿透的一阶状态转移情况:
   [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AvcaEJ7d-1633176787522)(https://www.52nlp.cn/images/trellis.1.gif)]
  对于网格中的每一个中间及终止状态,都有一个到达该状态的最可能路径。举例来说,在t=3时刻的3个状态中的每一个都有一个到达此状态的最可能路径,或许是这样的:
  paths.for.t_3
  我们称这些路径局部最佳路径(partial best paths)。其中每个局部最佳路径都有一个相关联的概率,即局部概率或delta

​ 因而delta是t时刻到达状态i的所有序列概率中最大的概率,而局部最佳路径是得到此最大概率的隐藏状态序列。对于每一个可能的i和t值来说,这一类概率(及局部路径)均存在。
  特别地,在t=T时每一个状态都有一个局部概率和一个局部最佳路径。这样我们就可以通过选择此时刻包含最大局部概率的状态及其相应的局部最佳路径来确定全局最佳路径(最佳隐藏状态序列)。

2b.计算t=1时刻的局部概率delta’s
  我们计算的局部概率delta是作为最可能到达我们当前位置的路径的概率(已知的特殊知识如观察概率及前一个状态的概率)。当t=1的时候,到达某状态的最可能路径明显是不存在的;但是,我们使用t=1时的所处状态的初始概率及相应的观察状态k1的观察概率计算局部概率delta;即
在这里插入图片描述

——与前向算法类似,这个结果是通过初始概率和相应的观察概率相乘得出的。

2c.计算t>1时刻的局部概率delta’s
  现在我们来展示如何利用t-1时刻的局部概率delta计算t时刻的局部概率delta
  考虑如下的网格:
    abcxtrellis
  我们考虑计算t时刻到达状态X的最可能的路径;这条到达状态X的路径将通过t-1时刻的状态A,B或C中的某一个。
  因此,最可能的到达状态X的路径将是下面这些路径的某一个
       (状态序列),…,A,X
       (状态序列),…,B,X
或      (状态序列),…,C,X
  我们想找到路径末端是AX,BX或CX并且拥有最大概率的路径。
  回顾一下马尔科夫假设:给定一个状态序列,一个状态发生的概率只依赖于前n个状态。特别地,在一阶马尔可夫假设下,状态X在一个状态序列后发生的概率只取决于之前的一个状态,即
   Pr (到达状态A最可能的路径) .Pr (X | A) . Pr (观察状态 | X)
  与此相同,路径末端是AX的最可能的路径将是到达A的最可能路径再紧跟X。相似地,这条路径的概率将是:
   Pr (到达状态A最可能的路径) .Pr (X | A) . Pr (观察状态 | X)
  因此,到达状态X的最可能路径概率是:
在这里插入图片描述

其中第一项是t-1时刻的局部概率delta,第二项是状态转移概率以及第三项是观察概率。
  泛化上述公式,就是在t时刻,观察状态是kt,到达隐藏状态i的最佳局部路径的概率是:
     6.1.2.3_b
  这里,我们假设前一个状态的知识(局部概率)是已知的,同时利用了状态转移概率和相应的观察概率之积。然后,我们就可以在其中选择最大的概率了(局部概率delta)。

2d.反向指针,phi's
  考虑下面这个网格
   [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TgZutUr-1633176787532)(https://www.52nlp.cn/images/trellis.1.gif)]

在每一个中间及终止状态我们都知道了局部概率,delta(i,t)。然而我们的目标是在给定一个观察序列的情况下寻找网格中最可能的隐藏状态序列——因此,我们需要一些方法来记住网格中的局部最佳路径。
  回顾一下我们是如何计算局部概率的,计算t时刻的delta’s我们仅仅需要知道t-1时刻的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCyrw9NR-1633176787535)(https://www.52nlp.cn/images/delta.gif)]'s。在这个局部概率计算之后,就有可能记录前一时刻哪个状态生成了delta(i,t)——也就是说,在t-1时刻系统必须处于某个状态,该状态导致了系统在t时刻到达状态i是最优的。这种记录(记忆)是通过对每一个状态赋予一个反向指针phi完成的,这个指针指向最优的引发当前状态的前一时刻的某个状态。
  形式上,我们可以写成如下的公式
    6.1.2.4_a
  其中argmax运算符是用来计算使括号中表达式的值最大的索引j的。
  请注意这个表达式是通过前一个时间步骤的局部概率delta’s和转移概率计算的,并不包括观察概率(与计算局部概率本身不同)这是因为我们希望其能回答这些问题:“如果我在这里,最可能通过哪条路径到达下一个状态?"——这个问题与隐藏状态有关,因此与观察概率有关的混淆(矩阵)因子是可以被忽略的。

2e.维特比算法的优点

​ 通过使用递归减少计算复杂度——这一点和前向算法使用递归减少计算复杂度是完全类似的。

算法总结

1、维特比算法的形式化定义
  在这里插入图片描述

5.前向-后向算法(了解)

根据观察序列生成隐马尔科夫模型(Generating a HMM from a sequence of obersvations)

与HMM模型相关的“有用”的问题是评估(前向算法)和解码(维特比算法)——它们一个被用来测量一个模型的相对适用性,另一个被用来推测模型隐藏的部分在做什么(“到底发生了”什么)。可以看出它们都依赖于隐马尔科夫模型(HMM)参数这一先验知识——状态转移矩阵,混淆(观察)矩阵,以及pi向量(初始化概率向量)。
  然而,在许多实际问题的情况下这些参数都不能直接计算的,而要需要进行估计——这就是隐马尔科夫模型中的学习问题。前向-后向算法就可以以一个观察序列为基础来进行这样的估计,而这个观察序列来自于一个给定的集合,它所代表的是一个隐马尔科夫模型中的一个已知的隐藏集合。
  前向-后向算法首先对于隐马尔科夫模型的参数进行一个初始的估计(这很可能是完全错误的),然后通过对于给定的数据评估这些参数的的价值并减少它们所引起的错误来重新修订这些HMM参数。从这个意义上讲,它是以一种梯度下降的形式寻找一种错误测度的最小值。

EM 算法
  假定集合Z = (X,Y。)由观测数据 X 和未观测数据Y 组成,Z = (X,Y)和 X 分别称为完整数据和不完整数据。假设Z的联合概率密度被参数化地定义为P(X,Y|Θ),其中Θ 表示要被估计的参数。Θ 的最大似然估计是求不完整数据的对数似然函数L(X;Θ)的最大值而得到的:
   L(Θ; X )= log p(X |Θ) = ∫log p(X ,Y |Θ)dY ;(1)
  EM算法包括两个步骤:由E步和M步组成,它是通过迭代地最大化完整数据的对数似然函数Lc( X;Θ )的期望来最大化不完整数据的对数似然函数,其中:
   Lc(X;Θ) =log p(X,Y |Θ) ; (2)
  假设在算法第t次迭代后Θ 获得的估计记为Θ(t ) ,则在(t+1)次迭代时,
  E-步:计算完整数据的对数似然函数的期望,记为:
   Q(Θ |Θ (t) ) = E{Lc(Θ;Z)|X;Θ(t) }; (3)
  M-步:通过最大化Q(Θ |Θ(t) ) 来获得新的Θ 。
  通过交替使用这两个步骤,EM算法逐步改进模型的参数,使参数和训练样本的似然概率逐渐增大,最后终止于一个极大点。
  直观地理解EM算法,它也可被看作为一个逐次逼近算法:事先并不知道模型的参数,可以随机的选择一套参数或者事先粗略地给定某个初始参数λ0 ,确定出对应于这组参数的最可能的状态,计算每个训练样本的可能结果的概率,在当前的状态下再由样本对参数修正,重新估计参数λ ,并在新的参数下重新确定模型的状态,这样,通过多次的迭代,循环直至某个收敛条件满足为止,就可以使得模型的参数逐渐逼近真实参数。
  EM算法的主要目的是提供一个简单的迭代算法计算后验密度函数,它的最大优点是简单和稳定,但容易陷入局部最优。

二、使用HMM进行文本分类

1.问题分析

将文本分类用HMM模型来描述

(1)模型中的隐藏状态

在中文分词中一般只有4个状态:STATES={‘B’,‘I’,‘E’,‘S’},

  • B:代表一个词的开始
  • I :代表一个词的中间部分,若词为两个字则没有I
  • E:代表一个词的结束
  • S:代表一个单独的字作为一个词

例如:小明是中国人,对应的状态序列就是:B,E,S,B,I,E

(2)观察状态

在中文分词中就是对应每一个字符

(3)状态转移矩阵A

在中文分词中就是状态序列STATES={‘B’,‘I’,‘E’,‘S’}的转移概率,这个状态概率矩阵是在训练阶段参数估计中得到。在中文分词中状态转移矩阵是一个4*4的矩阵,

{'B': {'B': 0.0, 'I': 0.0, 'E': 0.0, 'S': 0.0}, 
'I': {'B': 0.0, 'I': 0.0, 'E': 0.0, 'S': 0.0},
'E': {'B': 0.0, 'I': 0.0, 'E': 0.0, 'S': 0.0}, 
'S': {'B': 0.0, 'I': 0.0, 'E': 0.0, 'S': 0.0}}

(4)混淆矩阵(发射概率矩阵)B

在中文分词中发射概率指的是每一个字符对应状态序列STATES={‘B’,‘M’,‘E’,‘S’}中每一个状态的概率,通过对训练集每个字符对应状态的频数统计得到。

img

2. 代码流程

首先定义类

class HMMModel:

初始化模型参数:

    def __init__(self): 
        self.A = {
   
   }  # 状态转移概率矩阵
        self.B = {
   
   }  # 发射概率矩阵
        self.PI = {
   
   }  # 初始状态矩阵
        self.stateSet = [] # 存放状态
        self.state_num = {
   
   }  # ‘B,I,E,S’每个状态在训练集中出现的次数
        self.Sentence_Num = 0  # 训练集语句数量
    # 初始化所有概率矩阵
    def initArray(self):
        #初始化状态矩阵
        self.stateSet = ['B', 'I', 'E', 'S']
        # 初始化状态转移矩阵
        for state0 in self.stateSet:
            self.A[state0] 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值