深度学习之自然语言处理

运用深度学习向语义层面的理解迈进

Posted by Xiaosheng on June 28, 2017

本文内容摘取自 《Deep Learning》,部分内容有修改。向辛勤翻译本书的 Exacity 团队致敬。

自然语言处理(Natural Language Processing)让计算机能够使用人类语言。为了让简单的程序能够高效明确地解析,计算机程序通常读取和发出特殊化的语言。而自然的语言通常是模糊的,并且可能不遵循形式的描述。自然语言处理中的应用如机器翻译,学习者需要读取一种人类语言的句子,并用另一种人类语言发出等同的句子。许多 NLP 应用程序基于语言模型,语言模型定义了关于自然语言中的字、字符或字节序列的概率分布。

虽然非常通用的神经网络技术可以成功地应用于自然语言处理,但是为了实现卓越的性能并扩展到大型应用程序,一些领域特定的策略也很重要。为了构建自然语言的有效模型,通常必须使用专门处理序列数据的技术。 在很多情况下,我们将自然语言视为一系列词,而不是单个字符或字节序列。因为可能的词总数非常大,基于词的语言模型必须在极高维度和稀疏的离散空间上操作。 为使这种空间上的模型在计算和统计意义上都高效,研究者已经开发了几种策略。

1. 语言模型

n-gram

语言模型(language model)定义了自然语言中标记序列的概率分布。根据模型的设计,标记可以是词、字符、甚至是字节,标记总是离散的实体。最早成功的语言模型基于固定长度序列的标记模型,称为 $\text{n-gram}$。一个 $\text{n-gram}$ 是一个包含 $n$ 个标记的序列。

基于 $\text{n-gram}$ 的模型定义一个条件概率——给定前 $n − 1$ 个标记后的第 $n$ 个标记的条件概率。该模型使用这些条件分布的乘积定义较长序列的概率分布:

这个分解可以由概率的链式法则证明。初始序列 $P(x_1 , . . . , x_{n−1})$ 的概率分布可以通过带有较小 $n$ 值的不同模型建模。

训练 $\text{n-gram}$ 模型是简单的,因为最大似然估计可以通过简单地统计每个可能的 $\text{n-gram}$ 在训练集中出现的次数来获得。几十年来, 基于 $\text{n-gram}$ 的模型都是统计语言模型的核心模块。对于小的 $n$ 值,模型有特定的名称:$n = 1$ 称为一元语法(unigram),$n = 2$ 称为二元语法(bigram)及 $n = 3$ 称为三元语法(trigram)。这些名称源于相应数字的拉丁前缀和希腊后缀 “-gram’’,分别表示所写之物。

通常我们同时训练 $\text{n-gram}$ 模型和 $\text{n − 1 gram}$ 模型,这使得下式可以简单地通过查找两个存储的概率来计算:

为了在 $P_n$ 中精确地再现推断,我们训练 $P_{n−1}$ 时必须省略每个序列最后一个字符。

举个例子,我们演示三元模型如何计算句子$\text{“THE DOG RAN AWAY.”}$的概率。句子的第一个词不能通过上述条件概率的公式计算,因为句子的开头没有上下文,因而必须使用词的边缘概率,因此我们计算 $P_3 (\text{THE DOG RAN})$。 最后,可以使用条件分布 $P(\text{AWAY} \mid \text{DOG RAN})$(典型情况)来预测最后一个词。结合上面的公式可以得到:

$\text{n-gram}$ 模型最大似然的基本限制是,在许多情况下从训练集计数估计得到的 $P_n$ 很可能为零(即使元组 $(x_{t−n+1} , \cdots , x_t )$ 可能出现在测试集中)。这可能会导致两种不同的灾难性后果:当 $P_{n−1}$ 为零时,该比率是未定义的,因此模型甚至不能产生有意义的输出;当 $P_{n−1}$ 非零而 $P_n$ 为零时,测试样本的对数似然为 $−\infty$。为避免这种灾难性的后果,大多数 $\text{n-gram}$ 模型采用某种形式的平滑(smoothing)。 平滑技术将概率质量从观察到的元组转移到类似的未观察到的元组。

平滑的一种基本技术基于向所有可能的下一个符号值添加非零概率质量,这个方法可以被证明是,计数参数具有均匀或 $\text{Dirichlet}$ 先验的贝叶斯推断。另一个非常流行的想法是包含高阶和低阶 $\text{n-gram}$ 模型的混合模型,其中高阶模型提供更多的容量,而低阶模型尽可能地避免零计数。如果上下文 $x_{t−n+k} , \cdots , x_{t−1}$ 的频率太小而不能使用高阶模型,回退方法(back-off methods)就查找低阶 $\text{n-gram}$。更正式地说,它们通过上下文 $x_{t−n+k} , \cdots , x_{t−1}$ 估计 $x_t$ 上的分布,并增加 $k$ 直到找到足够可靠的估计。

经典的 $\text{n-gram}$ 模型特别容易引起维数灾难,因为存在 $|\mathbb{V}|^n$ 可能的 $\text{n-gram}$,而且 $|\mathbb{V}|$ 通常很大。即使有大量训练数据和适当的 $n$,大多数 $\text{n-gram}$ 也不会出现在训练集中。经典 $\text{n-gram}$ 模型的一种观点是执行最近邻查询,换句话说,它可以被视为局部非参数预测器,类似于 $k$-最近邻。语言模型的问题甚至比普通模型更严重,因为任何两个不同的词在 $\text{one-hot}$ 向量空间中的距离彼此相同。因此,难以大量利用来自任意“邻居”的信息——只有重复相同上下文的训练样本对局部泛化有用。为了克服这些问题,语言模型必须能够在一个词和其他语义相似的词之间共享知识。

为了提高 $\text{n-gram}$ 模型的统计效率,基于类的语言模型(class-based language model)引入词类别的概念,属于同一类别的词共享词之间的统计强度。这个想法使用了聚类算法,基于它们与其他词同时出现的频率,将该组词分成集群或类。随后,模型可以在条件竖杠的右侧使用词类 $\text{ID}$ 而不是单个词 $\text{ID}$。混合(或回退)词模型和类模型的复合模型也是可能的。尽管词类提供了在序列之间泛化的方式,但其中一些词被相同类的另一个替换,导致该表示丢失了很多信息。

神经语言模型

神经语言模型(Neural Language Model, NLM)是一类用来克服维数灾难的语言模型,它使用词的分布式表示对自然语言序列建模。不同于基于类的 $\text{n-gram}$ 模型,神经语言模型在能够识别两个相似的词,并且不丧失将每个 词编码为彼此不同的能力。神经语言模型共享一个词(及其上下文)和其他类似词(和上下文之间)的统计强度。模型为每个词学习的分布式表示,允许模型处理具有类似共同特征的词来实现这种共享。

例如,如果相似的词 $\text{dog}$ 和词 $\text{cat}$ 映射到具有许多属性的表示,则包含词 $\text{cat}$ 的句子可以告知模型对包含词 $\text{dog}$ 的句子做出预测,反之亦然。因为这样的属性很多,所以存在许多泛化的方式,可以将信息从每个训练语句传递到指数数量的语义相关语句。维数灾难需要模型泛化到指数多的句子(指数相对句子长度而言),该模型通过将每个训练句子与指数数量的类似句子相关联克服这个问题。

我们有时将这些词表示称为词嵌入(word embedding)。在这个解释下,我们将原始符号视为维度等于词表大小的空间中的点。词表示将这些点嵌入到较低维的特征空间中。在原始空间中,每个词由一个 $\text{one-hot}$ 向量表示,因此每对词彼此之间的欧氏距离都是 $\sqrt{2}$。在嵌入空间中,经常出现在类似上下文(或共享由模型学习的一些“特征”的任何词对)中的词彼此接近。这通常导致具有相似含义的词变得邻近。 下图放大了学到的词嵌入空间的特定区域,我们可以看到语义上相似的词如何映射到彼此接近的表示。

1

上图为从神经机器翻译模型获得的词嵌入的二维可视化。此图在语义相关词的特定区域放大,它们具有彼此接近的嵌入向量。国家在左图,数字在右图。注意,这些嵌入是为了可视化才表示为 $2$ 维。在实际应用中,嵌入通常具有更高的维度并且可以同时捕获词之间多种相似性。

其他领域的神经网络也可以定义嵌入。例如,卷积网络的隐藏层提供“图像嵌入”。因为自然语言最初不在实值向量空间上,所以 $\text{NLP}$ 从业者通常对嵌入的这个想法更感兴趣。隐藏层在表示数据的方式上提供了更质变的戏剧性变化。

使用分布式表示来改进自然语言处理模型的基本思想不必局限于神经网络。它还可以用于图模型,其中分布式表示是多个潜变量的形式。

2. 高维输出

在许多自然语言应用中,我们通常希望我们的模型产生词(而不是字符)作为输出的基本单位。对于大词汇表,由于词汇量很大,在词的选择上输出分布表示的计算成本可能非常高。在许多应用中,$\mathbb{V}$ 包含数十万词。表示这种分布的朴素方法是应用一个仿射变换,将隐藏表示转换到输出空间,然后应用 $\text{softmax}$ 函数。假设我们的词汇表 $\mathbb{V}$ 大小为 $|\mathbb{V}|$。因为其输出维数为 $|\mathbb{V}|$,描述该仿射变换线性分量的权重矩阵非常大。这造成了表示该矩阵的高存储成本,以及与之相乘的高计算成本。因为 $\text{softmax}$ 要在所有 $|\mathbb{V}|$ 输出之间归一化,所以在训练时以及测试时执行全矩阵乘法是必要的——我们不能仅计算与正确输出的权重向量的点积。因此,输出层的高计算成本在训练期间(计算似然性及其梯度)和测试期间(计算所有或所选词的概率)都有出现。对于专门的损失函数,可以有效地计算梯度, 但是应用于传统 $\text{softmax}$ 输出层的标准交叉熵损失时会出现许多困难。

假设 $\boldsymbol{h}$ 是用于预测输出概率 $\hat{\boldsymbol{y}}$ 的顶部隐藏层。如果我们使用学到的权重 $\boldsymbol{W}$ 和学到的偏置 $\boldsymbol{b}$ 参数化从 $\boldsymbol{h}$ 到 $\hat{\boldsymbol{y}}$ 的变换,则仿射 $\text{softmax}$ 输出层执行以下计算:

如果 $\boldsymbol{h}$ 包含 $n_h$ 个元素,则上述操作复杂度是 $O(|\mathbb{V}|n_h )$。在 $n_h$ 为数千和 $|\mathbb{V}|$ 数十万的情况下,这个操作占据了神经语言模型的大多数计算。

使用短列表

第一个神经语言模型通过将词汇量限制为 $10,000$ 或 $20,000$ 来减轻大词汇表上 $\text{softmax}$ 的高成本。后来有人在这种方法的基础上建立新的方式,将词汇表 $\mathbb{V}$ 分为最常见词汇(由神经网络处理)的短列表(shortlist) $\mathbb{L}$ 和较稀有词汇的尾列表 $\mathbb{T} = \mathbb{V} \backslash \mathbb{L}$(由 $\text{n-gram}$ 模型处理)。为了组合这两个预测,神经网络还必须预测在上下文 $C$ 之后出现的词位于尾列表的概率。我们可以添加额外的 $\text{sigmoid}$ 输出单元估计 $P(i \in \mathbb{T} \mid C)$ 实现这个预测。额外输出则可以用来估计 $\mathbb{V}$ 中所有词的概率分布,如下:

其中 $P(y = i \mid C, i \in \mathbb{L})$ 由神经语言模型提供 $P(y = i \mid C, i \in \mathbb{T})$ 由 $\text{n-gram}$ 模型提供。稍作修改,这种方法也可以在神经语言模型模型的 $\text{softmax}$ 层中使用额外的输出值,而不是单独的 $\text{sigmoid}$ 单元。

短列表方法的一个明显缺点是,神经语言模型的潜在泛化优势仅限于最常用的词,这大概是最没用的。这个缺点引发了处理高维输出替代方法的探索,如下所述。

分层 Softmax

减少大词汇表 $\mathbb{V}$ 上高维输出层计算负担的经典方法是分层地分解概率。$|\mathbb{V}|$ 因子可以降低到 $\log |\mathbb{V}|$ 一样低,而无需执行与 $|\mathbb{V}|$ 成比例数量(并且也与隐藏单元数量 $n_h$ 成比例)的计算。

我们可以认为这种层次结构是先建立词的类别,然后是词类别的类别,然后是词类别的类别的类别等等。这些嵌套类别构成一棵树, 其叶子为词。在平衡树中, 树的深度为 $\log |\mathbb{V}|$。选择一个词的概率是由路径(从树根到包含该词叶子的路径)上的每个节点通向该词分支概率的乘积给出。下图给出了一个简单的例子:

2

上面是词类别简单层次结构的示意图,其中 $8$ 个词 $w_0 , \cdots , w_7$ 组织成三级层次结构,树的叶子表示实际特定的词,内部节点表示词的组别。任何节点都可以通过二值决策序列($0=$ 左,$1=$ 右)索引,从根到达节点。超类 $(0)$ 包含类 $(0, 0)$ 和 $(0, 1)$,其中分别包含词 ${w_0 , w_1}$ 和 ${w_2 , w_3}$ 的集合,超类 $(1)$ 类似。如果树充分平衡,则最大深度(二值决策的数量)与词数 $|\mathbb{V}|$ 的对数同阶:从 $|\mathbb{V}|$ 个词中选一个词只需执行 $O(\log|\mathbb{V}|)$ 次操作(从根开始的路径上的每个节点一次操作)。在该示例中,我们乘三次概率就能计算词 $y$ 的概率,这三次概率与从根到节点 $y$ 的路径上每个节点向左或向右的二值决策相关联。令 $b_i (y)$ 为遍历树移向 $y$ 时的第 $i$ 个二值决策。对输出 $\text{y}$ 进行采样的概率可以通过条件概率的链式法则分解为条件概率的乘积,其中每个节点由这些位的前缀索引。例如,节点 $(1, 0)$ 对应于前缀 $(b_0 (w_4 ) = 1, b_1 (w_4 ) = 0)$,并且 $w_4$ 的概率可以如下分解:

为了预测树的每个节点所需的条件概率,我们通常在树的每个节点处使用逻辑回归模型,并且为所有这些模型提供与输入相同的上下文 $C$。因为正确的输出编码在训练集中,我们可以使用监督学习训练逻辑回归模型。我们通常使用标准交叉熵损失,对应于最大化正确判断序列的对数似然。

因为可以高效地计算输出对数似然(低至 $\log|\mathbb{V}|$ 而不是 $|\mathbb{V}|$),所以也可以高效地计算梯度。这不仅包括关于输出参数的梯度,而且还包括关于隐藏层激活的梯度。

优化树结构最小化期望的计算数量是可能的,但通常不切实际。给定词的相对频率,信息理论的工具可以指定如何选择最佳的二进制编码。为此,我们可以构造树,使得与词相关联的位数量近似等于该词频率的对数。然而在实践中,节省计算通常事倍功半,因为输出概率的计算仅是神经语言模型中总计算的一部分。

一个仍然有点开放的问题是如何最好地定义这些词类,或者如何定义一般的词层次结构。早期工作使用现有的层次结构,但也可以理想地与神经语言模型联合学习层次结构。学习层次结构很困难。对数似然的精确优化似乎难以解决,因为词层次的选择是离散的,不适于基于梯度的优化。然而,我们可以使用离散优化来近似地最优化词类的分割。

分层 $\text{softmax}$ 的一个重要优点是,它在训练期间和测试期间(如果在测试时我们想计算特定词的概率)都带来了计算上的好处。当然即使使用分层 $\text{softmax}$,计算所有 $|\mathbb{V}|$ 个词概率的成本仍是很高的。另一个重要的操作是在给定上下文中选择最可能的词。不幸的是,树结构不能为这个问题提供高效精确的解决方案。分层 $\text{softmax}$ 的缺点是,在实践中更倾向于更差的测试结果(相对基于采样的方法),这可能是因为词类选择得不好。

3. 神经机器翻译

机器翻译以一种自然语言读取句子并产生等同含义的另一种语言的句子。机器翻译系统通常涉及许多组件。在高层次,一个组件通常会提出许多候选翻译。由于语言之间的差异,这些翻译中的许多翻译是不符合语法的。例如,许多语言在名词后放置形容词,因此直接翻译成英语时,它们会产生诸如“apple red”的短语。提议机制提出建议翻译的许多变体,理想情况下应包括“red apple”。翻译系统的第二个组成部分(语言模型)评估提议的翻译,并可以评估“red apple”比“apple red”更好。

最早的机器翻译神经网络探索中已经纳入了编码器和解码器的想法,而翻译中神经网络的第一个大规模有竞争力的用途是通过神经语言模型升级翻译系统的语言模型。之前,大多数机器翻译系统在该组件使用 $\text{n-gram}$ 模型。机器翻译中基于 $\text{n-gram}$ 的模型不仅包括传统的回退 $\text{n-gram}$ 模型,而且包括最大熵语言模型(maximum entropy language models),其中给定上下文中常见的词,$\text{affine-softmax}$ 层预测下一个词。

传统语言模型仅仅报告自然语言句子的概率。因为机器翻译涉及给定输入句子产生输出句子,所以将自然语言模型扩展为条件的是有意义的。可以使用最大似然学习条件分布,直接地扩展一个模型,该模型定义某些变量的边缘分布,以便在给定上下文 $C$($C$ 可以是单个变量或变量列表)的情况下定义该变量的条件分布。Devlin 在一些统计机器翻译的基准中击败了最先进的技术,他给定源语言中的短语 $s_1 , s_2 , . . . , s_k$ 后使用 $\text{MLP}$ 对目标语言的短语 $t_1 , t_2 , . . . , t_k$ 进行评分。这个 $\text{MLP}$ 估计 $P(t_1 , t_2 , . . . , t_k \mid s_1 , s_2 , . . . , s_k )$。这个 $\text{MLP}$ 的估计替代了条件 $\text{n-gram}$ 模型提供的估计。

基于 $\text{MLP}$ 方法的缺点是需要将序列预处理为固定长度。为了使翻译更加灵活,我们希望模型允许可变的输入长度和输出长度,而 $\text{RNN}$ 具备这种能力。在所有情况下,一个模型首先读取输入序列并产生概括输入序列的数据结构,我们称这个概括为“上下文” $C$。上下文 $C$ 可以是向量列表,或者向量或张量。读取输入以产生 $C$ 的模型可以是 $\text{RNN}$ 或卷积网络。另一个模型(通常是 $\text{RNN}$),则读取上下文 $C$ 并且生成目标语言的句子。下图中展示了这种用于机器翻译的编码器-解码器框架的总体思想:

3

编码器-解码器架构在直观表示(例如词序列或图像)和语义表示之间来回映射。使用来自一种模态数据的编码器输出(例如从法语句子到捕获句子含义的隐藏表示的编码器映射)作为用于另一模态的解码器输入(如解码器将捕获句子含义的隐藏表示映射到英语),我们可以训练将一种模态转换到另一种模态的系统。这个想法已经成功应用于很多领域,不仅仅是机器翻译,还包括为图像生成标题。

使用注意力机制并对齐数据片段

使用固定大小的表示概括非常长的句子(例如 $60$ 个词)的所有语义细节是非常困难的。这需要使用足够大的 $\text{RNN}$,并且用足够长时间训练得很好才能实现。然而,更高效的方法是先读取整个句子或段落(以获得正在表达的上下文和焦点),然后一次翻译一个词,每次聚焦于输入句子的不同部分来收集产生下一个输出词所需的语义细节。下图展示了注意力机制,其中每个时间步关注输入序列的特定部分:

4

上图展示了现代注意力机制,本质上是加权平均。注意力机制对具有权重 $\alpha^{(t)}$ 的特征向量 $\boldsymbol{h}^{(t)}$ 进行加权平均形成上下文向量 $\boldsymbol{c}$。在一些应用中,特征向量 $\boldsymbol{h}$ 是神经网络的隐藏单元,但它们也可以是模型的原始输入。权重 $\alpha^{(t)}$ 由模型本身产生,它们通常是区间 $[0, 1]$ 中的值,并且旨在仅仅集中在单个 $\boldsymbol{h}^{(t)}$ 周围,使得加权平均精确地读取接近一个特定时间步的特征向量。权重 $\alpha^{(t)}$ 通常由模型另一部分发出的相关性得分应用 $\text{softmax}$ 函数后产生。注意 力机制在计算上需要比直接索引期望的 $\boldsymbol{h}^{(t)}$ 付出更高的代价,但直接索引不能使用梯度下降训练。 基于加权平均的注意力机制是平滑、可微的近似,可以使用现有优化算法训练。

我们可以认为基于注意力机制的系统有三个组件:

  • 读取器读取原始数据(例如源语句中的源词)并将其转换为分布式表示,其中一个特征向量与每个词的位置相关联。
  • 存储器存储读取器输出的特征向量列表。这可以被理解为包含事实序列的存储器,而之后不必以相同的顺序从中检索,也不必访问全部。
  • 最后一个程序利用存储器的内容顺序地执行任务,每个时间步聚焦于某个存储器元素的内容(或几个,具有不同权重)。

第三组件可以生成翻译语句。

当用一种语言书写的句子中的词与另一种语言的翻译语句中的相应词对齐时,可以使对应的词嵌入相关联。早期的工作表明, 我们可以学习将一种语言中的词嵌入与另一种语言中的词嵌入相关联的翻译矩阵,与传统的基于短语表中频率计数的方法相比,可以产生较低的对齐错误率。更早的工作也对跨语言词向量进行了研究。这种方法的存在很多扩展。 例如,允许在更大数据集上训练的更高效的跨语言对齐。

本文内容摘取自 《Deep Learning》,部分内容有修改。向辛勤翻译本书的 Exacity 团队致敬。