专栏名称: GitChat技术杂谈
GitChat是新时代的学习工具。
目录
相关文章推荐
程序猿  ·  离谱!下载 DeepSeek 将判 20 ... ·  昨天  
OSC开源社区  ·  龙芯处理器成功运行DeepSeek大模型 ·  2 天前  
程序员小灰  ·  DeepSeek让我的朋友一夜暴富! ·  4 天前  
程序员小灰  ·  DeepSeek + IDEA!辅助编程太强了! ·  3 天前  
51好读  ›  专栏  ›  GitChat技术杂谈

想做聊天机器人,如何语言理解模型开发?

GitChat技术杂谈  · 公众号  · 程序员  · 2017-09-13 07:44

正文

本文来自作者 李烨 GitChat 上精彩分享「聊天机器人语言理解模型开发实践」

【不要错过文末彩蛋】

编辑 | 文乐

写在前面

之前分享过一个Chat:「 从 0 开始,开发一款聊天机器人 」,其目标是为零基础开发者提供一个最简版的 chat bot 开发流程。按照这个流程,一个有基本编程经验,但没有AI知识的人,也可以在短时间里开发出一款自己的bot。

本着这样的目的,上次分享的重点,不在某个具体的技术点,而是讲如何利用已有的AI技术、框架、工具,来解决实际问题。

AI对于社会真正的贡献并不是某一个模型算法多么炫酷高深,而是它可以为尽量多的人所利用,来做实事。

因此,在上次 Chat 在介绍 Bo t的语言理解(Language Understanding/LU)模块时,就选用了一款现成的在线LU工具:LUIS(https://luis.ai/),而不是告诉大家如何自己写LU模型。

没想到许多参与讨论的同学对 LU 特别感兴趣,想要知道意图识别和实体抽取究竟是如何实现的。

既然大家这样感兴趣,而且在线 LU 工具又存在无法本地部署,有 concurrency 限制等问题,可能导致在某些场景(例如无法访问外网,需要高 concurrency 或极低 latency)下无法满足需求。

因此,新开本次的Chat,从原理开始,讲解语言理解模块的工程实现。

一、聊天机器人的语言理解模块

聊天机器人的语言理解有很多种实现技术。在此,我们继续 上次 chat 里主要介绍的 solution:对于用户输入问题进行意图识别和实体提取。

上次讲过,意图识别和语言提取可以通过基于规则(rule-based))和基于模型(model-based)两种方式来实现。

最简单直接的是基于规则的方法:用关键字/正则表达式匹配的方式,来发现自然语言中的意图和实体。

其实,如果大家真的去开发一个以使用为目的,垂直领域内回答有限问题的 Bot。就会发现,最 straight forward 的方法,就是去设置大量规则,进行 rule-based 理解。

不仅准确率高,而且特别好修改,哪里有错,直接改 rule就好了。还不需要准备训练语料,和 model-based 比起来,真是不知道好用到哪里去了。

可是,毕竟基于规则的方法缺点也很明显:缺乏泛化能力。而且,上次chat听众提问和评论来看,大家最感兴趣的,偏偏是 model-based LU。

确实,model-based LU 应用到了 Machine Learning 的技术,离炫酷的AI最近。虽然在实际当中,用最小代价解决必要问题的方法就是最好的方法,选技术应该选对的,而不是「贵」的。

但是,既然大家就喜欢「贵」的,那我们就专门来讲讲它。在讲具体算法模型之前,我们先来看看 NLP。

二、NLP是怎么回事

我们今天要讲的语言理解,是理解人类的自然语言(Natural Language)。这部分工作可以算作自然语言处理(Natural Language Process/NLP)的一部分。

当然,现在也有人把自然语言理解(NLU)单独提出来,当作和NLP并列的另一个领域。不过我们没必要玩这种文字游戏。NLU也罢,NLP也好,都要让计算机“听懂”人类正常讲话时使用的语言,而不是几个英文关键字加一堆参数的格式化的指令。

我们人类是怎样理解语言呢?

举个例子,我说“苹果”这个词,你会想到什么?一种酸酸甜甜红红绿绿的球状水果,对吧。想起来的时候,或许脑子里会出现苹果的图像,或者会回味起它香甜的味道,或者想起和这种水果有关的什么事情。

我们人类理解语言的时候,是把一个抽象的词语和一个具体的事物关联起来,这个事物是我们头脑中知识库图谱里的一个节点,和周围若干节点直接相连,和更多节点间接相连……

计算机又如何理解语言呢?

我们用键盘敲出“苹果”两个字的时候,计算机并不会幻视出一个水果,也不会像人那样“意识到”这个单词的含义。

无论通过输出设备显示成什么样子,计算机所真正能够处理的,是各种各样的数值。要想让计算机理解人类的语言,就需要把人类的语言转化成它可以用来读取、存储、计算的数值形式。

当若干自然语言被转换为数值之后,计算机通过在这些数值之上的一系列运算来确定它们之间的关系,再根据一个全集之中个体之间的相互关系,来确定某个个体在整体(全集)中的位置。

这么说有点绕,还是回到例子上。很可能,我说“苹果”的时候,有些人首先想到的不是苹果,而是乔帮主创立的科技公司。

但是,我继续说:“苹果一定要生吃,蒸熟了再吃就不脆了。”——在这句话里,“苹果”一词确定无疑指的是水果,而不是公司。因为在我们的知识库里,都知道水果可以吃,但是公司不能吃。

出现在同一句话中的 “吃”对“苹果”起到了限定作用——这是人类的理解。

对于计算机,当若干包含“苹果”一词的文档被输入进去的时候,“苹果”被转化为一个数值 Va。

经过计算,这个数值和对应“吃”的数值 Ve 产生了某种直接的关联,而同时和 Ve 产生关联的还有若干数值,它们对应的概念可能是“香蕉”(Vb)、“菠萝”(Vp)、“猕猴桃”(Vc)……那么据此,计算机就会发现Va,Vb,Vp,Vc之间的某些关联(怎么利用这些关联,就要看具体的处理需求了)。

总结一下,计算机处理自然语言必经由两个步骤:i)数值化和ii)计算。

NOTE 1: 说到数值,大家可能本能的想到 int, double, float…… 但实际上,如果将一个语言要素对应成一个标量的话,太容易出现两个原本相差甚远的概念经过简单运算相等的情况。

假设“苹果“被转化为2,而”香蕉“被转化为4,难道说两个苹果等于一个香蕉吗?

因此,一般在处理时会将自然语言转化成n维向量。只要转化方式合理,规避向量之间因为简单运算而引起歧义的情况还是比较容易的。

NOTE2: 具体的转化方法有很多种(后面章节会详细介绍具体方法)。不过,既然要把「字」转化为「数」,有一个天然的数值就很容易被选中,这个数值就是:这个字的概率(在当前文档中,或者在所有文档中)。

由概率,我们又可以引出一个概念:信息熵。这个概念大家可以自行百度,先看一下它的计算公式:

其中 P(xi) 就是 xi 的概率。可见,只要已知集合中每个元素的概率,就可以求取集合的信息熵。

三、语言理解模型

3.1 模型、算法、VSM

本文所说的LU 包括两大功能: 意图识别和实体提取。

意图识别是一个典型的分类问题,而实体抽取则是一个 Sequence-to-Sequence 判别问题。因此我们需要构建一个分类模型和一个 seq2seq 判别模型。

我们先来说说 模型是什么。

一个已经训练好的模型可以被理解成一个公式 y=f(x),我们把数据(对应其中的x)输入进去,得到输出结果(对应其中的y)。这个输出结果可能是一个数值,也可能是一个标签,它会告诉我们一些事情。

比如,我们把用户说的一句话输入识别用户意图的分类模型。模型经过 一番运算,吐出一个标签,这个标签,就是这句话的意图(intent)。

把这句话再输入到实体提取模型里面,模型会吐出一个List,其中每一个element都是一个实体,这个实体的信息包含:i)实体名:输入句子中一个的片段;ii)实体位置:该片段在输入句子中的位置和长度;iii)实体类型:该片段所对应的实体属于什么类型。

模型是怎么得到的?

模型是基于数据,经由训练得到的。训练又是怎么回事?

当我们把模型当做y=f(x)时,x就是其中的自变量,y是因变量。从x计算出y要看f(x)是一个具体什么样的公式,这个公式中还有哪些参数,这些参数的值都是什么。训练的过程就是得到具体的某个f(x),和其中各个参数的具体取值的过程。

在开始训练的时候,我们所有的是x的一些样本数据,这些样本本身即有自变量(特征)也有因变量(预期结果)。对应于y=f(x)中的x和y取值实例。

这个时候,因为已经选定了模型类型,我们已经知道了f(x)的形制,比如是一个线性模型 y=f(x)=ax^2+bx+c,但却不知道里面的参数a,b,c的值。

训练,就是要将已有样本经过依据某种章法的运算,得到那些参数的值,由此得到一个通用的f(x)。这些运算的章法,就叫做:算法。

说到算法,就涉及到了机器学习的内容,经过几十年的研究,已经有很多现成的算法可以用于获得不同类型的模型。

关于生成分类模型和 seq2seq 判别模型的算法,我们下面有专门章节讨论。

要得到模型,算法固然重要,但往往更重要的是数据。

用于训练模型的数据有个专名的名称称呼它们:训练数据。训练数据的集合叫做训练集。

分类模型和 seq2seq 判别模型的训练都属于有监督学习,因此,所有的训练数据都是标注数据。

因此,在进入训练阶段前必须要经过一个步骤:人工标注。这部分已经在 之前 chat 中讲过,不赘述。

标注的过程繁琐且工作量颇大。然而只要进行有监督学习,就无法跳过这一步。偏偏大量在实践中证明确实有效的模型都是有监督学习模型。

因此,如果大家真的在工作中应用机器学习,标注就是无法逾越的脏活累活,是必经的 pain。

这里需要提醒大家的是:人工标注的过程看似简单,但实际上,标注策略和质量对最终生成模型的质量有直接影响。

而往往能够决定模型质量的不是高深的算法和精密的模型,而是高质量的标注数据。因此,对标注,切莫小歔。

此处有一点和之前 NLP 一节呼应,就是:任何算法的处理对象都是数值。

而我们要对其进行分类和识别的对象却是自然语言文本。因此需要一个步骤,把原始文字形式的训练数据转化为数值形式。

为了做到这一点,我们需要构建一个向量空间模型(Vector Space Model/VSM)。VSM 负责将一个个自然语言文档转化为一个个向量。下面也会专门章节讲 VSM 的构建。

训练数据经过 VSM 转换之后,我们把这些转换成的向量输入给分类或识别算法,进入正式的训练过程。训练的输出结果,就是模型。

3.2 如何判别模型的优劣

通过训练得到模型后,我们需要用模型来对用户不断输入的语句进行预测(也就是把用户语句输入到模型中让模型吐出一个结果)。

预测肯定能出结果,至于这个预测结果是否是你想要的,就不一定了。一般来说,没有任何模型能百分百保证尽如人意,但我们总是追求尽量好。

什么样的模型算好呢?当然需要测试。当我们训练出了一个模型以后,为了确定它的质量,需要用一些知道预期预测结果的数据来对其进行测试。这些用于测试的数据的集合,叫做测试集。

一般而言,除了训练集和测试集,还会需要验证集:

训练集(Train Set) 用来训练数据。

验证集(Validation Set) 用来在训练的过程中优化模型(模型优化在下面也会单独讲)。

测试集(Test Set) 用来检验最终得出的模型的性能。

训练集必须是独立的,和验证集、测试集都无关。验证集和测试集在个别情况下只有一份,不过当然最好还是分开。这三个集合可以从同一份标注数据中随机选取。

三者的比例可以是训练集:验证集:测试集=2:1:1,也可以是7:1:2。总之,测试集占大头。

在用测试集做测试时,我们需要一些具体的评价指标来评判结果的优劣。对于分类和 seq2seq 识别模型而言,评价标准可以通用。

最简单也是最常见的验证指标:精准率(Precision)和召回率(Recall),为了综合这两个指标并得出量化结果,又发明了 F1Score。

对一个分类模型而言,给它一个输入,它就会输出一个标签,这个标签就是它预测的当前输入的类别。

假设数据 data1 被模型预测的类别是Class_A。那么,对于 data1 就有两种可能性:data1 本来就是 Class_A(预测正确),data1 本来不是 Class_A(预测错误)。

当一个测试集全部被预测完之后,相对于 Class_A,会有一些实际是 Class_A 的数据被预测为其他类,也会有一些其实不是 Class_A 的,被预测成 Class_A,这样的话就导致了下面这个结果

精准率: Precision=TP/(TP+FP),即在所有被预测为Class_A的测试数据中,预测正确的比率。

召回率: Recall=TP/(TP+FN),即在所有实际为Class_A的测试数据中,预测正确的比率。

F1Score = 2(Precision  Recall)/(Precision + Recall)。

显然上面三个值都是越大越好,但往往在实际当中P和R是矛盾的,很难保证双高。

此处需要注意,P,R,F1Score 在分类问题中都是对某一个类而言的。也就是说假设这个模型总共可以分10个类,那么对于每一个类都有一套独立的P,R,F1Score的值。衡量模型整体质量,要综合看所有10套指标,而不是只看一套。

同时,这套指标还和测试数据有关。同样的模型,换一套测试数据后,很可能P,R,F1Score 会有变化,如果这种变化超过了一定幅度,就要考虑是否存在 bias 或者 overfitting 的情况。

seq2seq 识别实际上可以看作是一种位置相关的分类。每一种实体类型都可以被看作一个类别,因此也就同样适用P,R,F1Score指标。

此外还有 ROC 曲线,PR曲线,AUC等评价指标,大家可以自行查询参考。

3.3 构建模型的步骤

笼统而言,为了构建一个模型,我们需要经历以下步骤:

  1. 收集语料(收集被标注的数据)

  2. 标注数据

  3. 将标注数据切分为训练集、验证集和测试集

  4. 构建 VSM

  5. 选取算法

  6. 训练(期间要经历多次迭代优化,在验证集上达到最优)

  7. 测试

聊天机器人的语言理解需要两个模型,那么上面这套步骤就需要做两遍。

其中唯一有可能共享的,是第一步:收集语料。但并不是说两个模型只能用同一套语料。实践中,两份语料往往是有一部分 overlap,但并不全相同。

语料来源何处?

有一些 bot 的开发目的是为了辅助或者部分替代已有的人工客服。这种情况下,往往之前人工客服和用户对话的 log 已经积累了很多。从中筛选出比较典型的用户提问语句,就可以用来做模型需要的语料。

如果是冷启动的bot,相对困难一点。可能需要在最开始的时候主动造一些语料。开发者想象自己是用户,把有可能提问的语句直接记录下来作为下面要用的语料。

如果是这样做的话,最好由多个人来共同构造语料。基本上构造语料的人越多,语料与真实环境的收集结果也就越接近。

其后的每一步,两个模型就都是自顾自了。标注部分,请参见上次chat。

四、构建 VSM

之前提到了 VSM,我们来看看具体怎么构造。

假设训练集中包含N个用户问题,我们把每个问题称为一个文档(document),你要把这N个文档转换成N个与之一一对应的向量。

再假设每个向量包含M维。那么最终,当全部转换完之后,整个训练集就构成了一个 NxM 的矩阵(Matrix),这就是向量空间模型(Vector Space Model,VSM)。

其中,M是你的全部训练集文本(所有N个文档)中包含的Term数。这个Term具体是一个字、一个词还是别的什么,实际是由VSM的构建者自己来确定。

对于中文而言,这个Term比较常见的有两种选择,一个是分词后的单个词语,另一个是n-gram方式提取的Term。

n-gram中的n和文档个数的N无关(此处特别用大小写来区分他们),这个n是一个由你确定的值,它指的是最长 Term 中包含的汉字的个数。一般情况下,我们选n=2就好了。

当 n==2 时的 n-gram 又叫做 bigram。n==1时叫unigram,n==3 时叫 trigram。

N个文档,设其中第i个文档的Term数为ci个(i 取值区间为[1, N])。那么这N个文档分别有:c1,c2…cn个Term。

这些Term中肯定有些是重复的。我们对所有这些Term做一个去重操作,最后得出的无重复Term的个数就是M。

针对具体的一个文档,我们就可以构建一个M维的向量,其中每一维对应这M个Term中的一个。

每一个维度的值,都是一个实数(一般在计算机处理中是float或者double类型)。这个实数值,通常的情况下,取这一维度所对应Term在全部训练文档中的TF-IDF(请自行百度TF-IDF)。

假设我们一共处理了1万个文档(N == 10000),总共得出了2万个Term (M == 20000)。这样就得到了一个10000 x 20000的矩阵。其中,每个Vector都只有20多个维度有非零值,实在是太稀疏了。

这样稀疏的矩阵恐怕也不会有太好的运算效果。而且,一些区分度过大的Term(例如某一个Term仅仅只在一个或者极少的文档中出现),在经过运算之后往往会拥有过大的权重,导致之后只要一个文档包含这个 Term 就会被归到某一个类。这种情况显然是我们要避免的。

因此,我们最好先对所有的 Term 做一个筛选。此处讲两个特别简单和常见的 Term 筛选方法:

  1. 设定DF(DocumentFrequency)的下限。设定一个 Threshold (e.g. DF_Threshold = 2),若一个 Term 的 DF 小于该 Threshold,则将该 Term 弃之不用。

  2. 根据每个 Term 的信息熵对其进行筛选。

一个 Term 的信息熵(Entroy)表现了该Term在不同类别中的分布情况。一般来说,一个 Term 的 Entropy 越大,则说明它在各个类中均匀出现的概率越大,因此区分度就越小;

反之,Entroy越小也就说明该Term的类别区分度越大。我们当然要选用Entroy尽量小的Term。具体选用多少,可以自己定义一个Threshold。

Entropy_Threshold 可以是一个数字(例如8000),也可以是一个百分比(例如40%)。

计算了所有 Term 的 Entropy 之后,按 Entropy 从小到大排序,选取不大于 Entropy_Threshold 的前若干个,作为最终构建 VSM 的Term。

假设所有的训练样本一共被分为K类,则 Entropy 的计算方法如下(设tx表示某个具体的 Term): Entropy(tx) = Sigma[i] ((-P(ci) *log(P(ci)))) — i取值范围为[1,K]

其中,P(ci) 表示tx在第i个列别中的出现概率,具体计算方法采用softmax算法:

P(ci)= exp(y(ci)) /Sigma[j] (exp(y(cj))) — j取值范围为[1,K]

其中 y(ci) 为tx在类别j中出现的次数。

经过筛选,M 个 Term 缩减为M’ 个,我们 NxM’ 矩阵变得更加精炼有效了。这也就是我们最终的 VSM。

五、分类模型

分类模型是机器学习中最常用的一类模型,常用的分类模型就有:Naïve Bayes,Logistic Regression,Decision Tree,SVM等。

今天我们在这里介绍其中的Logistic Regression。它也是之前我们介绍的LUIS(https://luis.ai)做意图识别时用到的模型。

5.1 LR模型的原理及目标函数

Logistic regression (LR,一般翻译为逻辑回归)是一种简单、高效的常用分类模型。它典型的应用是二分类问题上,也就是说,把所有的数据只分为两个类。当然,这并不是说LR不能处理多分类问题,它当然可以处理,具体方法稍后讲。我们先来看LR本身。

如前所述,模型可以被看做一个形式确定、参数值待定的函数。LR对应的这个函数,我们记作:y=h(x)。

其中自变量x是向量,物理意义是一系列特征,在bot LU的scenario之下,这些特征值就是用户问题经过VSM转换后得出的向量。

而最终计算出的因变量y,则是一个[0,1]区间之内的实数值。当y>0.5 时,x 被归类为阳性(Positive),否则当y <=0.5时,被归类为阴性(Negative)。

如果单纯看这个取值,是不是会有点担心,如果大量的输入得到的结果都在y=0.5附近,那岂不是很容易分错?

说得极端一点,如果所有的输入数据得出的结果都在y=0.5附近,那岂不是没有什么分类意义了,和随机乱归类结果差不多?

这样的担心其实是不必要的,因为LR的模型对应公式是:

这个公式对应的分布是这样的:

发现没有,此函数在y=0.5附近非常敏感,自变量取值稍有不同,因变量取值就会有很大差异,所以不用担心出现大量因细微特征差异而被归错类的情况。

上述的h(x) 是我们要通过训练得出来的最终结果,但是在最开始的时候,我们是不知道其中的参数 theta 的,我们所有的只是若干的x和与其对应的y(训练集合)。

怎么通过训练数据中已知的x和y来求未知的 theta 呢?

首先要么要设定一个目标:我们希望这个最终得出的 theta达到一个什么样的效果——我们当然是希望得出来的这个 theta,能够让训练数据中被归为阳性的数据预测结果为阳,本来被分为阴性的预测结果为阴。

而从公式本身的角度来看,h(x)实际上是x为阳性的分布概率,所以,才会在h(x) > 0.5时将x归于阳性。也就是说h(x) = P(y=1)。反之,样例是阴性的概率P(y=0) = 1 - h(x)。

当我们把测试数据带入其中的时候,P(y=1)和P(y=0)就都有了先决条件,它们为训练数据的x所限定。因此 P(y=1|x) = h(x); P(y=0|x) = 1- h(x)

根据二项分布公式,可得出 P(y|x) = h(x) ^y*(1- h(x))^(1-y)

假设我们的训练集一共有m个数据,那么这m个数据的联合概率就是:

我们求取 theta的 结果,就是让这个l(theta)达到最大。上面这个函数就叫做LR的似然函数。为了好计算,我们对它求对数。得到对数似然函数:

我们要做的就是求出让 l(theta) 能够得到最大值的 theta。l(theta) 就是 LR的目标函数。

NOTE: 目标函数是机器学习的核心。机器学习要做的最关键的事情就是将一个实际问题抽象为数学模型,将解决这个问题的方法抽象问一个能够以某种确定性手段(最大化、最小化)使其达到最优的目标函数。

在此,我们已经得到了LR的目标函数 l(theta),并且优化目标是最大化它。为了获得 l(theta) 的最大值,我们要对它求导:

因为 l(theta) 为凸函数,因此当其导数函数为0时原函数达到最大值。所以,我们要求取的,就是上述公式为0时的 theta,其中的y(i)和x(i)都是已知的。

5.2 LR的算法

上面是 LR 的基本原理和公式。在上述目标函数的导函数中,如果求解 theta 呢?具体方法有很多,我们在此仅介绍最常见最基础的梯度下降算法。

我们已经知道 l(theta) 函数是有极值的,那么如何去找到这个极值呢?

我们可以试,即先找到这个函数上的一点 p1,算出它的函数值,然后沿着该点导数方向前进一步,跨到 p2 点,再计算出 p2 点所对应的函数值,然后不断迭代,直到找到函数值收敛的点为止:

Set initial value: theta(0), alpha

while (not convergence)

{

}

其中,参数α叫学习率,就是每一步的步长。步长的大小很关键,如果步长过大,很可能会跨过极值点,总也无法达到收敛。步长太小,则需要的迭代次数太多,训练速度过慢。

可以尝试在早期的若干轮迭代中设置一个较大的步长,之后再缩小步长继续迭代。

具体判断收敛的方式可以是判断两次迭代之间的差值小于某个阈值ϵ(即比阈值小就停止)。

有时候,在实际应用中会强行规定一个迭代次数,到了这个次数无论收敛与否都先停止。具体推出迭代条件要按实际需要确定。

5.3 LR处理多分类问题

LR是用来做而分类的,我们的意图识别肯定不是只有两个意图啊,怎么能用LR?!

别急,LR一样可以做多分类,不过就是要做多次。

假设你一共有n个 intent,也就是说可能的分类一共有n个。那么就构造n个LR分类模型,第一个模型用来区分 intent_1 和 non-intent_1(即所有不属于intent_1的都归属到一类),第二个模型用来区分 intent_2 和 non-intent_2,…, 第n个模型用来区分 intent_n 和 non-intent_n。

使用的时候,每一个输入数据都被这n个模型同时预测。最后哪个模型得出了 positive 结果,就是该数据最终的结果。

如果有多个模型都得出了 positive,那也没有关系。因为LR是一个回归模型,它直接预测的输出不仅是一个标签,还包括该标签正确的概率。那么对比几个 positive 结果的概率,选最高的一个就是了。

例如:有一个数据,第一和第二个模型都给出了 positive 结果,不过intent_1模型的预测值是0.95,而 intent_2 的结果是0.78,那么当然是选高的,结果就是 intent_1。

六、seq2seq 判别模型

seq2seq 判别模型在一定程度上也有分类的意味。不同之处在于,seq2seq当中每一个被分类的片段,究竟最终被分为哪个类,除了与其自身相关,还与其前后片段的相互位置有关。

在文本处理当中,linear-chain CRF(线性链CRF)是最常用的一种 seq2seq 判别模型,也是LUIS在做实体提取时用到的模型。

上图显示了 LR 和线性链 CRF 的联系与区别。上图中的灰色节点为输入给模型的自变量(x1,x2,x3),而白色节点则是模型输出的结果。

可见,LR中,多个特征输入后得到了唯一的分类结果。而线性链CRF中,决定一个输出的除了和它对应的输入,还有排在它之前的那个输出。

举个例子:对「我要一张从北京到上海的机票。」 进行LR分类(意图识别)的时候,整句话都被分为「购买机票」意图。

而当对其进行线性链CRF判别时,则会将「北京」抽取为出发地,”上海”抽取为到达地。

直观的来看,我们也不难发现,当运行线性链CRF时,「从」字在「北京」之前,「到」在「上海」 之前;而且,在判别到达地时,前面已经抽取出了出发地,这些都对当前的判别有所贡献。

6.1 线性链 CRF 模型的原理及目标函数

线性链条件随机场的定义是: 设X=(X1,X2,…,Xn), Y=(Y1,Y2,…,Yn)均为线性链表示的随机变量序列,若在给定随机变量序列X的条件下,随机变量序列Y的条件概率分布 P(Y|X) 满足马尔可夫性(请自行搜索马尔科夫性定义), 则称 P(Y|X) 为线性链条件随机场。

在实体提取问题中,X表示输入观测序列(用户问题),Y表示对应的输出标记序列(实体类型)。

线性链条件随机场的模型

线性链 CRF 模型表示:给定输入序列x,对输出序列y进行预测的条件概率。

其中,上式右侧分母部分是规范化因子。

t(k) 是链状图中边的特征函数,称为转移特征(t for transition),依赖于当前和前一个位置,s(l)是图中节点的特征函数,称为状态特征(s for status),依赖于当前位置。

无论哪种特征函数,都将当前可能的 y(i) 作为参数。 它们都依赖于位置,是局部特征函数。

通常,特征函数 t(k) 和 s(l) 取值为1或0;当满足特征条件时取值为1,否则为0。lambda(k) 和 mu(l) 是它们对应的权值。

为简便起见,将转移特征和状态特征及其权值用统一的符号表示。设有K1个转移特征,K2个状态特征,K=K1+K2,记作:

上式其实是对特征函数进行编码,编号的前K1个属于转移特征,后K2个属于状态特征。

然后,对转移与状态特征在各个位置i求和,记作:

其中虽然有4个参数的形式,但对状态特征函数而言,y(i-1)会被忽略掉。

用 wk 表示特征 fk(y,x) 的权值,即:

于是, 线性链条件随机场模型可简化表示为

其中,右侧分母为归一化因子, wk 为模型的参数, fk(x,y) 为特征函数(feature function)。

线性链条件随机场模型 实际上是定义在时序数据上的对数线形模型,其学习方法包括极大似然估计和正则化的极大似然估计。它的优化目标函数是:

其梯度函数是:







请到「今天看啥」查看全文