技术编程|词向量因何存在:一段往计算机输入文字的历史


_本文原题:词向量因何存在:一段往计算机输入文字的历史
本文转载自:AI科技评论
往计算机输入文字 , 是整个自然语言处理(NLP)领域的宏大故事的一部分 , 而 NLP 则是人工智能的重要分支研究领域 。
NLP中 , 最细粒度的部分就是词语 , 词语组成句子 , 句子再组成段落、篇章、文档 。 而语言作为人类独有的表达方式 , 如果要输入到计算机中 , 则要将语言中的一个个词语转换成数值形式 , 这就需要用到词向量 , 或者说词嵌入的方法 。
因而 , 要想研究好NLP, 势必要对词向量有透彻的理解 。
读罢此文 , 你将对词向量有一个一般性的认识:它们为何而存在 , 它们解决了什么问题 , 它们源自何处 , 它们随着时间如何变化?以及 , 目前关于词向量有哪些有待解决的问题?
本文的关键论点包括:
即使是在最基本的单词层面上 , 在可计算的条件下表征自然语言文本仍然是个难题 。
不同单词的意义或多或少有其相似之处 。 人们使用连续的向量有效地获取这种性质 , 大规模的文本语料让我们可以自动地发掘许多层面上的词义相似性 。 通常 , 预料词典中的每个单词都有一个但以固定的表征向量 。
单词的意义可以随着其出现的上下文不同而发生很大的变化 。 最新的研究进展使用 NLP 和机器学习(ML)领域的常用工具识别并学习了这种变化 。 这些方法在诸多对比基准上展示出了巨大的性能提升 。
1
早期方法:离散化表征
在计算机中 , 表征一段文本的最简单的形式是一个字符序列(根据编码的不同 , 存储一个字符可能需要一个字节或多个字节) 。 一个词形可以被表征为一个字符串(字符的有序列表) , 但是比较两个字符串是否相同的计算成本却很高 。
在之前 , 单词往往都会被整数化处理 。 这样一来 , 每个词形都会被赋予一个唯一的(或多或少任意的)非负整数值 。 这样做的优点是每个词形都以相同大小的空间被存储下来 , 基于数组的数据结构可以被用来通过词形索引其它的信息(如单词的字符串 , 对属于该词形的词例进行技术 , 或者包含单词潜在语义的细节信息的更丰富的数据结构) 。 当遇到新的词形时 , 词汇表就会被不断地扩展(直到单词数达到整型数据类型的上限 , 对于 4 字节无符号整数来说 , 这一上限超过了 40 亿) 。 当然 , 我们可以很快地测试两个整数是否相同 。
整数本身并不具有任何意义 。 为整数分配意义的过程可以是随机的 , 也可以是按照字母顺序进行的 , 或者是或根据词例在生成单词表的参考文本语料中出现的顺序进行(也就是说 , 第一个出现的词例的词形被赋予整数 0;如果第二个出现的词例与第一个不同 , 则将整数 1 赋予它对应的词形) 。 具有相关语义的两个词形将会被赋予具有一定「距离」的整数 , 两个在分配的空间中「相近」的词形彼此之间可能没有任何关系 。
使用整数只是遵循当下流行的编程语言中可用的数据类型的一种方便的表示方法 。 例如 , 在 Lisp 语言中 ,「gensym」也能达到同样的目的(尽管效率可能低一些) 。 因此 , 我们将基于整数的词形表征称为「离散化表征」 。
考虑到 NLP 程序大多都是使用监督式机器学习构建的 , 我们认为「单词或多或少存在相似性」的思路是十分重要的 。
2
究竟该如何在计算机中使用 文字 ?
为了解释 NLP 从业者为什么不再通过离散化表征的方法处理词形 , 很有必要解释下单词是如何在 NLP 程序中被使用的 。 下面是一些示例:
观测给定文档中的一个词例 , 以此为证据(evidence)预测文档的类别 。 例如 , 在一段电影影评中出现的「delightful」单词 , 说明影评人可能很喜欢这部电影 , 并给予它一个正面评价 。
观测给定文档中的一个词例 , 以此为证据在句子翻译中预测一个词例 。 例如 , 在英语句子中出现单词「cucumber」说明在法语翻译中可能出现单词「concombre」 。
相反 , 给定证据的全部权重 , 在给定的上下文中 , 选择一个词形并输出一个它的词例 。
在以上各种情况下 , 对词形进行离散化处理有一个严重的缺点:有关如何将一个特定的词用作证据 , 或者是否生成一个输出词例的信息 , 不能在具有相似特性的单词之间共享 。 举个简单的例子 , 请考虑填补下面句子中的空缺:
S.will eat anything, but V. hates _
根据你对世界的先验知识 , 你可能会倾向于很有把握地填上词形为「豌豆」(pears)、「豆芽菜」(sprouts)、「鸡肉」(chicken)的词例 , 或其它代表食物的复数名词 。 这样的词形共有一些性质(和其它表示食物的单词一起) , 我们希望使用这些单词的模型能够用到这样的信息 。 两个不同的单词可能或多或少具有一些相似性 。
考虑到 NLP 程序大多都是使用监督式机器学习构建的 , 我们认为「单词或多或少具有一些相似性」的思路是十分重要的 。 在这里 , 监督式机器学习指的是我们拥有代表一个任务的输入和输出的示例(二者中至少有一个是由单词组成的) , 并且有一套根据这些「输入-输出」对泛化的机制 。 理想状况下 , 这样的机制应该能够利用相似性:它发现的关于某个单词的性质可以迁移到相似的单词上 。
在本文中 , 探讨两种将相似性信息引入程序的方法(理性主义和经验主义) 。
理性主义告诉我们 , 人类(尤其是受过人类语言科学方面训练的人)会知道这些相似性信息 , 我们可以设计数据结构显式地对其进行编码 , 让我们的程序在需要时访问这些信息 。 一个代表性的工作是 WordNet , 它使用 13 个词法数据库存储单词及其之间的关系(例如 , 同义:两个单词意味着同样的事情;上下位关系:一个词的意思是另一个词更加具象化的表现) 。 WordNet 也显式地捕获了一词多义的现象(例如 , 风扇:吹动空气的机器 , 有时也指「粉丝」) 。 句子结构(句法)的语言学理论提供了另一种方法来思考名词、动词这种形式的词的相似性 。
经验主义告诉我们 , 针对 NLP 应用 , 我们可以使用一组独立的程序收集并组织信息 。 随着网络上的文本数据越来越多 , 这种方式逐渐占据了主导地位 。 被用于从语料库中提取信息的程序已经经历了几个阶段的发展(从基于技术的统计 , 到使用更先进的统计方法建模 , 再到越来越强大的机器学习工具) 。
基于以上两种思路 , 我们都会想到通过向量而不是整数来表示词形 。 此时 , 我们需要确定向量的维度 , 并赋予不同的维度不同的目的 。 例如:
为每个词形赋予一个维度 , 该维度上赋值为 1(而其它所有的词形对应的维度上的值为 0) 。 这种方式本质上相当于对单词进行整数化处理 , 单词被表征为一个独热(one-hot)编码 。
对于属于已知类型的词形(例如 , 一周的七天) , 我们可以使用给定了二进制值的维度 。
对于具有相同词根的变体词形 , 我们同样可以使用一个维度将其归于同一类 。 例如 , 「know」、「known」、「knew」、「knows」的某一个维度上都被赋值为 1 , 而其它与 know 词根不同的单词则在该维度上被赋值为 0 。
更宽泛地说 , 我们可以使用表面的属性将看起来相似的词形绑定在一起:例如大小写的模式 , 长度 , 出现某个数字 。
如果词形的存在表示大小关系的意义 , 我们可能会分配一些维度来捕获这样的大小信息 。
在 NLP 领域中 , 有很多通过赋予向量某些维度 , 从而表征词形(或多单词序列)的例子 。 这些维度被称为「特征」 , 它们可以由专家设计 , 也可以通过自动化的算法得到 。
3
将词表征为分布式的向量
在语言学中 , 一个重要的思想是:可以通过相似的方式使用的单词(或表达)趋向于拥有相关的语义 。 在一个大型语料库中 , 我们可以收集有关词形「w」被使用的方式的信息(例如 , 统计它子其它词形附近出现的次数) 。 当我们研究语料库中存在 w 的上下文(附近的单词或句子)的完整分布时 , 我们采取了一种词义的分布式视角 。
「聚类」就是基于这种思想生成特征的一种成功的方法 。 例如 , Brown 等人提出的聚类算法根据语料库中出现的上下文自动地将单词组织成一些聚类簇 。 倾向于出现在相同的邻居上下文的单词会被划分到同一个簇中 。 如图 1 所示这种方法具有惊人的可解释性和实用性 , 我们还可以使用任意给定的语料库重新构建它 , 包含所有观测到的单词 。

技术编程|词向量因何存在:一段往计算机输入文字的历史
本文插图

图 1:Brown 聚类示意图 。 该结果是根据 56M 条 tweet 生成的 , 本图中给出了以 00110 二进制串为前缀的簇的层次结构 , 以及簇中 10 个出现频率最高的单词 。 树中的中间节点对应于包含后继节点中所有单词的簇 。
另一类方法在一开始需要创建单词向量 , 其中每个维度对应于词性在某些上下文中出现的频率 。 例如 , 一个维度可能对应于「the」 , 并且包含在一个词例「the」附近的一个小的窗口中某单词出现的次数 。 该向量可能包括单词左侧、右侧 , 以及不同距离和长度的上下文模式 。 这样创建的单词向量可能比词汇表的还要行很多倍 。 我们可以利用线性代数的降维方法 , 将这些向量压缩地更短 , 从而减少维度之间的冗余 。

技术编程|词向量因何存在:一段往计算机输入文字的历史
本文插图

图 2:计算单词向量的方法示意图 。
降维之后的向量的优点有:首先 , NLP 程序员可以根据程序的需要选择合适的维度 。 更紧凑的向量计算效率更高 , 也可能由于特定语料库的噪声在压缩过程中消失而受益 。 然而 , 压缩的代价则是牺牲了一部分原始信息 。 由于压缩后的向量中单独的维度是很难被解释的 , 我们可以使用一些常见的算法找到单词在向量空间中的最近邻 , 它们往往是具有相关语义的单词 。
实际上 , 这些观测结果催生了「向量空间语义」的思想 , 我们可以对单词向量进行算术运算 , 从而理解学习到的单词「意义」 。 一个著名的例子是:
降维后的向量的缺点在于:独立的维度并不是可解释的特征 , 不能够直接被映射回构建单词意义的模块 。 单词的意义是分布在整个向量上的;因此 , 这些向量有时被称为分布的表征 。
随着语料库规模不短增长 , 可伸缩性成为了一个重大的挑战 。 所有词向量算法底层的思想是:词形向量的每个维度上的值是一个有待优化的参数 。 我们通过优化这些参数 , 最佳地拟合观测到的数据中的单词模式 。 由于我们将这些参数视为连续的值 , 而且拟合数据的概念可以作为光滑、连续的目标函数来操作 , 因此可以通过基于梯度下降的迭代式算法完成优化 。
研究人员对获取分布式词向量的方法进行了大量的探索 。 接下来 , 我们将列举出一些有趣的想法:
如图 3 所示 , 我们首先将每个输入的词例映射到其向量上 , 然后将词向量输入到神经网络模型中 , 该神经网络执行类似于翻译的任务 。 向量可以预先给定(或使用上述方法根据一个语料库预训练得到) , 也可以作为神经网络模型的参数 , 根据特定任务进行调整 。 「调优」(fine-tuning)是指通过预训练初始化向量 , 然后通过特定任务的学习算法来调整他们 。 我们也可以随机初始化词向量 , 从头开始学习 。
【技术编程|词向量因何存在:一段往计算机输入文字的历史】图 3:一个简单的神经网络示意图 。 神经网络是一种将向量映射到向量的函数 。 例如 , 将二维输入映射到二维输出上的函数:
我们可以使用 WordNet 这种专家构建的数据结构作为额外的输入来创建词向量 。 「retrofitting」方法首先从语料库中提取出词向量 , 然后试图自动地对其进行调整 , 使得在 WordNet 中那个相关的词形在向量空间中更接近 。
我们可以使用双语词典 , 将两种语言状态下的词向量「对齐」到同一个向量空间中 。 这样一来 , 例如英语词形「cucumber」和法语词形「concombre」的向量之间的欧氏距离就很小了 。
根据部分(或全部的)字符序列计算词向量 。 这种方法倾向于使用神经网络将任意长度的序列映射为固定长度的向量 。 这样做有两个有趣的作用:在具有复杂单词构造系统的语言中 , 具有相同底层词根的变体会拥有相似的词向量;同一单词的不同拼写方式将有详细的词向量 。
4
上下文相关词向量
首先 , 我们要区分词例和词形 。 一直以来 , 在我们的 NLP 程序中 , 我们都假设每个词形都会使用一个固定的数据对象(一开始是整数 , 后来又发明了词向量)来表征 。 这样做是很方便 , 但是它又对语言做出了一些不符合现实情况的假设 。 最重要的一点是 , 单词在不同的上下文中应该有不同的意思 。
在粗粒度的级别上 , 专家们在构建 WordNet 时捕获了这种特性 。 例如 , 在 WordNet 中「get」被映射到了 30 多种不同的含义上 。 然而 , 应该给各个单词分配多少种词义(或者确定词义之间的边界)一直都是一个难以取得共识的问题 。 词义也有可能是随语境动态变化的 。
事实上 , 在很多基于神经网络的 NLP 程序中 , 首先要做的就是将每个单词词例所属的词形向量输入到一个函数中 , 然后基于该词例附近的上下文对这个向量进行变换 。 变换过程如图 4、图 5 所示 。

技术编程|词向量因何存在:一段往计算机输入文字的历史
本文插图

图 4:图 2 中计算的 3-单词向量之间的关系大致的可视化结果 。

技术编程|词向量因何存在:一段往计算机输入文字的历史
本文插图

图 5:图 2 和图 4 中的词例「astronomers」、「bodies」、「objects」的上下文相关词向量的假想的可视化结果 。
根据相似性的基本概念 , 我们期望相似的单词彼此之间能够很好地相互替换 。 有时仅仅根据词形是很难确定相似性的 , 而当我们考虑上下文语境时 , 这个问题就会简单很多 。
在大型语料库上预训练得到的 ELMo(基于语言模型的嵌入) , 以词例向量(针对上下文中的单词的向量 , 上下文相关向量)的形式带来了巨大的进步 。 EMLo 背后有两个主要的思想:
如果每个词例都有自己的向量 , 那么这个向量应该依赖于附近单词组成的任意长度的上下文 。 为了获得「上下文向量」 , 我们首先得到词形向量 , 然后将它们传递给一个神经网络 , 该神经网络可以将任意长度的左右上下文词向量序列转换为一个固定长度的向量 。 词形向量本质上是查找表 , 与之不同的是 , 上下文相关词向量是由代表单词类型的向量和将每个单词置于上下文中的神经网络参数构建的 。 ELMo 训练一个神经网络处理左侧的上下文(往回观测到出现某词例的句子的开头) , 另一个神经网络处理右侧的上下文(直到句子的结尾) 。 原则上说 , ELMo 也可能处理更长的上下文 。
回想一下 , 估计单词向量需要通过求解优化问题来拟合数据(在这里是语料库) 。 语言建模是 NLP 领域中一个长期存在的数据拟合问题 , 它指的是根据历史单词序列预测接下来的单词 。 已经被人们所使用的许多词形向量算法都是基于固定大小的上下文工作的 , 这些上下文是从语料库中词形的所有实例中收集的 。 ELMo 涉及的语料范围更广 , 它使用任意长度的历史单词序列 , 并直接引入了对应情况下最有效的语言模型(基于循环神经网络) 。 尽管循环神经网络已经在 NLP 领域中被广泛使用 , 但是将它们训练为语言模型 , 然后使用它们为每个词例提供的上下文向量作为与训练的词例向量还是很新颖的 。
这样的研究进展为什么令人振奋呢?上下文相关的词向量是否能完全解决歧义词带来的挑战仍然有待研究 。 人们往往会在对比基准测试中使用客观的性能评价指标测试 NLP 领域新的思路 。 研究人员发现 , ELMo 在以下领域中极大提升了 NLP 程序的性能:
给定一段文字 , 回答有关其中内容的问题(在 SQuAD 对比基准上将误差降低了 9%) 。
标注动词的语义论元(在 Ontonotes 语义角色标注对比基准上将误差降低了 16%) 。
解析那些指称表达指代的是相同的实体(在 CoNLL 2003 对比基准上将误差降低了 4%) 。
在语言学中 , 一个重要的思想是:可以通过相似的方式使用的单词(或表示)可能拥有相同的语义 。
Howard 和 Ruder 介绍了一种简单的方法「ULMFiT」 , 显示了上下文相关向量在文本分类问题上的优势 。 接着 , 基于 Transformer 的双向编码器表征在学习方法上引入了一些创新之处 , 并利用更多的数据进行学习 , 在第一个任务中相较于 ELMo 进一步降低了 45% 的误差 , 在第二个任务中降低了 7% 的误差 。
在 SWAG 对比基准测试中 , Devlin 等人近期在常识推理任务中发现 ELMo 相对于上下文无关词向量降低了 5% 的误差 , 而 BERT 则相对于 EMLo 又降低了 66% 。 自此之后 , 一系列论文纷纷涌现了出来 , 如 GPT-2、RoBERTa、T5、XLM、XLNet 。
在作者撰写本文时 , 有许多关于不同方法的相对性能的开放性问题 。 对于不同的学习算法 , 特别是神经网络架构的完整解释超出了本文介绍的范围 , 但是公平地说 , 上下文相关词向量的可能学习器还没有被充分探索 。
5
不足之处
词向量是有偏的 。 和许多工程产品一样 , 计算机程序很可能反映出其制造者的观点 。 根据数据构建的计算机程序将反映出数据(在本例中是语料库)中的内容 。 如果文本语料库表示了反应文化偏见的概念之间的联系 , 那么这些联系会在词向量和使用它们的任何系统中存在 。
语言不仅仅是单词 。 语言的有效理解和生成不仅仅局限于理解词义 , 这还需要知道单词如何被组合起来形成更加复杂的概念和命题 。 这只是 NLP 领域研究的冰山一角 , 关于处理自然语言语法、语义和语用的方法 , 以及我们如何将人类理解和生成语言的任务转化为我们可以试着去设计算法的任务 , 还有很多有待研究的问题 。 关于上下文相关词向量 , 一个令人惊讶的发现是:当我们使用非常大的语料库进行训练时 , 它们更容易通过各种句法和语义解析来进行排歧 。
研究 NLP 问题不应该只局限于某一点来看 。 虽然上述成果令人印象深刻 , 但是请记住 , 它们仅仅反映了在研究社区中出现的少数对比基准上的表现 。 这些对比基准在某种程度上是有争议的 。 只有当我们客观衡量方法的进展时 , NLP 领域才能得以发展我们还需要再设计用于比较的对比基准和评价指标等方面取得突破 。
6
接下来 , 我们该做什么?
在接下来的一些年中 , 我们希望看到将各种上下文相关词向量应用于新的问题所带来的更多新发现 。 例如 , 构建一个系统可能涉及到复杂的协议 , 其中就需要在一系列数据集和任务的组合上执行调优和针对特定任务的训练 。
在拥有相对较少的监督信号的条件下 , 如何提升 NLP 程序性能的潜力 , 也是一个有意思的方向 。 例如 , 类似于 EMLo 的方法可以提升低资源类型和语言条件下的 NLP 程序性能 。 同时 , 计算开销较小的方法也有更广阔的应用前景 。
希望看到更多人尝试使用语言学的术语来概括这些方法正在学习的东西(以及那些没有学习的东西) 。


    推荐阅读