浅谈自然语言处理基础(上)

本系列第三篇,承接前面的《浅谈机器学习基础》和《浅谈深度学习基础》。

自然语言处理绪论

什么是自然语言处理?

自然语言处理是研究人与人交际中以及人与计算机交际中的语言问题的一门学科。自然语言处理要研制表示语言能力和语言应用的模型,建立计算框架来实现这样的语言模型,提出相应的方法来不断完善这样的语言模型,根据这样的语言模型设计各种实用系统,并探讨这些实用系统评测技术。

一般认为,自然语言处理中存在两种不同的研究方法,一种是理性主义方法,一种是经验主义方法。

理性主义的代表人物是乔姆斯基,主张建立符号处理系统,试图刻画人类思维的模型或方法,由人工编写自然语言处理规则。系统根据规则将自然语言理解为符号结构,再通过符号的意义推导出该结构的意义。

按这种思路,在自然语言处理系统中,一般先由词法分析器按照人编写的词法规则对输入句子的单词进行词法分析,然后,语法分析器根据人设计的语法规则对输入句子进行句法分析,最后再根据一套变换规则将语法结构映射到语义符号(如逻辑表达式,语义网络,中间语言等),进行语义分析

而经验主义认为,人脑并不是从一开始就具有一些具体的处理原则和对具体语言成分的处理方法,而是假定孩子的大脑一开始具有处理联想、模式识别和泛化处理的能力,这些能力能够使孩子充分利用感官输入来掌握具体的自然语言处理结构。

理性主义试图刻画的是人类思维的模型或方法。对于这种方法而言,某种语言的真实文本数据只是提供间接地证据。而经验主义方法则直接关心如何刻画这种真实的语言本身。

在系统实现方法上,经验主义方法主张通过建立特定的数学模型来学习复杂的、广泛的语言结构,然后利用统计学、模式识别和机器学习等方法来训练模型的参数,以扩大语言使用的规模。因此,经验主义的自然语言处理方法是建立在统计方法基础之上的,因此,我们称其为统计自然语言处理。

20世纪20年代到60年代的近40年里,经验主义处于主导地位;
大约从20世纪60年代中期到20世纪80年代中后期,理性主义的研究方法控制着自然语言处理等领域的研究;
大约在20世纪80年代后期,人们越来越关注工程化、实用化的解决问题方法,经验主义方法被人们重新认识并得到迅速发展,人们开始倾向于结合经验主义与理性主义的方法。

预备知识

H(X)又称自信息,是描述一个随机变量不确定性大小的量,熵越大则不确定性越大,则需要用更多的信息量来消除这种不确定性。前面《浅谈机器学习基础》中讲决策树的时候就提到了香农熵。

在只掌握关于未知分布的部分知识的情况下,符合已知知识的概率分布可能有多个,但使熵值最大的概率分布真实的反映了事件的分布情况。以此为依据构建的模型叫做最大熵模型,后面会详细讲,这里只做简单介绍。

然后是联合熵H(X,Y)条件熵H(Y|X)互信息I(X;Y)

联合熵、条件熵、互信息

H(X)是描述一个随机变量X所需要的信息量,而联合熵H(X,Y)就是描述两个随机变量XY所需要的信息量,联合熵大于或等于这两个变量中任一个的熵。

互信息I(X;Y)描述的是两个随机变量XY之间的相关性,也即已知X后,Y不确定性的减少量(熵H(Y)的减少量),反之亦成立。换句话讲,XY关联越大,越相关,则互信息I(X;Y)越大。

条件熵H(Y|X)就是在已知X的条件下,Y的熵。因为互信息I(X;Y)的存在,已知X会使Y的熵减少,减少后的Y的熵就是H(Y|X)

从图中也可以看出:H(X,Y) = H(X) + H(Y|X) = H(Y) + H(X|Y)。回想一下,是不是和条件概率的计算公式有相似的地方。

接下来是相对熵D(p||q),相对熵又称Kullback-Leibler差异,或简称KL距离,是衡量相同事件空间里两个概率分布相对差距的测度,当两个随机分布完全相同时,相对熵为0。当两个随机分布的差别增加时,其相对熵期望值也增大。

然后是交叉熵H(X,q)X是随机变量,q是模型。我们前面讲过交叉熵损失函数,交叉熵的概念就是用来衡量估计模型与真实概率分布之间差异情况的。而困惑度的概念与交叉熵相似,交叉熵对应的困惑度的计算方式为:2的交叉熵次方。交叉熵与困惑度都是越小越证明模型有效。

形式语言与自动机

在乔姆斯基的语法理论中,文法被划分为4种:3型文法、2型文法、1型文法和0型文法,分别称为正则文法、上下文无关文法、上下文相关文法和无约束文法。从0型文法到3型文法,对规则的约束越来越多,每一个正则文法都可以被认为是上下文无关文法,每一个上下文无关文法都是上下文有关文法,而每一个上下文有关文法都可以认为是0型文法。

正则文法要求所有含非终结符号的规则形式为A->Bx(或A->xB),分别为左线性正则文法和右线性正则文法。

上下文无关文法不要求所有含非终结符号的规则右侧为BxxB

上下文相关文法对左侧的A增加了上下文要求,也即αAβ->αγβ,只有A前为αA后为β才能进行状态转换,也可以看出,若αβ为空,也即成为了上下文无关文法。

自动机因为后面并没有用到,所以这里只简单提一下。

正则文法与有限状态自动机(FA)一一对应,FA是为研究有限内存的计算过程和某些语言类而抽象出的一种计算模型。有限状态自动机拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。有限状态自动机可以表示为一个有向图。FA又分为确定有限状态自动机(DFA)和不确定有限状态自动机(NFA),NFA可以转化为DFA。

上下文无关文法与下推自动机(PDA)一一对应。上下文相关文法与线性界限自动机相对应。无约束文法与图灵机一一对应。

语料库与语言知识库

自然语言处理系统离不开数据和知识库的支持。语料库(corpus base)就是存放语言材料的数据库,而语言知识库比语料库包含更广泛的内容,可以分为两种不同的类型:一类是词典、规则库、语义概念库等,分别与解析过程中的词法分析、句法分析和语义分析相对应;另一类语言知识存在于语料库之中,每个语言单位的出现,其范畴、意义、用法都是确定的。

这部分内容我主要想讲两种为我带来启发的知识库组织形式。

首先是知网

知网的概念关系示意图

它着力反映概念的共性和个性,比如对于『患者』与『医生』,他们的共性是『人』,同时又具有个性,与类之间的继承关系相似;此外,还反映了概念之间以及概念的属性之间的各种关系,通过对各种关系的标注,知网把这种知识网络系统明确教给了计算机,进而使知识对计算机而言成为可计算的

知网定义了如下各种关系:上下位关系、同义关系、反义关系、对义关系、部件-整体关系、属性-宿主关系、材料-成品关系、施事/经验者/关系主体-事件关系(医生、雇主)、受事/内容/领属物等-事件关系(患者、雇员)、工具-事件关系(手表、计算机)、场所-事件关系(银行、医院)、时间-事件关系(假日、孕期)、值-属性关系(蓝、慢)、实体-值关系(矮子、傻瓜)、事件-角色关系(购物、盗墓)、相关关系(谷物、煤田)。

然后是动态演化认知架构系统(Dynamically Evolving Cognitive Architecture System,简称DECAS),DECAS是前苹果Siri开发团队离职后所设计的bot创建平台Viv所使用的技术。这部分介绍参考了Chatbot 4: Viv能搅动bot市场吗?

DECAS中主要包含了两种对象:概念对象(Concept Object)和动作对象(Action Object),其中概念对象指的就是实体,而动作对象就是执行的动作。

概念对象之间定义了两种关系:扩展(extension),相当于“is a”的关系,比如“跑步鞋”概念对象扩展自“鞋”概念对象;属性(property),相当于“has a”的关系,比如“跑步鞋”概念对象有属性“尺码”概念对象。

动作接收一些概念对象,然后产出一些新的概念对象,类似于函数有输入和输出。动作接收的概念对象包含了两类,一类是必须要有的,没有动作就没法执行;另一类是可选的,可有可无,类似提供了默认参数。

以概念和动作对象为节点,Viv构建了规模庞大的有向网络图。概念节点到动作节点的边表示此动作以此概念为输入参数,而动作节点到概念节点的边表示此动作的输出中包含了此概念。如果两个概念节点存在扩展或者属性关系,那么它们之间也会存在有向边。随着开发者不断把新的概念和动作对象加入到Viv系统,这个网络图会逐渐延伸,越来越大。借助于Viv的动态演化认知架构系统,Viv能做的事会随着网络图的增大而指数增长。

DECAS

举一个具体的例子,有条这样的问句『我是学生,买什么Asics跑步鞋合适呢?』,Viv首先将问句进行词法分析,得到语义组块序列,然后对其进行意图识别,意图分为两部分,一部分是目标概念对象,另一部分是条件概念对象。如下图:

Viv的核心技术就是利用DECAS找到从条件概念对象到目标概念对象的连通路径,Viv把一条路径称为一个计划(Plan)。

前面提到,动作接收一些概念对象,然后产出一些新的概念对象,如果执行一个动作就可以由条件到目标,那当然直接执行下这个动作就搞定了,但显然实际情况复杂得多。

举个例子,开发者定义了两种动作,1) transform_occupation_to_price,转化职业为价格偏好;2) rec_shoes_based_on_price,转化价格偏好为跑鞋推荐。也就是上图中的计划一,这样就实现了由条件概念对象到目标概念对象的推理。当然达到目标的计划也许并不只有一个,开发者可以为每个计划设定一个价值函数,DECAS则只需要选择价值最高的topN计划具体执行即可,或者做得更复杂,比如依据用户反馈实时调整计划。

如果一个计划包含的动作所需的必须输入概念对象缺失,那么就需要与用户进行多次交互以收集缺失概念对象的值,也即多轮对话。多轮对话的目的从来不应该是为了炫技或是强行提高与用户的对话轮数,而是帮助不能清晰表达自己意思的用户补全自己的需求。

语言模型

语言模型(language model,LM)在基于统计模型的语音识别、机器翻译、汉语自动分词和句法缝隙等相关研究领域得到了广泛的应用。

目前主要采用的是n元文法模型(n-gram model),这种模型构建简单、直接,但同时也因为数据缺乏而必须采取平滑(smoothing)算法。

一个语言模型通常构建为字符串s的概率分布p(s),这里p(s)试图反映的是字符串s作为一个句子出现的频率。

对于一个由l个基元(“基元”可以为字、词或短语等,为了表述方便,以后我们只用“词”来通指)构成的句子s=w1w2…wl,其概率计算公式可以表示为:

也即产生第i个词的概率是由已经产生的i-1个词w1w2…w(i-1)决定的,这i-1个词被称为第i个词的历史,随着历史长度的增加,不同历史数目按指数级增长,这会导致我们根本无法在训练数据中对参数进行估计。

所以我们假定,出现在第i个位置上的词wi仅与它前面的n-1个历史词有关,n取多少,我们就称其为几元文法模型,一般来讲,我们一般取n<=3来避免前面的自由参数过多的问题。

当n=1时,被称为一元文法模型(unigram或uni-gram或monogram),也即出现于第i位的词独立于历史,在《浅谈机器学习基础》中朴素贝叶斯算法中的朴素假设,实际上就是一元文法模型。

当n=2时,被称为二元文法模型(bigram或bi-gram),即出现在第i位的词只与它前面第一个历史词有关,二元文法模型又被称为一阶马尔可夫链。

三元文法模型被称为二阶马尔可夫链,记作trigram或tri-gram。

用于构建语言模型的文本被称为训练语料(training corpus)。训练语料的规模一般要有几百万个词。举个例子,我们通过训练语料计算出p(a|<BOS>)、p(b|a)、p(c|b)、p(d|c)、p(<EOS>|d),那我们自然就能得到句子a b c d的出现概率为上面的概率依次相乘。<BOS>为句首标志,<EOS>为句尾标志。上面的例子是bigram的,《浅谈机器学习基础》中的朴素贝叶斯算法给出了unigram下的计算方法,都是大同小异。

接下来是如何评价一个语言模型的性能。

首先,我们需要一个用于评价语言模型性能的测试集,然后按照上面的方法,我们计算测试集中每个句子的生成概率,然后将它们全部乘起来,即得到该测试集的生成概率,测试集的生成概率越大,则语言模型的效果越好。

当然我们也可以通过前面提到的交叉熵和困惑度作为评价语言模型性能的测度,交叉熵与困惑度越小越好,具体的计算方法比较复杂,这里不讲。

然后是数据平滑问题。

我们前面说了,我们要根据训练语料来计算词的出现概率,进而计算句子的生成概率,但是这样就有一个问题,如果我们的训练语料不那么全怎么办?

这样就会导致比如某一个概率p(b|a)为0,因为训练语料中没有出现过这样的词,但是p(b|a)真的应该为0吗,带a b的句子真的永远不会出现吗?显然不是的,只是概率小而已,但不应该为0。

所以我们需要进行数据平滑,为这些在训练语料中没有出现过的词分配一些概率,使其不为0。但因为总概率还要保持为1的,所以我们选择降低略微降低高概率词的概率来留出一部分概率分配给这些没在训练语料中出现过的词。

首先我们介绍一种经典的平滑方法,即古德-图灵(Good-Turing)估计法

nrn(r+1)的意思是训练语料中出现rr+1次的词的个数。rr+1自然就是它们在训练语料中实际出现的次数了。

上文提到,对于没有看见的事件,我们不能认为它发生的概率就是0,因此我们从概率的总量中分配一个很小的比例给这些没有看见的事件。所以对于任何一个出现了r次的n元语法,我们都假定其出现了r*次,r*的计算方法如上式所示。

首先我们将,r=0代入,可以发现新计算出来的r*已经不等于0了,也即为这些未出现的词分配了一定的出现概率。

我们用相对频度来估计出现了r次的词的概率和,也即r*nr/NN为训练语料的大小。

总概率是一定的,既然r=0的概率增加了,那谁的概率减少了呢?

我们考虑这样一个问题,一般出现次数越少的词的个数越多,也即出现一次的词的个数多于出现两次的词的个数,也多于出现三次的词的个数,这叫做Zipf定律。而且往往这种分布符合长尾理论,也即n2/n1要比n3/n2小,以此类推。

回到上面的式子中,n(r+1)是小于nr的,所以r*等于r+1乘以了一个小于1的数,这样一般情况下r*是小于r的,用r*替代r,代入r*nr/N中计算,可以发现其概率减小了。

而且,其实词在训练语料中的出现次数越少,依照训练语料对其概率进行估计的结果就越不可信,而越是不可信的,其概率就越应该被折扣。所以往往我们定一个阈值,出现次数大于这个阈值的,仍然用原来的r来表示其出现次数,概率不变;只对出现次数低于这个阈值的词,频率才下调,下调得到的频率总和给未出现的词。

这样,对于频率超过一定阈值的词,它们的概率估计就是它们在语料中的出现的相对频度,对于频率小于这个阈值的词,它们的概率估计就小于它们的相对频度,出现次数越少的,折扣越多(因为n2/n1要比n3/n2小,所以r越小,r*就比r小的越多,所以算出来的概率也就小的更多)。对于未看见的词,也给予了一个比较小的概率,这样所有词的概率估计都很平滑了。

而且这样估计了,求和之后就会发现,总概率仍然等于1。

古德-图灵估计法是种经典的平滑方法,但仍然存在很多的不足,比如,我们为没出现的词平均分配了概率。需要明确的一点是,前面提到过,这里的『词』并不都指真正意义上的词,举个例子,在二元语法中,a b是一个基元,是一个『词』,我们发现a b不存在,所以我们用古德-图灵估计法为所有不存在的基元平均的赋予概率,比如赋予了同样没出现过的a bc d同样的概率。但是我们考虑一个问题,如果a bc d都没出现过,但要是ab都出现过呢,如果ab的出现概率都很高,只是a b没有出现过而已,但对于cd,不仅c dcd也根本都没有出现过,那么a bc d应该被赋予相同的出现概率吗?显然不该,平滑二元文法模型时应该考虑到一元文法模型,根据低阶的语法模型分配由于减值而节省下来的剩余概率给未见事件,要比将剩余概率平均分配给未见事件要合理的多。这就是Katz平滑方法的思想。

其实还有不足,比如『San Francisco』这个词中的『Francisco』,它作为一元模型时出现的次数是非常多,但是它只会跟在『San』后面,如果我们根据上一段的思想,因为它的一元模型出现次数很多,就在平滑时为『Francisco』和别的词的搭配赋予了更高的概率,这显然也是不对的。所以使用的一元文法的概率不应该单纯和它的出现次数有关,而是与它前面的不同单词的数目成正比。这就是Kneser-Ney平滑方法的思想。

平滑的方法还有很多,当前平滑效果最好的方法就是在Kneser-Ney平滑方法上经过修正得到的。

概率图模型

概述

这部分将会讲到贝叶斯网络、马尔可夫模型、隐马尔可夫模型、层次化的隐马尔可夫模型、马尔可夫网络、最大熵模型、最大熵马尔可夫模型和条件随机场,可以说这一章是书名中『统计』两个字的核心。

常见的概率图模型

动态贝叶斯网络用于处理随时间变化的动态系统中的推断和预测问题。其中,隐马尔可夫模型(hidden Markov model,HMM)在语音识别、汉语自动分词与词性标注和统计机器翻译等若干语音语言处理任务中得到了广泛应用;卡尔曼滤波器则在信号处理领域有广泛的用途。马尔可夫网络又称马尔可夫随机场(MRF),马尔可夫网络下的条件随机场(CRF)广泛应用于自然语言处理中的序列标注、特征选择、机器翻译等任务,玻尔兹曼机近年来被用于依存句法分析和语义角色标注。

自然语言处理中概率图模型的演变

横向是由点到线(序列结构)、到面(图结构)。纵向是在一定条件下生成模型转变为判别式模型。

在《浅谈机器学习基础》中,我们也讲过了朴素贝叶斯算法和逻辑回归算法,了解了朴素贝叶斯算法是生成模型,而逻辑回归算法是判别模型。

朴素贝叶斯算法是先在不同类别的训练语料上构造一元文法模型,也即得到了计算联合概率分布所需的先验概率,然后依照贝叶斯公式通过联合概率分布计算测试语句在不同文法模型下的生成概率,选取生成概率最高的那个文法模型所对应的类别。

而逻辑回归算法是用的最大似然估计,先利用默认的参数和模型表示出训练集每个样本的生成概率,依次相乘得到整个训练集的生成概率,然后对模型参数进行优化,使得整个训练集的总生成概率最大化,当需要对测试样本进行分类时,不需要计算联合概率分布,直接代入训练好参数的模型即可。

这里再深入说一下生成模型与判别模型,生成模型与判别模型的本质区别在于模型中观测序列x和状态序列y之间的决定关系,前者假设y决定x,后者假设x决定y。我们通常说的模型输入序列就是x,而输出序列是y

生成模型认为,输出序列y按照一定的规律生成输入序列x,也即认为同一分类结果对应的输入具有一定规律,针对联合概率分布p(x,y)进行建模,并且通过估计使生成概率最大的生成序列来获取y,也即找出什么样的输出序列y最有可能生成输入序列x,这种情况下,y就是输入x后的输出,通过贝叶斯公式计算出来的p(y|x)可以这么理解,我们已经得到了输入序列x,这个输入序列是由怎样的输出序列y生成的呢?我们选取生成概率最大的生成序列y作为输入序列x的输出结果。典型的生成模型有:n元语法模型、HMM、朴素的贝叶斯分类器、概率上下文无关文法。

判别模型则符合传统的模型分类思想,认为输出序列y由输入序列x决定,直接对后验概率p(y|x)进行建模,它从x中提取特征,学习模型参数,使得条件概率符合一定形式的最优,也即判别模型知道输入序列x应该对应输出序列y1而不是y2。代表性的判别模型有:最大熵模型、条件随机场、支持向量机、最大熵马尔可夫模型、感知机等。

举一个不太恰当的例子,生成模型就是有3个男人y1y2y3,现在有一个小孩x,我们看x最像谁生的,谁就是x的爸爸。而判别模型就是,这个小孩x知道他爸爸的特征,x直接通过特征判断谁是他爸爸。(我这个例子举得真是太好了)

贝叶斯网络

一个简单的贝叶斯网络

贝叶斯网络是一种基于概率推理的数学模型,其理论基础是贝叶斯公式,其目的是通过概率推理处理不确定和不完整性问题。

形式上,如上图,一个贝叶斯网络就是一个有向无环图,节点表示随机变量,可以是可观测变量、隐含变量、未知参量或假设等;节点之间的有向边表示条件依存关系,箭头指向的节点依存于箭头发出的节点(父节点)。两个节点没有连接表示两个随机变量能够在某些特定情况下条件独立,而两个节点有连接关系表示两个随机变量在任何条件下都不存在条件独立。

每个节点还都与一个概率函数相关,如上图,对于事件『News』,T的概率为0.2、F的概率为0.8;对于事件『Sightseeing』,在『News』为F的情况下为T的概率0.4、为F的概率为0.6,在『News』为T的情况下为T的概率为0.1、为F的概率为0.9;事件『History』也是同理。

这样的模型可以回答如下类似的问题:如果『History』为T,那『News』为T的可能性有多大?下式中用H代指『History』,S代指『Sightseeing』,N代指『News』。


第一步推导就是简单的贝叶斯公式,第二步推导用到了全概率公式的变形(让我想到了数理逻辑中的排中律):


全概率公式

第三步就是依照已有的条件概率代入进行计算了。

构造贝叶斯网络是一项复杂的任务,涉及表示、推断和学习三个方面内容。

首先是表示,贝叶斯网络的表示代价很高,即便在上例中随机变量仅有两种取值的简单情况下,一个联合概率分布也需要提供2^n种不同取值下的概率。

然后是推断,由于贝叶斯网络是变量及其关系的完整模型,因此可以回答关于变量的询问,比如,当观察到某些变量(证据变量)时,推断另一些变量子集的变化。常用的精确推理方法包括变量消除法和团树法。

最后是学习,贝叶斯网络的学习有两种,一种是参数学习,另一种是结构学习。参数学习的目的是确定变量之间相互关联的量化关系,即依存强度估计。结构学习是寻找变量之间的图关系。

贝叶斯网络是一种不定性因果关联模型,能够在已知有限的、不完整、不确定信息的条件下进行学习和推理,因此广泛应用于故障诊断和维修决策等领域。在自然语言处理中也被应用于汉语自动分词和词义消歧等任务。

其实贝叶斯网络与我们在《浅谈深度学习基础》中讲过的人工神经网络非常相似。他们的共同点如下:

  • 它们都是有向图,每一个节点只取决于前一级节点,而与更前面的节点无关,也就是说遵从马尔可夫假设。贝叶斯网络其实就是马尔可夫链的拓展。
  • 它们的训练方式相似。
  • 对于很多模式分类问题,这两种方法在效果上相似,也就是说很多用人工神经网络解决的问题,也能用贝叶斯网络解决,反之亦然,但是效率可能不同。如果将它们都看做是统计模型,那么这两种模型的准确性也是类似的。
  • 它们的训练计算量都特别大。

它们也有很多不同之处:

  • 人工神经网络在结构上是完全标准化的,而贝叶斯网络更灵活。
  • 在人工神经网络中,虽然神经元的激活函数可以为非线性函数,但是各个输入变量只能先进行线性组合,最后对前面组合出来的结果进行非线性变换,因此用计算机实现起来比较容易。而贝叶斯网络,变量可以组合成任意的函数,毫无限制,在获得灵活性的同时,也增加了复杂性。
  • 贝叶斯网络更容易考虑上下文的相关性,因此可以解码一个输入的序列,比如将一段语音识别成文字,或者将一个英语句子翻译成中文,而普通的人工神经网络的输出相对孤立,它可以识别一个个字,但是很难处理一个序列(RNN就是为了解决这个问题而设计的)。

马尔可夫模型

前面的贝叶斯网络用于在已知某随机变量值的前提下推断其它随机变量的可能取值,而马尔可夫模型描述的是一个状态转化的随机过程。

如果一个系统有N个有限状态,那么随着时间的推移,该系统将从某一状态转移到另一个状态。对该系统的描述,通常需要给出当前时刻的状态和其前面所有状态的关系,如果在特定条件下,系统在时间t的状态j只与其在时间t-1的状态i相关,则该系统构成一个离散的一阶马尔可夫链。

进一步,如果只考虑独立于时间t的随机过程,那我们就能得到两个状态之间的转移概率aij,该随机过程为马尔可夫模型,aij需要大于0,而且从i出发到达所有可能的j的概率和应该为1。

例如,一段文字中名词、动词、形容词三类词性出现的情况可由三个状态的马尔可夫模型描述:s1:名词、s2:动词、s3:形容词。假定状态之间的转移矩阵如下:

那么根据这一模型M,一个以名词开头的句子O的词性序列为名词、动词、形容词、名词的概率为:


马尔可夫模型又可视为随机的有限状态自动机:


马尔可夫模型

如上例,一个马尔可夫链的状态序列的概率可以通过计算形成该状态序列的所有状态之间转移弧上的概率乘积而得出。

前面也讲过,n元文法模型就是n-1阶马尔可夫模型。

隐马尔可夫模型

接下来是隐马尔可夫模型,隐马尔可夫模型是一种经典的概率图模型,应用非常广泛。

在马尔可夫模型中,每个状态代表了一个可观察的事件,所以马尔可夫模型有时又可称作可视马尔可夫模型(VMM),这在某种程度上限制了模型的适应性。

在隐马尔可夫模型(HMM)中,有两个序列,一个序列是状态序列,类似于VMM中的状态转换过程,状态序列是隐蔽的;另一个是观察序列,可以观察到,观察序列由状态序列经过相应的随机函数得到。也即隐马尔可夫模型是一个双重的随机过程,隐蔽的状态转换是一个随机过程,由状态序列得到观察序列又是一个随机过程。


HMM

举个例子,一个暗室中有N个口袋,每个口袋中有M种不同颜色的球。一个实验员根据概率分布随机选择了一个口袋,再根据口袋中不同颜色球的概率分布,随机的取出一个球,向室外报告球的颜色,然后再根据口袋的概率分布选择另一个口袋,根据不同颜色球的概率分布从中随机选择另外一个球,重复进行这个过程。

对于暗室外面的人,他不知道口袋的序列,只知道球的序列。

描述一个HMM需要五个部分,通过上例也可以看出来:

  • 模型中状态的数目N(上例中口袋的数目)
  • 每个状态可能输出的不同符号的数目M(上例中球的不同颜色数)
  • 状态转移矩阵A={aij}(上例中口袋的转换概率)
  • 从状态观察到符号的概率分布矩阵B={bj(k)},即从第j个口袋取出第k种颜色的球的概率,观察符号的概率又称符号发射概率。
  • 初始状态概率分布π={πi},所有πi之和为1。

观察序列的产生步骤如下:

  • 根据初始状态的概率分布πi选择一个初始状态
  • 假定时间t=1
  • 根据状态的输出概率分布输出观察符号
  • 根据状态转移概率分布,由当前时刻t的状态qt转移到新的状态q(t+1)
  • 重复执行上两步直到t到达总时间长度T

HMM中有三个假设:

  • 有限历史性假设:也即一阶马尔可夫模型,认定t时刻出现的状态只与t-1时刻的状态有关
  • 齐次性假设:假定P(s(i+1)|si)=P(s(j+1),sj)
  • 输出独立性假设:假定输出仅与当前状态有关

HMM中有三个基本问题:

  • 估计问题:给定一个观察序列O=O1O2...OT和模型μ=(A, B, π),如何快速地计算出给定模型μ的情况下,观察序列O的概率,即P(O|µ)?
  • 解码问题:给定一个观察序列O=O1O2...OT和模型μ=(A, B, π),如何快速有效地选择在一定意义下的最优状态序列Q=q1q2...qT,使得该状态序列最好地解释观察序列?
  • 训练问题或参数估计问题:给定一个观察序列O=O1O2...OT,如何根据最大似然估计来求模型的参数值?即如何调节模型μ=(A, B, π)的参数,使得P(O|µ)最大?

先说第一个估计问题,也即求解观察序列的概率,我们先来想一种最直接的推导方式:假设状态序列Q已经给定,那我们将Q到O对应位置上的符号发射概率依次相乘即可得到观察序列的概率。但是因为目前不知道Q,我们应该将给定模型µ下,所有可能的Q都列举出来,然后将其得到O的概率全部相加。也即下式:


不过这样存在一个很大的问题,就是复杂度过高,如果模型中有N个状态,时间长度为T,那就有N^T种可能的序列,当T很大时,几乎不可能有效的执行这个过程。

为了解决这个问题,我们利用动态规划算法的思想,这里我们提出前向算法。

首先我们定义一个前向变量αt(i)αt(i)是给定模型µ下,在时间t,HMM输出了序列O1O2...Ot,并且当前状态为si的概率:

前向变量

前向算法的主要思想是,如果可以快速的计算前向变量αt(i),那么就可以利用αt(i)计算出P(O|µ),因为P(O|µ)其实就是所有状态qt下观察到序列O1O2...OT的概率:

因为αT(i)就是输出O1O2...OT,且状态为si的概率,其实我们要的只是输出O1O2...OT,si为哪个都可以,所以这里利用全概率公式的思想,我们把时刻T下出现任意状态且观察到O1O2...OT的概率相加,即得到了观察到O1O2...OT的概率。

我们还可以观察出前向变量αt(i)的递推公式,因为t+1时刻的前向变量α(t+1)(j)实际上就是t时刻之后,状态序列增加了一个sj,然后观察序列多输出了一个O(t+1)。所以我们先根据前面提过的全概率公式的思想计算出输出序列O1O2...Ot的概率,然后因为状态由所有可能的状态si变到了某一特定sj所以自然要乘一个对应的aij,然后我们就得到了t+1时刻下的状态序列,这个状态序列的最后一个状态是sj。然后为了得到输出序列O1O2...OtO(t+1),只需要再多乘一个bj(O(t+1)),也即状态sj发射出符号O(t+1)的概率,因为前面已经是O1O2...Ot了。也即如下式:

前向变量的归纳关系图如下,其实也就是我上一段讲的东西:


前向变量的归纳关系

t时刻已经输出到Ot了,然后先让所有可能的状态转移到状态sj,然后再让sj发射出符号O(t+1)。

由此我们得到了前向算法,首先依照初始状态概率分布和初始输出符号O1对状态进行初始化,然后依照递推公式计算出所有的αT(i),将其求和即得到P(O|µ)。

前向算法的时间复杂度为O(T*N2),N2是两层相乘,T是层数。

求解P(O|µ),除了前向算法之外,相应的,我们还要提出一个后向算法。

对应于前向变量,我们定义一个后向变量βt(i)βt(i)是在给定模型µ,并且t时刻状态为si的条件下,HMM输出观察序列O(t+1)O(t+2)...OT的概率。这里和前向变量有一个明显的不同,对于前向变量,条件只有模型µ,说的是『输出O1O2...OT,且状态为si的概率』,而后向变量说的是『状态为si的条件下,输出O(t+1)O(t+2)...OT的概率』,条件除了µ之外,状态si也成了前提条件。后向变量表达式如下:

后向变量

我们思考一下怎么用后向变量表示P(O|µ),看着后向变量的表达式,我们考虑,如果t=1呢?那么后向变量βt(i)就成了初始状态为si然后输出后续观察序列为O2O3...OT的概率了,那还缺什么?缺两部分,一个是初始状态,而且我们要考虑所有可能的si初始状态,第二个就是我们还缺观察序列的第一个符号,也就是O1,那么我们只要让s1输出O1就可以了,也即我们用后向变量表示出了P(O|µ),如下式:

∑求和考虑了所有的初始状态,然后πi给出了任意初始状态的出现概率,然后后面bi(O1)是该初始状态发射出观察符号O1的概率。

对照前向算法,我们还缺后向变量的递推公式,我们想一下t+1时刻的后向变量和t时刻的后向变量的关系,因为最后我们需要的是β1(i),所以我们的递推公式应该是由β(t+1)(j)得到β(t)(i)β(t)(i)是状态为si下,后续输出为O(t+1)O(t+2)...OT,β(t+1)(j)是状态为sj下,后续状态为O(t+2)O(t+3)...OT的概率。我们考虑一下由β(t+1)(j)β(t)(i)需要什么,首先我们缺一个输出符号O(t+1),这个输出符号正是由t+1时刻的状态sj输出的,所以我们需要乘以一个bj(O(t+1)),然后我们的状态不对,我们需要由状态sj转移到si,所以需要乘以aij,而且t时刻对应状态si下,t+1时刻对应的状态sj是任意的,所以我们需要∑求和。

我们参考一下后向变量的归纳关系图,和我上一段讲的是一个意思:


后向变量的归纳关系

t+1时刻后面的O(t+2)已经有了,缺O(t+1),我们就让所有可能的sj都去生成O(t+1),然后再让这些sj都转化成β(t)(i)里面的那个si

由此我们得到了后向算法,首先初始化βT(i)=1,然后根据递推公式计算出β1(i),最后按照前面的公式通过β1(i)计算出P(O|µ)。

然后其实更一般的,我们可以采用前向算法和后向算法相结合的方法来计算P(O|µ):


对于任意合理时刻t,前向变量与后向变量的乘以刚好就是P(O|µ),当然我们也要考虑到t时刻所对应的状态是任意的,所以我们要将概率∑求和,考虑到所有情况。不过这个算法不是前向后向算法,前向后向算法是用来解决第三个问题的。

然后是HMM的第二个问题,即给定一个观察序列O=O1O2...OT和模型μ=(A, B, π),如何快速有效地选择在一定意义下的最优状态序列Q=q1q2...qT,使得该状态序列最好地解释观察序列。我们这里将最优状态序列理解为,在给定模型µ和观察序列O的前提下,使条件概率P(Q|O,µ)最大的状态序列。这样我们优化的不是状态序列中的单个状态,而是整个状态序列,不会存在因为优化单个状态概率而导致产生不合法序列或无法达到全局最优。

解决这个问题采用的是维特比算法,维特比算法采用了动态规划的思想来求解这种最优状态序列。

首先我们定义一个维特比变量δt(i)δt(i)是在时间t时,HMM沿着某一条路径到达状态si,并输出观察序列O1O2...Ot的最大概率,也即如下式:

维特比变量

维特比变量也有自己的递推公式,与前向变量的相似:


看起来挺简单的,先状态转化,由j到i,取最大值,然后状态序列就到了状态si,然后由si发射出符号O(t+1)就结束了。但是这里需要明确一个问题,也就是δ(t+1)(i)为什么会由
δ(t)(j)得到,也即t+1时刻(到某特定状态si)拥有最大概率的状态序列和t时刻(到所有可能状态sj)拥有最大概率的状态序列们是什么关系?

首先是,t时刻(到所有可能状态sj)拥有最大概率的状态序列们对于计算t+1时刻(到某特定状态si)拥有最大概率的状态序列为什么是必要的。

如果t+1时刻概率最大的状态序列t时刻经过了某个状态sj,那这个状态序列从初始状态到状态sj的子状态序列一定是从初始状态到sj状态的所有可能的状态序列里面,概率最大的那一条。因为sjsi的概率是一定的,如果sj到初始状态的序列不是概率最大的那一条,那t+1时刻的这个状态序列也一定不是概率最大的状态序列。

然后是,为什么t时刻(到所有可能状态sj)拥有最大概率的状态序列们对于计算t+1时刻(到某特定状态si)拥有最大概率的状态序列是充分的。

要产生t+1时刻的状态si必然要先产生t时刻的某个状态sj,假定所有可能的状态sj有k个(这里不是N个的原因,是因为可能有的状态sjsi的转化概率aji为0,不可能出现在t+1时刻产生si的这个序列里面),然后我们记录了这k个状态sj到初始状态且拥有最大概率的状态序列,那t+1时刻概率最大的那个状态序列必然经过其中的一条,也即其中必然有一条是t+1时刻概率最大的那个状态序列t时刻的子状态序列。这样,任何时刻,只要考虑非常有限条候选路径即可。

这样我们只用记录t时刻(到所有可能状态sj)拥有最大概率的状态序列们,也即δt(j),就能得到t+1时刻到状态si拥有最大概率的状态序列δ(t+1)(i)。一直递推下去,我们就能得到δT(i),也即最后一个时刻拥有最大概率的状态序列了,也即求得了使P(Q|O,µ)概率最大的状态序列Q。

接下来是第三个问题,即给定一个观察序列O=O1O2...OT,如何根据最大似然估计来求模型的参数值?即如何调节模型μ=(A, B, π)的参数,使得P(O|µ)最大?

隐马尔可夫模型µ包括三部分,分别是初始状态概率分布π={πi}、状态转移矩阵A={aij}、从状态观察到符号的概率分布矩阵B={bj(k)},如果产生观察序列的状态序列Q=q1q2...qT已知,那我们根据最大似然估计,HMM的参数就可以通过如下公式计算:

第一行是描述初始概率分布,其中,δ(x,y)为克罗奈克函数,当x=y时,δ(x,y)=1;否则δ(x,y)=0。这个其实很好理解,如果状态序列都有了,那什么样的初始概率分布最能拟合这个状态序列呢?当然是让初始概率分布中,状态序列里真实的那个初始状态作为初始状态的概率为1,其余的都是0了。

第二个式子描述的是状态转移概率,同样的,状态序列都有了,就按照状态序列的结果去构造模型就好了。比如,状态序列中,si只转移到sj,那aij我们就定为100%,如果sj一次转移到了sk一次转移到了sl,那ajkajl的概率就都是50%好了。

第三个式子描述的是符号发射概率,同样的思路,状态序列也有,观察序列也有,我们直接计算一下这两个序列所反映出来的实际符号发射概率是多少,然后把它们作为参数赋给模型就好了,这肯定是概率最大的情况。

上面的想法看起来很好,但是关键问题是我们要处理的是隐马尔可夫模型,也就意味着我们是不知道状态序列Q的,所以没办法直接用这种最大似然估计。但是期望最大化算法(expection maximization,EM)可以用于这种含有隐变量的统计模型的最大似然估计。

前面的《浅谈机器学习基础》和《浅谈深度学习基础》提到过最大似然估计、梯度上升/下降算法,现在又提到了期望最大化算法,那它们有什么区别呢?

讲逻辑回归算法(LR)的时候我们就提到了最大似然估计,我们根据最大似然估计得到了目标函数,也即最大自然估计是一种求得目标函数的方法;而梯度上升/下降算法是一种最优化算法,在LR中,最大似然估计得到的目标函数就是由梯度上升算法进行优化的。

EM与梯度上升/下降算法一样,也是一种最优化方法,用于优化目标函数,但区别就在于梯度上升/下降算法的『梯度』上,我们知道梯度实际上是偏导,梯度上升/下降算法实际上是根据不同维度上的偏导来决定参数的改变,但是EM并不求导,因为并不是所有的式子都是方便求导的。

EM 算法是作为一种求参数极大似然估计的方法而被提出的,举个形象的例子,比如说食堂的大师傅炒了一份菜,要等分成两份给两个人吃,显然没有必要拿来天平一点一点的精确的去称分量,最简单的办法是先随意的把菜分到两个碗中,然后观察是否一样多,把比较多的那一份取出一点放到另一个碗中,这个过程一直迭代地执行下去,直到大家看不出两个碗所容纳的菜有什么分量上的不同为止。

EM算法就是这样,假设我们估计知道A和B两个参数,在开始状态下二者都是未知的,并且知道了A的信息就可以得到B的信息,反过来知道了B也就得到了A。可以考虑首先赋予A某种初值,以此得到B的估计值,然后从B的当前值出发,重新估计A的取值,这个过程一直持续到收敛为止。

如果将EM算法的思想应用于最大似然估计HMM模型的参数,其基本思想是,初始时随机地给模型的参数赋值(随意的给第一个同学打饭),该赋值遵循模型对参数的限制(饭的总量是一定的),例如,从某一状态出发的所有转移概率的和为1。给模型参数赋值以后,得到模型µ0,然后根据µ0可以得到模型中隐变量的期望值(剩下的饭给第二个同学),例如,从µ0得到从某一状态转移到另一状态的期望次数,用期望次数来替代我们不知道的实际状态转移次数,这样可以得到模型参数的新估计值,由此得到新的模型µ1(发现第二个同学饭多了,取一部分给第一个同学),然后不断迭代,直到参数收敛于最大似然估计值(两个同学饭一样多)。

这种迭代爬山算法可以局部地使P(O|µ)最大化,HMM中具体实现这种EM方法的算法叫做Baum-Welch算法,也叫前向后向算法,下面我们详细介绍这种算法:

这里我们引入这样一个变量ξt(i,j)ξt(i,j)是给定HMM的参数µ和观察序列O=O1O2...OT,在时间t位于状态si,时间t+1位于状态sj的概率。与前向变量和后向变量的定义很相近:

前向变量

后向变量

ξt(i,j)与前向变量和后向变量的关系是什么呢?首先是计算公式:

计算公式只是代入计算的时候用到的,我们还是要理解它们的本质。

我们先来回想一下前向变量和后向变量有什么关系,前面在解决HMM的第一个问题的时候,提出了一种结合前向变量和后向变量的方法,从那个方法中我们能够发现,前向变量和后向变量的设计是非常巧妙的,我们再看一下它们的表达式:


前向变量
后向变量

我们想一下前向变量αt(i)和后向变量βt(i)相乘是什么,前向变量的条件是模型µ,前向变量是已知模型µ,得到观察序列O1O2...Ot,且当前状态为si的概率,然后再乘以后向变量,后向变量的条件是模型µ和当前状态为si,这个当前状态为si正好与前向变量的结论契合的严丝合缝,然后我们继续看,后向变量的结论是O(t+1)O(t+2)...OT,当时提出后向变量的时候有没有想过这样一个问题,为什么是O(t+1)O(t+2)...OT,而不是OtO(t+1)...OT,从Ot而不是O(t+1)开始?为的就是与前向变量向契合,前向变量的结论是O1O2...Ot,再加上后向变量的结论O(t+1)O(t+2)...OT,正好是全部的观察序列O1O2...OT。

然后我们再看ξt(i,j),它的定义是给定HMM的参数µ和观察序列O=O1O2...OT,在时间t位于状态si,时间t+1位于状态sj的概率。

ξt(i,j)与前向变量αt(i)和后向变量β(t+1)(j)的关系如下:

`ξt(i,j)`与前向变量和后向变量的关系

前面讲了αt(i)β(t)(i)的关系,这里有些区别,不是β(t)(i)而是t+1时刻的β(t+1)(j)。根据ξt(i,j)的定义,我们需要观察序列O=O1O2...OT、在时间t位于状态si和时间t+1位于状态sj,依次补齐即可,αt(i)提供了O1O2...Ot和在时间t位于状态siβ(t+1)(j)提供了O(t+2)O(t+3)...OT和在时间t+1位于状态sj,还缺什么?还缺状态si到状态sj的转化和符号O(t+1),这就很清楚了,乘以aijbj(O(t+1))即可,我们再看一下上面的式子:

分子就与我们推理出来的表达式相同,但是多了一个分母P(O|µ),是因为在ξt(i,j)的定义里,观察序列O属于已知条件,应该放在竖线的右侧,所以除以P(O|µ),根据贝叶斯公式转化得到ξt(i,j)

根据ξt(i,j),依照全概率公式的思想,我们可以知道给定µ和观察序列O下,在时间t位于状态si的概率γt(i)

有了ξt(i,j)γt(i),我们就可以重新计算出µ参数估计值了(也即把第二个同学的饭分一部分给第一个同学):

前向后向算法的基本过程:

  • 初始化,随机给µ的参数赋值,同时保证:


  • EM计算
    E-步骤:根据模型µ计算ξt(i,j)γt(i)
    M-步骤:根据ξt(i,j)γt(i)重新估计模型µ

  • 重复执行EM计算,直到模型µ的参数收敛

HMM在自然语言处理研究中有着非常广泛的应用,除了上面的理论问题之外,还有一些技术上的问题需要注意,比如连乘引起的浮点数下溢,或者取对数使乘法变成加法,还有在前向后向算法中给出一个足够小的实数来判定模型参数是否收敛。

推荐阅读更多精彩内容