自然语言处理基础
本章首先介绍自然语言处理中最基础、最本质的问题,即文本如何在计算机内表示,才能达到易于处理和计算的目的。其中,词的表示大体经过了早期的独热(One-hot)表示,到后来的分布式表示,再到最近的词向量三个阶段。至于更长文本的表示方法,本章只对最简单的词袋模型加以介绍,后续章节将介绍其他更好的表示方法。接着介绍三大类自然语言处理任务,即:语言模型、基础任务以及应用任务。其中,基础任务包括中文分词、词性标注、句法分析和语义分析等,应用任务包括信息抽取、情感分析、问答系统、机器翻译和对话系统等。由于这些任务基本可以归纳为文本分类、结构预测和序列到序列三大类问题,所以同时介绍这三大类问题的解决思路。最后,介绍自然语言处理任务的评价方法,主要包括针对确定答案的准确率和F值,针对非确定答案的BLEU值,以及针对开放答案的人工评价等。
文本的表示
若要利用计算机对自然语言进行处理,首先需要解决语言(本书特指文本)
在计算机内部的存储和计算问题。字符串(String)是文本最自然,也是最常用的机内存储形式。所谓字符串,即字符序列,而其中的一个字符本质上就是一个整数。基于字符串的文本表示方式可以实现简单的字符串增删改查等编辑任务,并能够通过编辑距离等算法计算两个字符串之间的字面相似度。在使用字符串表示(也叫符号表示)计算文本的语义信息时,往往需要使用基于规则的方法。例如,要判断一个句子的情感极性(褒义或贬义),规则的形式可能为:如果句子中出现“喜欢””漂亮”等词则为褒义;如果出现“讨厌”“丑陋"等词则为贬义。
这种基于规则的方法存在很多问题。首先,规则的归纳依赖专家的经验,需 要花费大量的人力、物力和财力;其次,规则的表达能力有限,很多语言现象无法用简单的规则描述;最后,随着规则的增多,规则之间可能存在矛盾和冲突的情况,导致最终无法做出决策。例如,一个句子中既出现了“喜欢”,又出现了“讨厌”,那么其极性应该是什么呢?
为了解决基于规则的方法存在的以上诸多问题,基于机器学习的自然语言处理技术应运而生,其最本质的思想是将文本表示为向量,其中的每一维代表一个特征。在进行决策的时候,只要对这些特征的相应值进行加权求和,就可以得到一个分数用于最终的判断。仍然以情感极性识别为例,一种非常简单的将原始文本表示为向量的方法为:令向量 \(\bm{x}\) 的每一维表示某个词在该文本中出现的次数,如 \(x_1\) 表示“我”出现的次数, \(x_2\) 表示“喜欢”出现的次数, \(x_3\) 表示“电影”出现的次数, \(x_4\) 表示“讨厌”出现的次数等,如果某个词在该句中没有出现,则相应的维数被设置为0。可见,输入向量 \(\bm{x}\) 的大小恰好为整个词表(所有不相同的词)的大小。然后就可以根据每个词对判断情感极性的重要性进行加权,如“喜欢”( \(x_2\) )对应的权重 \(w_2\) 可能比较大,而“讨厌"( \(x_4\) )对应的权重 \(w_4\) 可能比较小(可以为负数),对于情感极性影响比较小的词,如“我”“电影”等,对应的权重可能会趋近于 \(0\) 。这种文本表示的方法是两种技术的组合,即词的独热表示和文本的词袋表示。除了可以应用于基于机器学习的方法,文本向量表示还可以用于计算两个文本之间的相似度,即使用余弦函数等度量函数表示两个向量之间的相似度,并应用于信息检索等任务。下面就以上提到的各项技术分别进行详细的介绍。
词的独热表示
所谓词的独热表示,即使用一个词表大小的向量表示一个词(假设词表为 \( \mathbb{V}\) ,则其大小为 \(|\mathbb{V}|\) ),然后将词表中的第 \(i\) 个词 \(w_i\) 表示为向量:
\[ \bm{e}_{w_i}=[0,0,\cdots,\underbrace{1}_{第i个词},\cdots,0] \in \set{0,1}^{|\mathbb{V}|} \tag{1} \] 在该向量中,词表中第 \(i\) 个词在第 \(i\) 维上被设置为 \(1\) ,其余维均为 \(0\) 。这种表示被称为词的独热表示或独热编码(One-hot Encoding)。
独热表示的一个主要问题就是不同词使用完全不同的向量进行表示,这会导 致即使两个词在语义上很相似,但是通过余弦函数来度量它们之间的相似度时值却为 \(0\) 。另外,当应用于基于机器学习的方法时,独热模型会导致数据稀疏(Data Sparsity)问题。例如,假设在训练数据中只见过“漂亮”,在测试数据中出现了
“美丽”,虽然它们之间很相似,但是系统仍然无法恰当地对“美丽”进行加权。由于数据稀疏问题,导致当训练数据规模有限时,很多语言现象没有被充分地学习到。
为了缓解数据稀疏问题,传统的做法是除了词自身,再提取更多和词相关的泛化特征,如词性特征、词义特征和词聚类特征等。以语义特征为例,通过引入WordNet等语义词典,可以获知“漂亮”和“美丽”是同义词,然后引入它们的共同语义信息作为新的额外特征,从而缓解同义词的独热表示不同的问题。可以说,在使用传统机器学习方法解决自然语言处理问题时,研究者的很大一部分精力都用在了挖掘有效的特征上。
词的分布式表示
词的独热表示容易导致数据稀疏问题,而通过引入特征的方法虽然可以缓解 该问题,但是特征的设计费时费力。那么有没有办法自动提取特征并设置相应的特征值呢?
分布式语义假设
人们在阅读过程中遇到从未见过的词时,通常会根据上下文来推断其含义以 及相关属性。基于这种思想,John Rupert Firth于1957年提出了分布式语义假设:词的含义可由其上下文的分布进行表示。基于该思想,可以利用大规模的未标注文本数据,根据每个词的上下文分布对词进行表示。当然,分布式语义假设仅仅提供了一种语义建模的思想。具体到表示形式和上下文的选择,以及如何利用上下文的分布特征,都是需要解决的问题。
下面用一个具体的例子演示如何构建词的分布式表示。假设语料库中有以下三句话:
|
|
假设以词所在句子中的其他词语作为上下文,那么可以创建如表1所示的词语共现频次表。其中,词表 \(\mathbb{V}\) 包含“我”“喜欢”···“。”共10个词,即 \(|\mathbb{V}|=10\) 。表中的每一项代表一个词 \(w_i\) 与另一个词 \(w_j\) (上下文)在同一个句子中的共现频次,每个词与自身的共现频次设置为 \(0\) 。
\(w_j\) \(w_i\) | 我 | 喜欢 | 自然 | 语言 | 处理 | 爱 | 深度 | 学习 | 机器 | 。 |
---|---|---|---|---|---|---|---|---|---|---|
我 | 0 | 2 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 3 |
喜欢 | 2 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 2 |
自然 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
语言 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
处理 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
爱 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
深度 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
学习 | 2 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
机器 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
。 | 3 | 2 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 0 |
表1 词语共现频次表
表中的每一行代表一个词的向量。通过计算两个向量之间的余弦函数,就可 以计算两个词的相似度。如“喜欢”和“爱”,由于有共同的上下文“我”和“学习”,使得它们之间具有了一定的相似性,而不是如独热表示一样,没有任何关系。
除了词,上下文的选择有很多种方式,而选择不同的上下文得到的词向量表示性质会有所不同。例如,可以使用词在句子中的一个固定窗口内的词作为其上下文,也可以使用所在的文档本身作为上下文。前者得到的词表示将更多地反映词的局部性质:具有相似词法、句法属性的词将会具有相似的向量表示。而后者 将更多地反映词代表的主题信息。
不过,直接使用与上下文的共现频次作为词的向量表示,至少存在以下三个问题:
◦高频词误导计算结果。如上例中,“我”“。”与其他词的共现频次很高,导致实际上可能没有关系的两个词由于都和这些词共现过,从而产生了较高的 相似度。
◦共现频次无法反映词之间的高阶关系。例如,假设词“A”与”B”共现过,“B”与"C”共现过,“C”与“D"共现过,通过共现频次,只能获知“A”与“C”都与“B”共现过,它们之间存在一定的关系,而“A”与“D”这种高阶的关系则无法知晓。
◦仍然存在稀疏性的问题。即向量中仍有大量的值为0,这一点从表1中也可以看出。
下面分别介绍如何通过点互信息和奇异值分解两种技术来解决这些问题。
点互信息
首先看如何解决高频词误导计算结果的问题。最直接的想法是:如果一个词与很多词共现,则降低其权重;反之,如果一个词只与个别词共现,则提高其权重。信息论中的点互信息(Pointwise Mutual Information,PMI)恰好能够做到这一点。对于词 \(w\) 和上下文 \(c\) ,其PMI为:
\[ \text{PMI}(w,c)=\log_2\frac{P(w,c)}{P(w)P(c)} \tag{2} \] 式中, \(P(w,c)\) 、 \(P(w)\) 、 \(P(c)\) 分别是 \(w\) 与 \(c\) 的共现概率,以及 \(w\) 和 \(c\) 分别出现的概率。可见,通过PMI公式计算,如果 \(w\) 和 \(c\) 的共现概率(与频次正相关)较高, 但是 \(w\) 或者 \(c\) 出现的概率也较高(高频词),则最终的PMI值会变小;反之,即便 \(w\) 和 \(e\) 的共现概率不高,但是 \(w\) 或者 \(c\) 出现的概率较低(低频词),则最终的PMI值也可能会比较大。从而较好地解决高频词误导计算结果的问题。
可以通过最大似然估计(Maximum Likelihood Estimation,MLE),分别计算相关的概率值。具体公式为:
式中: \(C(w,c)\) 表示词 \(w\) 和上下文 \(c\) 在语料库中出现的次数(也成为频次); \(\sum_{c'}C(w,c')\) 为表1按行求和, \(\sum_{w'}C(w',c)\) 为表1按列求和; \(\sum_{w'}\sum_{c'}C(w',c')\) 为全部共现频次的和。代入以上 \(3\) 个公式,式(2)可进一步写为
\[ \begin{aligned} \text{PMI}(w,c)=&\log_2\frac{P(w,c)}{P(w)P(c)}\\[15pt] =&\log_2\frac{\displaystyle\frac{C(w,c)}{\sum_{w',c'}C(w',c')}}{\displaystyle\frac{\sum_{c'}C(w,c')}{\sum_{w'}\sum_{c'}C(w',c')}\cdot\frac{\sum_{w'}C(w',c)}{\sum_{w'}\sum_{c'}C(w',c')}}\\[30pt] =&\log_2\frac{\displaystyle C(w,c)}{\displaystyle\frac{\sum_{c'}C(w,c')\sum_{w'}C(w',c)}{\sum_{w'}\sum_{c'}C(w',c')}} \end{aligned} \tag{4} \]另外,当某个词与上下文之间共现次数较低时,可能会得到负的PMI值。考虑到这种情况下的PMI不太稳定(具有较大的方差),在实际应用中通常采用PPMI(Positive PMI)的形式,即:
\[ \text{PPMI}(w,c)=\max\set{\text{PMI}(w,c),0} \tag{5} \]接下来介绍PMI的代码实现。首先,将类似表1形式的共现频次表定义为共现矩阵的形式,即 \(\bm{M} \in \mathbb{R}^{|\mathbb{V}|\times|\mathbb{C}|}\) ,其中 \(|\mathbb{V}|\) 为词表, \(\mathbb{C}\) 为全部的上下文, \(M_{ij}\) 为词 \(w_i\) 与上下文 \(c_j\) 在语料库中的共现频次。然后,编写如下代码计PPMI:
|
|
则最终输出结果为
|
|
除了PMI,还有很多种其他方法可以达到类似的目的,如信息检索中常用的 TF-IDF等,在此不再加以赘述。
奇异值分解
下面看如何解决共现频次无法反映词之间高阶关系的问题。相关的技术有很 多,其中奇异值分解(Singular Value Decomposition,SVD)是一种常见的做法。对共现矩阵 \(\bm{M}\) 进行奇异值分解:
\[ \bm{M}=\bm{U}\bm{\Sigma}\bm{V}^T \tag{6} \] 式中: \(\bm{U} \in \mathbb{R}^{|\mathbb{V}|\times r}, \bm{V} \in \mathbb{R}^{r \times |\mathbb{C}}|\) 为正交矩阵,满足 \(\bm{U}^T\bm{U}=\bm{V}^T\bm{V}=\bm{I}\) ; \(\bm{\Sigma} \in \mathbb{R}^{r \times r}\) 是由 \(r\) 个奇异值(Singular Value)构成的对角矩阵。
若在 \(\bm{\Sigma}\) 中仅保留 \(d\) 个( \(d < r\) )最大的奇异值( \(\bm{U}\) 和 \(\bm{V}\) 也只保留相应的维度),则被称为截断奇异值分解(Truncated Singular Value Decomposition)。截断奇异值分解实际上是对矩阵M的低秩近似(详细见截断奇异值分解)。
通过截断奇异值分解所得到的矩阵 \(\bm{U}\) 中的每一行,则为相应词的 \(d\) 维向量表示,该向量一般具有连续、低维和稠密的性质。由于 \(\bm{U}\) 的各列相互正交,因此可以认为词表示的每一维表达了该词的一种独立的“潜在语义”,所以这种方法也被称作潜在语义分析(Latent Semantic Analysis,LSA)。相应地, \(\bm{\Sigma}\bm{V}^T\) 的每一列也可以作为相应上下文的向量表示。
在Python的numpy.linalg
库中内置了SVD函数,只需要输入共现矩阵,然后调用相应的函数即可。如:
|
|
执行结束后,矩阵 \(\bm{U}\) 中的每一行为相应词经过奇异值分解后的向量表示。如果仅保留前两维,每个词就可以显示为二维平面中的一个点,然后使用下面的代码进行可视化:
|
|
截断奇异值分解结果如图1所示,可见:上下文比较相近的词在空间上的距离比较近,如“深度”“学习”等;而“我”和等高频词则与其他词语距离比较远。
图1 截断奇异值分解结果
在信息检索等领域,也经常通过词与其出现的文档构成“词-文档”共现矩阵,此时也可以通过以上介绍的奇异值分解技术进行降维,并在低维空间(潜在语义空间)内计算词语或者文档之间的相似度,该技术也称潜在语义索引(Latent Semantic Indexing,LSI)。
虽然在基于传统机器学习的方法中,词的分布式表示取得了不错的效果,但是其仍然存在一些问题。首先,当共现矩阵规模较大时,奇异值分解的运行速度非常慢;其次,如果想在原来语料库的基础上增加更多的数据,则需要重新运行奇异值分解算法,代价非常高;另外,分布式表示只能用于表示比较短的单元,如词或短语等,如果待表示的单元比较长,如段落、句子等,由于与其共现的上下文会非常少,则无法获得有效的分布式表示;最后,分布式表示一旦训练完成,则无法修改,也就是说,无法根据具体的任务调整其表示方式。为了解决这些问题,可引入一种新的词表示方式——词嵌入表示。
词嵌入表示
与词的分布式表示类似,词嵌入表示(Word Embedding)也使用一个连续、低维、稠密的向量来表示词,经常直接简称为词向量,但与分布式表示不同之处在于其赋值方式。在词的分布式表示中,向量值是通过对语料库进行统计得到的,然后再经过点互信息、奇异值分解等变换,一旦确定则无法修改。而词向量中的向量值,是随着目标任务的优化过程自动调整的,也就是说,可以将词向量中的向量值看作模型的参数。不过,如果目标任务的训练数据比较少,学习合适的词向量难度会比较大,因此,利用自然语言文本中所蕴含的自监督学习信号(即词与上下文的共现信息),先来预训练词向量,往往会获得更好的结果。
文本的词袋表示
上面介绍了几种常见的词表示方法,那么如何通过词的表示构成更长文本的
表示呢?在此介绍一种最简单的文本表示方法——**词袋(Bag-Of-Words,BOW)**表示。所谓词袋表示,就是假设文本中的词语是没有顺序的集合,将文本中的全部词所对应的向量表示(既可以是独热表示,也可以是分布式表示或词向量)相加,即构成了文本的向量表示。如在使用独热表示时,文本向量表示的每一维恰好是相应的词在文本中出现的次数。
虽然这种文本表示的方法非常简单、直观,但是其缺点也非常明显:首先是 没有考虑词的顺序信息,导致“张三打李四”和“李四打张三”,虽然含义不同,但是由于它们包含的词相同,即使词序不同,词袋表示的结果也是一样的;其次是无法融入上下文信息。比如要表示“不喜欢”,只能将两个词的向量相加,无法进行更细致的语义操作。当然,可以通过增加词表的方法加以解决,比如引入二元词(Bigram)词表,将"不+喜欢"等作为"词”,然后同时学习二元词的词向量表示。这种方法既能部分解决否定词的问题,也能部分解决局部词序的问题,但是随着词表的增大,会引入更严重的数据稀疏问题。深度学习技术的引入为解决这些问题提供了更好的方案,后续将详细介绍。
自然语言处理任务
本节依次介绍三大类常见的自然语言处理任务,即:语言模型、基础任务以 及应用任务。
语言模型
语言模型(Language Model,LM)(也称统计语言模型)是描述自然语言概率分布的模型,是一个非常基础和重要的自然语言处理任务。利用语言模型,可以计算一个词序列或一句话的概率,也可以在给定上文的条件下对接下来可能出现 的词进行概率分布的估计。同时,语言模型是一项天然的预训练任务,在基于预训练模型的自然语言处理方法中起到非常重要的作用,因此这种预训练模型有时也被称为预训练语言模型。本篇将主要介绍经典的N元语言模型(N-gramLanguage Model),现代的神经网络语言模型(Neural Network Language Model)将在后续进行详细的介绍。
N元语言模型
语言模型的基本任务是在给定词序列 \(w_1w_2\cdots w_{t-1}\) 的条件下,对下一时刻 \(t\) 可能出现的词 \(w_t\) 的条件概率 \(P(w_t | w_1w_2\cdots w_{t-1})\) 进行估计。一般地,把 \(w_1w_2\cdots w_{t-1}\) 一称为 \(w_t\) 的历史。例如,对于历史“我 喜欢”,希望得到下一个词为“读书”的概率,即: \(P(读书|我\space 喜欢)\) 。在给定一个语料库时,该条件概率可以理解为当语料中出现“我喜欢”时,有多少次下一个词为“读书”,然后通过最大似然估计进行计算:
\[ P(读书|我 喜欢)=\frac{C(我\space喜欢\space读书)}{C(我\space喜欢)} \tag{7} \] 式中, \(C(\cdot)\) 表示相应词序列在语料库中出现的次数(也成为频次)。
通过以上的条件概率,可以进一步计算一个句子出现的概率,即相应单词序 列的联合概率 \(P(w_1w_2\cdots w_l)\) 为序列的长度。可以利用链式法则对该式进行分解,从而将其转化为条件概率的计算问题,即:
式中, \(w_{i:j}\) 表示由位置 \(i\) 到 \(j\) 的子串 \(w_iw_{i+1}\cdots w_j\) 。
然而,随着句子长度的增加, \(w_{1:i-1}\) 出现的次数会越来越少,甚至从未出现过,那么 \(P(w_i|w_{1:i-1})\) 则很可能为 \(0\) ,此时对于概率估计就没有意义了。为了解决该问题,可以假设“下一个词出现的概率只依赖于它前面 \(n-1\) 个词",即
该假设被称为马尔可夫假设(Markov Assumption)。满足这种假设的模型,被称为N元语法或N元文法(N-gram)模型。特别地,当 \(n=1\) 时,下一个词的出现独立于其历史,相应的一元语法通常记作unigram。当 \(n=2\) 时,下一个词只依赖于前 \(1\) 个词,对应的二元语法记作bigram。二元语法模型也被称为一阶马尔可夫链(MarkovChain)。类似的,三元语法假设( \(n=3\) )也被称为二阶马尔可夫假设,相应的三元语法记作trigram。 \(n\) 的取值越大,考虑的历史越完整。在unigram模型中,由于词与词之间相互独立,因此它是与语序无关的。
以bigram模型为例,式(8)可转换为
为了使 \(P(w_i|w_{i-1})\) 对于 \(i=1\) 有意义,可在句子的开头增加一个句首标记<BOS>
( Begin Of Sentence),并设 \(w_0=\) <BOS>
。同时,也可以在句子的结尾增加一个句尾标记<EOS>
(End Of Sentence),设 \(w_{l+1}=\) <EOS>
。
平滑
虽然马尔可夫假设(下一个词出现的概率只依赖于它前面 \(n-1\) 个词)降低了句子概率为 \(0\) 的可能性,但是当 \(n\) 比较大或者测试句子中含有未登录词(Out-Of-Vocabulary,OOV)时,仍然会出现“零概率”问题。由于数据的稀疏性,训练数据很难覆盖测试数据中所有可能出现的N-gram,但这并不意味着这些N-gram出现的概率为0。为了避免该问题,需要使用平滑(Smoothing)技术调整概率估计的结果。本节将介绍一种最基本,也最简单的平滑算法——折扣法。
折扣法(Discounting)平滑的基本思想是“损有余而补不足”,即从频繁出现的N-gram中匀出一部分概率并分配给低频次(含零频次)的N-gram,从而使得整体概率分布趋于均匀。
加1平滑(Add-one Discounting)是一种典型的折扣法,也被称为拉普拉斯平滑(Laplace Smoothing),它假设所有N-gram的频次比实际出现的频次多一次。例如,对于unigram模型来说,平滑之后的概率可由以下公式计算
式中, \(|\mathbb{V}|\) 是词表大小。所有未登录词可以映射为一个区别于其他已知词汇的独立标记,如<UNK>。
相应的,对于bigram模型,则有
在实际应用中,尤其当训练数据较小时,加1平滑将对低频次或零频次事件 给出过高的概率估计。一种自然的扩展是加 \(\delta\) 平滑。在加 \(\delta\) 平滑中,假设所有事件的频次比实际出现的频次多 \(\delta\) 次,其中 \(0 \le \delta \le 1\) 。
以bigram语言模型为例,使用加 \(\delta\) 平滑之后的条件概率为
关于超参数 \(\delta\) 的取值,需要用到开发集数据。根据开发集上的困惑度对不同 \(\delta\) 取值下的语言模型进行评价,最终将最优的 \(\delta\) 用于测试集。
由于引入了马尔可夫假设,导致N元语言模型无法对长度超过N的长距离词语依赖关系进行建模,如果将N扩大,又会带来更严重的数据稀疏问题,同 时还会急剧增加模型的参数量(N-gram数目),为存储和计算都带来极大的挑战。在后续篇章中将要介绍的神经网络语言模型可以较好地解决N元语言模型的这些缺陷。
语言模型性能评价
如何衡量一个语言模型的好坏呢?一种方法是将其应用于具体的外部任务(如机器翻译),并根据该任务上指标的高低对语言模型进行评价。这种方法也 被称为“外部任务评价”,是最接近实际应用需求的一种评价方法。但是,这种方式的计算代价较高,实现的难度也较大。因此,目前最为常用的是基于困惑度(Perplexity,PPL)的“内部评价”方式。
为了进行内部评价,首先将数据划分为不相交的两个集合,分别称为训练集 \(\mathbb{D}^{\text{train}}\) 和测试集 \(\mathbb{D}^{\text{test}}\) ,其中 \(\mathbb{D}^{\text{train}}\) 用于估计语言模型的参数。由该模型计算出的测试集的概率 \(P(\mathbb{D}^{\text{test}})\) 则反映了模型在测试集上的泛化能力。
假设测试集 \(\mathbb{D}^{\text{test}}=w_1w_2 \cdots w_N\) (每个句子的开始和结束分布增加<BOS>
与<EOS>
标记),那么测试集的概率为:
困惑度则为模型分配给测试集中每一个词的概率的几何平均值的倒数
\[ \text{PPL}(\mathbb{D}^{\text{test}})=\left(\prod_{i=1}^{N}P(w_i|w_{1:i-1})\right)^{-\frac{1}{N}} \tag{15} \]例如,对于bigram语言模型而言
\[ \text{PPL}(\mathbb{D}^{\text{test}})=\left(\prod_{i=1}^{N}P(w_i|w_{i-1})\right)^{-\frac{1}{N}} \tag{16} \]考虑到多个概率的连乘可能带来浮点数下溢的问题,通常需要将式(16)转化为对数和的形式
\[ \text{PPL}(\mathbb{D}^{\text{test}})=2^{-\displaystyle\frac{1}{N}\sum_{i=1}^{N}\log_2 P(w_i|w_{i-1})} \tag{17} \]困惑度越小,意味着单词序列的概率越大,也意味着模型能够更好地解释测试集中的数据。需要注意的是,困惑度越低的语言模型并不总是能在外部任务上取得更好的性能指标,但是两者之间通常呈现出一定的正相关性。因此,困惑度可以作为一种快速评价语言模型性能的指标,而在将其应用于下游任务时,仍然需要根据其在具体任务上的表现进行评价。
自然语言处理基础任务
自然语言处理的一大特点是任务种类纷繁复杂,有多种划分的方式。从处理 顺序的角度,可以分为底层的基础任务以及上层的应用任务。其中,基础任务往往是语言学家根据内省的方式定义的,输出的结果往往作为整个系统的一个环节或者下游任务的额外语言学特征,而并非面向普罗大众。本节介绍几种常见的基础任务,包括词法分析(分词、词性标注)、句法分析和语义分析等。
中文分词
词(Word)是最小的能独立使用的音义结合体,是能够独立运用并能够表达语义或语用内容的最基本单元。在以英语为代表的印欧语(Indo-European languages)中,词之间通常用分隔符(空格等)区分。但是在以汉语为代表的汉藏语系(Sino-Tibetan languages),以及以阿拉伯语为代表的闪—含语系(Semito-Hamitic languages)中,却不包含明显的词之间的分隔符。因此,为了进行后续的自然语言处理,通常需要首先对不含分隔符的语言进行分词(Word Segmentation)操作。本节以中文分词为例,介绍词的切分问题和最简单的分词算法。
中文分词就是将一串连续的字符构成的句子分割成词语序列,如“我喜欢读书”,分词后的结果为“我 喜欢 读书”。最简单的分词算法叫作正向最大匹配(Forward Maximum Matching,FMM)分词算法,即从前向后扫描句子中的字符
串,尽量找到词典中较长的单词作为分词的结果。具体代码如下:
|
|
通过下面的代码加载词典并调用正向最大匹配分词算法:
|
|
这里提供一个可运行的辞典的例子lexicon.txt[点此下载]。
正向最大匹配分词算法存在的明显缺点是倾向于切分出较长的词,这容易导致错误的切分结果,如“研究生命的起源”,由于“研究生”是词典中的词,所以使用正向最大匹配分词算法的分词结果为“研究生 命 的 起源”,显然分词结果不正确。
这种情况一般被称为切分歧义问题,即同一个句子可能存在多种分词结果,一旦分词错误,则会影响对句子的语义理解。正向最大匹配分词算法除了存在切分歧义,对中文词的定义也不明确,如“哈尔滨市”可以是一个词,也可以认为“哈尔滨”是一个词,“市”是一个词。因此,目前存在多种中文分词的规范,根据不同规范又标注了不同的数据集。
另外,就是未登录词问题,也就是说有一些词并没有收录在词典中,如新词、命名实体、领域相关词和拼写错误词等。由于语言的动态性,新词语的出现可谓是层出不穷,所以无法将全部的词都及时地收录到词典中,因此,一个好的分词系统必须能够较好地处理未登录词问题。相比于切分歧义问题,在真实应用环境中,由未登录词问题引起的分词错误比例更高。因此,分词任务本身也是一项富有挑战的自然语言处理基础任务。
子词切分
一般认为,以英语为代表的印欧语系的语言,词语之间通常已有分隔符(空格等)进行切分,无须再进行额外的分词处理。然而,由于这些语言往往具有复杂的词形变化,如果仅以天然的分隔符进行切分,不但会造成一定的数据稀疏问题,还会导致由于词表过大而降低处理速度。如“computer”“computers”“computing”等,虽然它们语义相近,但是被认为是截然不同的单词。传统的处理方法是根据语言学规则,引入词形还原(Lemmatization)或者词干提取(Stemming)等任务, 提取出单词的词根,从而在一定程度上克服数据稀疏问题。其中,词形还原指的是将变形的词语转换为原形,如将“computing”还原为“compute”;而词干提取则是将前缀、后缀等去掉,保留词干(Stem),如“computing”的词干为“comput”,可见,词干提取的结果可能不是一个完整的单词。
词形还原或词干提取虽然在一定程度上解决了数据稀疏问题,但是需要人工撰写大量的规则,这种基于规则的方法既不容易扩展到新的领域,也不容易扩展到新的语言上。因此,基于统计的无监督子词(Subword)切分任务应运而生,并在现代的预训练模型中使用。
所谓子词切分,就是将一个单词切分为若干连续的片段。目前有多种常用的
子词切分算法,它们的方法大同小异,基本的原理都是使用尽量长且频次高的子词对单词进行切分。此处重点介绍常用的字节对编码(Byte Pair Encoding,BPE)算法。
首先,BPE通过算法1构造子词词表。
算法1(BPE中子词词表构造算法)
输出:子词词表
下面,通过一个例子说明如何构造子词词表。首先,假设语料库中存在下列 Python词典中的3个单词以及每个单词对应的频次。其中,每个单词结尾增加了一个'</w>'
字符,并将每个单词切分成独立的字符构成子词。
|
|
初始化的子词词表表为3个单词包含的全部字符:
|
|
然后,统计单词内相邻的两个子词的频次,并选取频次最高的子词对e
,和s
,合并成新的子词es
(共出现9次),然后加入子词词表中,并将语料库中不再存在的子词s
从子词词表中删除。此时,语料库以及子词词表变为:
|
|
|
|
然后,合并下一个子词对es
和t
,新的语料库和子词词表为:
|
|
|
|
重复以上过程,直到子词词表大小达到一个期望的词表大小为止。构造好子词词表后,如何将一个单词切分成子词序列呢?可以采用贪心的方法,即首先将子词词表按照子词的长度由大到小进行排序。然后,从前向后遍历子词词表,依次判断一个子词是否为单词的子串,如果是的话,则将该单词切分,然 后继续向后遍历子词词表。如果子词词表全部遍历结束,单词中仍然有子串没有被切分,那么这些子串一定为低频串,则使用统一的标记,如'<UNK>'
进行替换。
例如,对一个含有三个单词的句子['the</w>', 'highest</w>', 'mountain </w>]
进行切分,假设排好序的词表为['errrr</w>','tain</w>' ,'moun' , 'est</w>' , 'high' , 'the</w>' , 'a</w>']
,则子词切分的结果为['the</w>', 'high', 'est</w>', 'moun', 'tain</w>']
。此过程也叫作对句子(单词序列)进行编码。
那么,如何对一个编码后的句子进行解码,也就是还原成原始的句子呢?此 时,单词结尾字符'</w>'
便发挥作用了。只要将全部子词进行拼接,然后将结尾字符替换为空格,就恰好为原始的句子了。
通过以上过程可以发现,BPE算法中的编码步骤需要遍历整个词表,是一个 非常耗时的过程。可以通过缓存技术加快编码的速度,即将常见单词对应的编码结果事先存储下来,然后编码时通过查表的方式快速获得编码的结果。对于查不到的单词再实际执行编码算法。由于高频词能够覆盖语言中的大部分单词,因此 该方法实际执行编码算法的次数并不多,因此可以极大地提高编码过程的速度。
除了BPE,还有很多其他类似的子词切分方法,如WordPiece、Unigram Language Model(ULM)算法等。其中,WordPiece与BPE算法类似,也是每次从子词词表中选出两个子词进行合并。与BPE的最大区别在于,选择两个子词进行合并的策略不同:BPE选择频次最高的相邻子词合并,而WordPiece选择能够提升语言模型概率最大的相邻子词进行合并。经过公式推导,提升语言模型概率最大的相邻子词具有最大的互信息值,也就是两子词在语言模型上具有较强的关联性,它们经常在语料中以相邻方式同时出现。
与WordPiece一样,ULM同样使用语言模型挑选子词。不同之处在于,BPE和WordPiece算法的词表大小都是从小到大变化,属于增量法。而ULM则是减量法,即先初始化一个大词表,根据评估准则不断丢弃词表中的子词,直到满足限定条件。ULM算法考虑了句子的不同分词可能,因而能够输出带概率的多个子词分段。
为了更方便地使用上述子词切分算法,Google推出了SentencePiece开源工具包,其中集成了 BPE、ULM等子词切分算法,并支持Python、C++编程语言的调 用,具有快速、轻量的优点。此外,通过将句子看作Unicode编码序列,从而使其能够处理多种语言。
词性标注
词性是词语在句子中扮演的语法角色,也被称为词类(Part-Of-Speech,POS)。例如,表示抽象或具体事物名字(如“计算机”)的词被归为名词,而表示动作(如“打”)、状态(如“存在”)的词被归为动词。词性可为句法分析、语义理解等提供帮助。
词性标注(POS Tagging)任务是指给定一个句子,输出句子中每个词相应的词性。例如,当输入句子为:
|
|
则词性标注的输出为:
|
|
其中,斜杠后面的PN
、VV
、NN
和PU
分别代表代词、动词、名词和标点符号。词性标注的主要难点在于歧义性,即一个词在不同的上下文中可能有不同的 词性。例如,上例中的“下”,既可以表示动词,也可以表示方位词。因此,需要结合上下文确定词在句子中的具体词性。
句法分析
句法分析(SyntacticParsing)的主要目标是给定一个句子,分析句子的句法成分信息,例如主谓宾定状补等成分。最终的目标是将词序列表示的句子转换成树状结构,从而有助于更准确地理解句子的含义,并辅助下游自然语言处理任务。例如,对于以下两个句子:
|
|
虽然它们只相差一个“的”字,但是表达的语义是截然不同的,这主要是因为两句话的主语不同。其中,第一句话的主语是“文章”,而第二句话的主语是"转"的动作。通过对两句话进行句法分析,就可以准确地获知各自的主语,从而推导出不同的语义。
典型的句法结构表示方法包含两种——短语结构句法表示和依存结构句法表示。它们的不同点在于依托的文法规则不一样。其中,短语结构句法表示依托上下文无关文法,属于一种层次性的表示方法。而依存结构句法表示依托依存文法。
图2对比了两种句法结构表示方法。在短语结构句法表示中,S
代表起始符号,NP
和VP
分别代表名词短语和动词短语。在依存结构句法表示中,sub
和obj
分别表示主语和宾语,root
表示虚拟根节点,其指向整个句子的核心谓词。
图2 两种句法结构表示方法结果对比
语义分析
自然语言处理的核心任务即是让计算机“理解”自然语言所蕴含的意义,即语义(Semantic)。本章前面介绍的文本向量表示,可以被认为隐性地蕴含了很多语义信息。而一般意义上的语义分析指的是通过离散的符号及结构显性地表示语义。根据待表示语言单元粒度以及语义表示方法的不同,语义分析又可以被分为多种形式。
从词语的粒度考虑,一个词语可能具有多种语义(词义),例如“打”,含义既可能是“攻击”(如“打人”),还可能是“玩”(如“打篮球”),甚至“编织”(如“打毛衣")等。根据词语出现的不同上下文,确定其具体含义的自然语言处理任务被称为词义消歧(Word Sense Disambiguation,WSD)。对于每个词可能具有的词义,往往是通过语义词典确定的,如WordNet等。除了以上一词多义情况,还有多词一义的情况,如“马铃薯”和“土豆”具有相同的词义。
由于语言的语义组合性和进化性,无法像词语一样使用词典定义句子、段落或篇章的语义,因此很难用统一的形式对句子等语言单元的语义进行表示。众多的语言学流派提出了各自不同的语义表示形式,如语义角色标注(Semantic Role Labeling,SRL)、语义依存分析(Semantic Dependency Parsing,SDP)等。
其中,语义角色标注也称谓词论元结构(Predicate-Argument Structure),即首先识别句子中可能的谓词(一般为动词),然后为每个谓词确定所携带的语义角色(也称作论元),如表示动作发出者的施事(Agent),表示动作承受者的受事(Patient)等。除了核心语义角色,还有一类辅助描述动作的语言成分,被称为附 加语义角色,如动作发生的时间、地点和方式等。表2展示了一个语义角色标注的示例,其中有两个谓词——“喜欢”和“下”并针对每个谓词产生相应的论元输出结果。
输入 | 他 | 喜欢 | 下 | 象棋 |
---|---|---|---|---|
输出1 | 施事 | 谓词 | 受事 | |
输出2 | 施事 | 谓词 | 受事 |
表2 语义角色标注示例
语义依存分析则利用通用图表示更丰富的语义信息。根据图中节点类型的不同,又可分为两种表示——语义依存图(Semantic Dependency Graph)表示和概念语义图(Conceptual Graph)表示。其中,语义依存图中的节点是句子中实际存在的词语,在词与词之间创建语义关系边。而概念语义图首先将句子转化为虚拟的概念节点,然后在概念节点之间创建语义关系边。图3展示了一个语义依存图分析结果示例。
图3 语义依存图分析结果示例
以上的语义表示方式属于通用语义表示方式,也就是针对各种语言现象,设计统一的语义表示。除此之外,还有另一类语义分析用于专门处理具体的任务,如将自然语言表示的数据库查询转换成结构化查询语言(SQL)。例如,对于如表3所示的学生信息表,系统需要将用户的自然语言查询:年龄大于18岁的学生姓名, 转化为 SQL 语句:select name where age > 18
。
学号 | 姓名 | 年龄 | \(\cdots\) |
---|---|---|---|
1001 | 张三 | 18 | \(\cdots\) |
1002 | 李四 | 19 | \(\cdots\) |
\(\vdots\) | \(\vdots\) | \(\vdots\) | \(\vdots\) |
表3 学生信息表
自然语言处理应用任务
本节介绍信息抽取、情感分析、问答系统、机器翻译和对话系统等自然语言处理应用任务。这些任务可以直接或间接地以产品的形式为终端用户提供服务,是自然语言处理研究应用落地的主要技术。
信息抽取
信息抽取(Information Extraction,IE)是从非结构化的文本中自动提取结构化信息的过程,这种结构化的信息方便计算机进行后续的处理。另外,抽取的结 果还可以作为新的知识加入知识库中。信息抽取一般包含以下几个子任务。
命名实体识别(Named Entity Recognition,NER)是在文本中抽取每个提及的命名实体并标注其类型,一般包括人名、地名和机构名等,也包括专有名称等,如书名、电影名和药物名等。在文本中找到提及的命名实体后,往往还需要将这些命名实体链接到知识库或知识图谱中的具体实体,这一过程被称作实体链接(Entity Linking)。如“华盛顿"既可以指美国首任总统,也可以指美国首都,需要根据上下文进行判断,这一过程类似于词义消歧任务。
关系抽取(Relation Extraction)用于识别和分类文本中提及的实体之间的语义关系,如夫妻、子女、工作单位和地理空间上的位置关系等二元关系。
事件抽取(Event Extraction)的任务是从文本中识别人们感兴趣的事件以及事件所涉及的时间、地点和人物等关键元素。其中,事件往往使用文本中提及的具体触发词(Trigger)定义。可见,事件抽取与语义角色标注任务较为类似,其中触发词对应语义角色标注中的谓词,而事件元素则可认为是语义角色标注中的论元。
事件的发生时间往往比较关键,因此时间表达式(Temporal Expression)识别也被认为是重要的信息抽取子任务,一般包括两种类型的时间:绝对时间(日期、 星期、月份和节假日等)和相对时间(如明天、两年前等)。使用时间表达归一化(Temporal Expression Normalization)将这些时间表达式映射到特定的日期或一天中的时间。
下面通过一个例子,综合展示以上的各项信息抽取子任务。如通过下面的新
闻报道:
|
|
信息抽取结果如表4所示。
信息抽取子任务 | 抽取结果 |
---|---|
命名实体识别 | 公司名:AMD 公司名:赛灵思 |
关系抽取 | 赛灵思 \(\xRightarrow{\text{从属}}\) AMD |
时间表达式抽取 | 10月28日 |
时间表达式归一化 | 10月28日 \(\to\) 2020年10月28日 |
事件抽取 | 事件:收购 事件:2020年10月28日 收购者:AMD 被收购者:赛灵思 收购金额:350亿美元 |
表4 信息抽取结果
情感分析
情感(Sentiment)是人类重要的心理认知能力,使用计算机自动感知和处理人类情感已经成为人工智能领域重要的研究内容之一。自然语言处理中的情感分析主要研究人类通过文字表达的情感,因此也称为文本情感分析。但是,情感又是一个相对比较笼统的概念,既包括个体对外界事物的态度、观点或倾向性,如正面、负面等;又可以指人自身的情绪(Emotion),如喜、怒、哀和惧等。随着互联网的迅速发展,产生了各种各样的用户生成内容(User Generated Content, UGC),其中很多内容包含着人们的喜怒哀惧等情感,对这些情感的准确分析有助于了解人们对某款产品的喜好,随时掌握舆情的发展。因此,情感分析成为目前自然语言处理技术的主要应用之一。
情感分析可以从任务角度分为两个主要的子任务,即情感分类(识别文本中蕴含的情感类型或者情感强度,其中,文本既可以是句子,也可以是篇章)和情感信息抽取(抽取文本中的情感元素,如评价词语、评价对象和评价搭配等)。针对下面的用户评论:
|
|
情感分析结果如表5所示。
情感分析子任务 | 分析结果 |
---|---|
情感分类 | 褒义 |
情感信息抽取 | 评价词:不错;可以 评价对象:屏幕;性能 评价搭配:屏幕 \(\Leftrightarrow\) 不错;性能 \(\Leftrightarrow\) 可以 |
表5 情感分析结果
由于情感分析具有众多的应用场景,如商品评论的分析、舆情分析等,因此, 情感分析受到工业界的广泛关注,已成为自然语言处理研究应用落地的重要体现。另外,情感分析还在社会学、经济学和管理学等领域显示出重要的研究意义和广泛的应用前景,这些需求对情感分析不断提出更高的要求,推动了情感分析研究 的内涵和外延不断扩展和深入。
问答系统
问答系统(Question Answering,QA)是指系统接受用户以自然语言形式描述的问题,并从异构数据中通过检索、匹配和推理等技术获得答案的自然语言处理系统。根据数据来源的不同,问答系统可以分为4种主要的类型:①检索式问答系统,答案来源于固定的文本语料库或互联网,系统通过查找相关文档并抽取答案完成回答;②知识库问答系统,回答问题所需的知识以数据库等结构化形式存储,问答系统首先将问题解析为结构化的查询语句,通过查询相关知识点,并结合知识推理获取答案;③常问问题集问答系统,通过对历史积累的常问问题集进行检索,回答用户提出的类似问题;④阅读理解式问答系统,通过抽取给定文档中的文本片段或生成一段答案来回答用户提出的问题。在实际应用中,可以综合利用以上多种类型的问答系统来更好地回答用户提出的问题。
机器翻译
机器翻译(Machine Translation, MT)是指利用计算机实现从一种自然语言(源语言)到另外一种自然语言(目标语言)的自动翻译。据统计,目前世界上存在约7,000种语言,其中,超过300种语言拥有100万个以上的使用者。而随着全球化趋势的发展和互联网的广泛普及,不同语言使用者之间的信息交流变得越来越重要。如何突破不同国家和不同民族之间的语言障碍,已成为全人类面临的共同难题。机器翻译为克服这一难题提供了有效的技术手段,其目标是建立自动翻译方法、模型和系统,打破语言壁垒,最终实现任意时间、任意地点和任意语言之间的自动翻译,完成人们无障碍自由交流的梦想。自从自然语言处理领域诞生以来,机器翻译一直是其主要的研究任务和应用场景。近年来,谷歌、百度等公司纷纷推出在线的机器翻译服务,科大讯飞等公司也推出了翻译机产品,能够直接将一种语言的语音翻译为另一种语言的语音,为具有不同语言的人们之间的互相交流提供了便利。
下面给出一个中英互译的例子,其中源语言(中文)和目标语言(英文)都经过了分词处理:
|
|
机器翻译方法一般以句子为基本输入单位,研究从源语言句子到目标语言句子的映射函数。机器翻译自诞生以来,主要围绕理性主义和经验主义两种方法进行研究。所谓“理性主义”,是指基于规则的方法;而“经验主义”是指数据驱动的统计方法,在机器翻译领域表现为基于语料库(翻译实例库)的研究方法。近年来兴起的基于深度学习的机器翻译方法利用深度神经网络学习源语言句子到目标语言句子的隐式翻译规则,即所有的翻译规则都被编码在神经网络的模型参数中。该方法又被称为神经机器翻译(Neural Machine Translation,NMT)。
对话系统
对话系统(Dialogue System)是指以自然语言为载体,用户与计算机通过多轮交互的方式实现特定目标的智能系统。其中,特定目标包括:完成特定任务、获取信息或推荐、获得情感抚慰和社交陪伴等。20世纪50年代,图灵提出用于评
测计算机系统智能化水平的“图灵测试”,就是以自然语言对话的形式进行的。对 话系统可以直接应用于语音助手、智能音箱和车载语音系统等众多场景。
对话系统主要分为任务型对话系统(Task-Oriented Dialogue)和开放域对话系统(Open-Domain Dialogue)。前者是任务导向型的对话系统,主要用于垂直领域的自动业务助理等,具有明确的任务目标,如完成机票预订、天气查询等特定 的任务。后者是以社交为目标的对话系统,通常以闲聊、情感陪护等为目标,因此也被称为聊天系统或聊天机器人(Chatbot),在领域和话题上具有很强的开放性。
下面是一段开放域对话系统人机对话的示例,其中U
代表用户的话语(Utterance),S
代表对话系统的回复。该类对话系统的主要目标是提升对话的轮次以及
用户的满意度。相比对话的准确性,开放域对话系统更关注对话的多样性以及对用户的吸引程度。
|
|
任务型对话系统一般由顺序执行的三个模块构成,即自然语言理解、对话管理和自然语言生成。其中,自然语言理解(Natural Language Understanding, NLU)模块的主要功能是分析用户话语的语义,通常的表示形式为该话语的领域、意图以及相应的槽值等。如对于用户话语:
|
|
自然语言理解的结果如表6所示。
NLU子任务 | 分析结果 |
---|---|
领域 | 机票 |
意图 | 订机票 |
槽值 | 出发时间 \(=\) 明天;到达地 \(=\) 北京;数量 \(=\) 一张 |
表6 自然语言理解的结果
对话管理(Dialogue Management,DM)模块包括对话状态跟踪(Dialogue State Tracking,DST)和对话策略优化(Dialogue Policy Optimization,DPO)**两个子模块。对话状态一般表示为语义槽和值的列表。例如,通过对以上用户话语自然语言理解的结果进行对话状态跟踪,得到当前的对话状态(通常为语义槽及其对应的值构成的列表):[到达地=北京;出发时间=明天;出发地=NULL;数量=1]。获得当前对话状态后,进行策略优化,即选择下一步采用什么样的策略,也叫作动作。动作有很多种,如此时可以询问出发地,也可以询问舱位类型等。
在任务型对话系统里,**自然语言生成(Natural Language Generation,NLG)模块工作相对比较简单,通常通过写模板即可实现。比如要询问出发地,就直接问“请问您从哪里出发?”,然后经过语音合成(Text-to-Speech,TTS)反馈给用户。
以上三个模块可以一直循环执行下去,随着每次用户的话语不同,对话状态也随之变化。然后,采用不同的回复策略,直到满足用户的订票需求为止。
基本问题
上面介绍了两大类常见的自然语言处理任务,虽然这些任务从表面上看各不 相同,但是都可以归为文本分类问题、结构预测问题或序列到序列问题,下面就这三个基本问题分别加以介绍。
文本分类问题
文本分类(Text Classification或Text Categorization)是最简单也是最基础的自然语言处理问题。即针对一段文本输入,输出该文本所属的类别,其中,类别是事先定义好的一个封闭的集合。文本分类具有众多的应用场景,如垃圾邮件过滤(将邮件分为垃圾和非垃圾两类)、新闻分类(将新闻分为政治、经济和体育等类别)等。先前介绍的文本情感分类任务就是典型的文本分类问题,类别既可以是褒、贬两类,也可以是喜、怒、哀和惧等多类。
在使用机器学习,尤其是深度学习方法解决文本分类问题时,首先,需要使
用文本表示技术,将输入的文本转化为特征向量;然后,使用机器学习模型(也叫分类器),将输入的特征向量映射为一个具体的类别。
除了直接使用文本分类技术解决实际问题,还有很多自然语言处理问题可以转换为文本分类问题,如文本匹配(Text Matching),即判断两段输入文本之间的匹配关系,包括复述关系(Paraphrasing:判断两个表述不同的文本语义是否相同)、蕴含关系(Entailment:根据一个前提文本,推断与假设文本之间的蕴含或矛盾关系)等。一种转换的方法是将两段文本直接拼接起来,然后按复述或非复述、蕴含或矛盾等关系分类。
结构预测问题
与文本分类问题不同,在结构预测问题中,输出类别之间具有较强的相互关 联性。例如,在词性标注任务中,一句话中不同词的词性之间往往相互影响,如副词之后往往出现动词或形容词,形容词之后往往跟着名词等。结构预测任务通常是自然语言处理独有的。下面介绍三种典型的结构预测问题——序列标注、序列分割和图结构生成。
序列标注
所谓序列标注(Sequence Labeling),指的是为输入文本序列中的每个词标注相应的标签,如词性标注是为每个词标注一个词性标签,包括名词、动词和形容词等。其中,输入词和输出标签数目相同且一一对应。表7展示了一个序列标注(词性标注)示例。序列标注问题可以简单地看成多个独立的文本分类问题,即针 对每个词提取特征,然后进行标签分类,并不考虑输出标签之间的关系。条件随机场(Conditional Random Field,CRF)模型是一种被广泛应用的序列标注模型,其不但考虑了每个词属于某一标签的概率(发射概率),还考虑了标签之间的相互关系(转移概率)。循环神经网络模型也隐含地建模了标签之间的相互关系,为了进一步提高准确率,也可以在循环神经网络之上再使用条件随机场模型。
输入: | 他 | 喜欢 | 下 | 象棋 | 。 |
---|---|---|---|---|---|
输出: | PN | VV | VV | NN | PU |
表7 序列标注示例
序列分割
除了序列标注问题,还有很多自然语言处理问题可以被建模为序列分割问题,如分词问题,就是将字符序列切分成若干连续的子序列;命名实体识别问题,也是在文本序列中切分出子序列,并为每个子序列赋予一个实体的类别,如人名、地名和机构名等。可以使用专门的序列分割模型对这些问题进行建模,不过为了简化,往往将它们转换为序列标注任务统一加以解决。如命名实体识别,序列标注的输出标签可以为一个实体的开始(B-XXX)、中间(I-XXX)或者非实体(O)等,其中B代表开始(Begin)、I代表中间(Inside)、O代表其他(Other)、XXX代表实体的类型,如人名(PER)、地名(LOC)和机构名(ORG)等。分词问题也可以转换为序列标注问题,即为每个字符标注一个标签,指明该字符是一个词的开始(B)或者中间(I)等。表8展示了使用序列标注方法解决序列分割(分词和命名实体识别)问题示例。其中,对于输入:“我爱北京天安门。”分词输出结果是:“我 爱 北京 天安门 。”,命名实体识别输出结果是:“北京天安门=LOC”。
输入 | 我 | 爱 | 北 | 京 | 天 | 安 | 门 | 。 |
---|---|---|---|---|---|---|---|---|
分词输出 | B | B | B | I | B | I | I | B |
命名实体识别输出 | O | O | B-LOC | I-LOC | I-LOC | I-LOC | I-LOC | O |
表8 使用序列标注方法解决序列分割(分词和命名实体识别)问题示例
图结构生成
图结构生成也是自然语言处理特有的一类结构预测问题,顾名思义,其输入 是自然语言,输出结果是一个以图表示的结构。图中的节点既可以来自原始输入,也可以是新生成的;边连接了两个节点,并可以赋予相应的类型。句法分析就是典型的图结构生成问题,其中,在依存分析中,节点皆为原始输入的词,而边则连接了有句法关系的两个词,然后在其上标注句法关系类别。此外,还 可以对输出的图结构进行一定的约束,如需要为树结构(一种特殊的图结构,要 求每个节点有且只有一个父节点)等。在短语结构句法分析中,除了原始输入词作为终结节点,还需要新生成词性以及短语类型节点作为非终结节点,然后,使 用边将这些节点相连,并最终形成树结构。不过,树结构也不是必要的限制,如在语义依存图分析中,结果就不必是一棵树,而可以是更灵活的图结构。
图结构生成算法主要包括两大类:基于图的算法和基于转移的算法。
基于图(Graph-based)的算法首先为图中任意两个节点(输入的词)构成的边赋予一定的分数,算法的目标是求解出一个满足约束的分数最大的子图,其中,子图的分数可以简单看作所有边的分数和,如果要求输出结果满足树结构的约束,则需要使用最大生成树(Maximum Spanning Tree, MST)算法进行解码。除了解码算法,基于图的算法还需要解决如何为边打分以及参数如何优化等问题。
基于转移(Transition-based)的算法将图结构的构建过程转化为一个状态转移序列,通过转移动作,从一个旧的状态转移到新的状态,也就是说转移动作是
状态向前前进一步的方式,体现了状态变化的策略,转移动作的选择本质上就是一个分类问题,其分类器的特征从当前的状态中加以提取。
首先,来看如何使用基于转移的算法解决依存句法分析问题。在此,以一种非常简单的标准弧(Arc-standard)转移算法为例,转移状态由一个栈(Stack)和一个队列(Queue)构成,栈中存储的是依存结构子树序列 \(S_m \cdots S_1S_0\) ,队列中存储的是未处理的词 \(Q_0Q_1 \cdots Q_n\) 在初始转移状态中,栈为空,句子当中的所有词有序地填入队列中;在结束转移状态中,栈中存储着一棵完整的依存结构句法分析树,队列为空。
另外,算法定义了以下三种转移动作,分别为移进(Shift,SH)、左弧归约(Reduce-Left,RL)和右弧归约(Reduce-Right,RR),具体含义如下:
◦SH,将队列中的第一个元素移入栈顶,形成一个仅包含一个节点的依存子树;
◦RL,将栈顶的两棵依存子树采用一个左弧 \(S_1 \curvearrowleft S_0\) 进行合并,然后 \(S_1\) 下栈;
◦RR,将栈顶的两棵依存子树采用一个右弧 \(S_1 \curvearrowright S_0\) 进行合并,然后 \(S_0\) 下栈。
图4展示了面向依存句法分析的标准弧转移算法中的三种动作。除了以上三个动作,还定义了一个特殊的完成动作(Finish,FIN)。根据上述的定义,可以使用表9中的动作序列逐步生成图2(b)所示的依存结构句法树。弧上的句法关系可以在生成弧的时候(采用RL或RR动作),使用额外的句法关系分类器加以预测。
图4 面向依存句法分析的标准弧转移算法中的三种动作
步骤 | 栈 | 队列 | 下一步动作 |
---|---|---|---|
0 | 他 喜欢 下 象棋 | SH | |
1 |
|
喜欢 下 象棋 | SH |
2 |
|
下 象棋 | RL |
3 |
|
下 象棋 | SH |
4 |
|
象棋 | SH |
5 |
|
RR | |
6 |
|
RR | |
7 |
|
FIN |
表9 基于标准弧转移算法的依存句法树生成动作序列示例
基于转移算法的短语结构句法分析方法过程也类似,只不过栈中存储的是短语结构句法子树序列,队列中同样存储的是未被处理的词。在此不再赘述。
序列到序列问题
除了文本分类和结构预测问题,还有很多自然语言处理问题可以归为序列到序列(Sequence-to-Sequence,Seq2seq)问题。机器翻译问题就是典型的代表,其中,输入为源语言句子,输出为目标语言句子。将其推广到序列到序列问题,输入就是一个由若干词组成的序列,输出则是一个新的序列,其中,输入和输出的序列不要求等长,同时也不要求词表一致。
使用传统的机器学习技术解决序列到序列问题是比较困难的,而基于深度学习模型,可以直接将输入序列表示为一个向量,然后,通过该向量生成输出序列。其中,对输入序列进行表示的过程又叫作编码,相应的模型则被称为编码器(Encoder);生成输出序列的过程又叫作解码,相应的模型则被称为解码器(Decoder)。 因此,序列到序列模型也被称为编码器—解码器(Encoder-Decoder)模型。图5以机器翻译问题为例,展示了一个编码器-解码器模型的示例。
图5 编码器—解码器模型示例
除了机器翻译,还有很多自然语言处理问题可以被建模为序列到序列问题,如对话系统中,用户话语可被视为输入序列,机器的回复则可被视为输出序列,甚至文本分类问题也可以被建模为序列到序列问题。首先,使用编码器对输入文本进行表示,然后,解码器只输出一个“词”,即文本所属的类别。结构预测问题也类似,首先,也需要使用编码器对输入文本进行表示,然后,在处理序列标注问题时,使用解码器生成输出标签序列(需要保证输出序列与输入序列长度相同);在处理序列分割问题时,直接输出结果序列;在处理图结构生成问题时,需要将图表示的结果进行序列化,即通过一定的遍历顺序,将图中的节点和边转换为一个序列,然后再执行解码操作。不过,由于输入和输出有较强的对应关系,而序列到序列模型很难保证这种对应关系,所以结构预测问题较少直接使用序列到序列模型加以解决。但是无论如何,由于序列到序列模型具备强大的建模能力,其已成为自然语言处理的大一统框架,越来越多的问题都可以尝试使用该模型加以解决。也就是说,可以将复杂的自然语言处理问题转化为编码、解码两个子问题,然后就可以分别使用独立的模型建模了。
评价指标
由于自然语言处理任务的多样性以及评价的主观性,因此很难使用单一的评
价指标衡量所有任务的性能,所以针对不同类型的任务,往往采用不同的评价方法。对评价方法的准确把握,有助于深入理解各项自然语言处理任务。
准确率(Accuracy)是最简单、直观的评价指标,经常被应用于文本分类等问题。其计算公式为:
词性标注等序列标注问题也可以采用准确率进行评价,即:
\[ \text{ACC}^{\text{pos}}=\frac{\text{正确标注的词数}}{\text{测试文本中词的总数}} \tag{19} \] 但是,并非全部的序列标注问题都可以采用准确率进行评价,如在将分词、命名实体识别等序列分割问题转化为序列标注问题后,就不应该使用准确率进行评价。以命名实体识别为例,如果采用按词计算的准确率,则很多非命名实体(相应词对应的类别为O
)也被计入准确率的计算之中。另外,如果错标了部分词,那么命名实体识别结果就是错误的,但是按照词准确率计算的话,仍然有部分词被认为分类正确了。如表10中的例子所示,按照词(此处为汉字)计算,在 \(8\) 个输入词中,仅仅预测错了 \(1\) 个(三),则准确率为 \(8/7=0.875\) ,这显然是不合理的。分词等其他序列分割问题的评价也存在类似的问题。
输入 | 张 | 三 | 是 | 哈 | 尔 | 滨 | 人 | 。 |
---|---|---|---|---|---|---|---|---|
正确标注序列 | B-PER | I-PER | O | B-LOC | I-LOC | I-LOC | O | O |
预测标注序列 | B-PER | O | O | B-LOC | I-LOC | I-LOC | O | O |
表10 命名体识别评价示例
那么,如何更合理地评价序列分割问题的性能呢?这就需要引入F值(F-Measure或F-Score)评价指标,其是精确率(Precision)和召回率(Recall)的加权调和平均,具体公式为
\[ \text{F值}=\frac{(\beta^2+1)PR}{\beta^2(P+R)} \tag{20} \]式中, \(\beta\) 是加权调和参数;\(P\) 是精确率, \(R\) 是召回率。当 \(\beta=1\) 时,即精确率和召回率相同,此时F值又称 \(\text{F}_1\) 值,具体公式为
\[ \text{F}_1=\frac{2PR}{P+R} \tag{21} \]在命名实体识别问题中,精确率和召回率的定义分别为:
\[ P=\frac{\text{正确识别的命名实体树木}}{\text{识别出的命名实体总数}} \tag{22} \] \[ R=\frac{\text{正确识别的命名实体数目}}{\text{测试文本中命名实体的总数}} \tag{23} \]
仍以表10中的示例为例,其中,“正确识别的命名实体数目”为 \(1\) (“哈尔滨”),“识别出的命名实体总数”为 \(2\) (“张”和“哈尔滨”),“测试文本中命名实体的总数”为 \(2\) (“张三”和“哈尔滨”),那么此时精确率和召回率皆为 \(1/2 = 0.5\) ,最终的 \(\text{F}_1\) 。与基于词计算的准确率( \(0.875\) )相比,该值更为合理了。
理解了准确率和F值两种评价指标的区别和联系后,就可以很容易地为一个自然语言处理任务选择合适的评价指标。例如,在评价依存句法分析时(分析结果是一棵句法依存树),由于正确的标注结果为每个词都赋予了一个正确的父节点,因此可以使用以词为单位的准确率对依存句法分析结果进行评价,以表明有多大比例的词正确地找到了父节点。不过,评价指标通常不被直接称作准确率,而使用UAS (Unlabeled Attachment Score)指标,即词的父节点被正确识别的准确率。另外,在考虑一个词与父节点的关系时,则使用LAS(Labeled Attachment Score)指标进行评价,即词的父节点以及与父节点的句法关系都被正确识别的准确率。而在对语义依存图任务进行评价时,由于每个词的父节点的个数不确定,则无法使用准确率进行评价,此时就需要使用F值了,即以图中的弧为单位,计算 其识别的精确率和召回率,然后计算F值。与依存句法分析一样,F值也分为考虑语义关系和不考虑语义关系两种情况。类似地,短语结构句法分析也无法使用 准确率进行评价,可以使用句法结构中包含短语(包括短语类型及短语所覆盖的范围)的F值进行评价。
虽然准确率和F值可以用来对标准答案比较明确的任务进行评价,但是很多自然语言处理问题的答案并不明确,或者说并不唯一。如语言模型问题,在给定历史文本预测下一个词时,除了在语料库中出现的词,还有许多其他词也是合理的。因此,不能简单地使用准确率进行评价,所以才引入了困惑度这一评价指标。
对机器翻译系统的评价也类似,测试数据中的参考译文并非唯一正确的答案,目标语言翻译结果只要与源语言语义相同,其表达方式可以非常的灵活。BLEU值是最常用的机器翻译自动评价指标,其计算方法是统计机器译文与参考译文(可以不止一个)中N-gram匹配的数目占机器译文中所有N-gram总数的比率,即N-gram的精确率。其中N的取值不易过大,也不易过小。过大的N会导致机器译文与参考译文中共现的N-gram过少,而过小的N会无法衡量机器译文中词语的顺序信息,所以一般N最大取4。另外,由于此评价方法仅考虑了精确率,而忽视了召回率,所以其倾向于较短的翻译。因此,BLEU值引入了一个长度惩罚因子,鼓励机器译文中单词数目尽量接近参考译文中的数目。最终,BLEU值的区间是0〜1,得分越高表明机器翻译系统的译文质量越好。
对人机对话系统的评价,虽然也可以利用历史上人人对话数据,采用BLEU值等指标,但是由于回复的开放性,这种自动评价的结果很难保证公正、客观。因为与机器翻译类似,人机对话系统的机器回复也没有唯一的标准答案,但比机器翻译评价更困难的是,人机对话系统的回复甚至都没有需要与输入语义相同这一约束,也就是说人机对话系统的答案是开放式的。此外,由于对话的交互性,不能简单地通过一轮人机对话就对系统进行评价。以上这些问题都给人机对话系统的自动评价带来了极大的挑战。因此,在评价一个人机对话系统时,往往采用人工评价的方式,即通过人与系统进行多轮对话后,最终给出一个总的或多个维度(流畅度、相关度和准确性等)的主观分数。由于评分的主观性,人工评价的一致性往往又比较低,也就是说不同人打分可能差异比较大,为了消除这种差异性,又需要多人进行评价并最终取一个平均分数。因此,人工评价的代价往往非常高,很难在系统开发的过程中多次进行。综上,人机对话系统的评价方法仍是目前自然语言处理领域一个非常棘手的开放性问题,并没有很好地被解决。
小结
本篇首先介绍了词的向量表示方法,从传统的独热向量表示、分布式向量表 示到最新的词向量和词袋表示。然后,介绍了传统的N元语言模型,分词、词性标注等自然语言处理基础任务,其中以BPE为代表的子词切分经常被用于现代的预训练语言模型中。接着,简单介绍了信息抽取、情感分析等自然语言处理应用任务。以上任务看似纷繁复杂,但是基本可以归纳为三类问题,即:文本分类、结构预测和序列到序列问题,并可以使用相应的模型加以解决。最后,介绍了如何评价一个自然语言处理任务。
我再也不会给你写信了,因为我终于意识到我们的联络不过是巨大的幻觉。事实上,我们每个人都不过是在给自己写信,我毫无疑问地深深地爱着你,但我又绝望地发现你远离我时,我爱你更深。
― 安德烈·纪德, 《窄门》