2.1 词汇表征
上周我们学习的词汇表示方法虽然能很准确地表示词汇,但这种表示方法把每个词都孤立起来,比如如果我们输入的是一个句子,上周我们所讲的方法虽然保存了词汇,但并不对矩形或者短语词汇之间进行表征和研究,算法对于相关词的泛化能力也不强。所以这一节我们来讲一个全新的方法:词嵌入。
- 原因:如果用上周所讲的向量表示方法来计算词向量与词向量之间的关系的话,任何两个词之间的内积都是0,所有词的距离都一样,所以也没有什么价值。
所以我们可以这样表示一个词:
抛弃词典的思维,我们来用一定的性质或者指标来衡量词,比如第一个是性别,显然男人和女人是直接与性别相关的,而苹果和橙子显然就不是了。第二个是皇家的,那么相应的,国王和皇后就与这个词很有关系了,而其他词就没有,第三个是年龄,历史上当选国王与皇后的年龄通常都是成年人,所以显然关系很大,而其他词就与年龄没有什么关系,其次是食物,显然苹果和橙子与其直接相关,但其他词就没什么能吃的了……
以此类推,比如说我们有三百维的指标,由此组成的三百维的向量就可以表示相应的词了。当然为了表示得更清晰,我们用e5391e_{5391}e5391来表示Man这个词,用e9853e_{9853}e9853来表示Woman这个词,以此类推而表示后续的词语。
这样一来,苹果和橙子除了在颜色的特征向量上有所不同之外,大多数的向量都是非常相似的。如果我们知道了orange juice这个短语的搭配(算法),那么很大几率上,他也会明白Apple juice这个东西。这样对于相似的词语,算法的泛化能力会强上很多。
我们还有另一个可以清晰地判断词语和词语之间的距离关系的算法:
如果我们可以得到一群词的相同维数的特征向量,比如是300维,那么我们可以把这300维的数据嵌入一个二维空间里,转变成可视化的图像。常用的可视化算法是:t-SNE算法。
如果观察这种词嵌入的表示方法,你会发现man和woman这些词聚集在一块,king和queen聚集在一块,这些都是人,也都聚集在一起。动物都聚集在一起,水果也都聚集在一起(上图编号5所示),像1、2、3、4这些数字也聚集在一起。如果把这些生物看成一个整体,他们也聚集在一起。
这种词嵌入算法对于相近的概念,学到的特征也比较类似,在对这些概念可视化的时候,这些概念就比较相似,最终把它们映射为相似的特征向量。这种表示方式用的是在300维空间里的特征表示,这叫做嵌入(embeddings)。
词嵌入在NLP中已经是一个非常重要的概念了,而为了可视化,t-SNE算法把这个空间映射到低维空间。
2.2 使用词嵌入
那么如何把这种表示方法应用到NLP应用中呢?我们来看一个命名实体识别的例子:
假如有一个句子:“Sally Johnson is an orange farmer.”(Sally Johnson是一个种橙子的农民),你会发现Sally Johnson就是一个人名,所以这里的输出为1。之所以能确定Sally Johnson是一个人名而不是一个公司名,是因为你知道种橙子的农民一定是一个人,前面我们已经讨论过用one-hot来表示这些单词,即x(1),x(2)x^{(1)},x^{(2)}x(1),x(2)的输出为1。
如果你用特征化表示方法,看到一个新的输入:“Robert Lin is an apple farmer.”(Robert Lin是一个种苹果的农民),因为知道orange和apple很相近,那么你的算法很容易就知道Robert Lin也是一个人,也是一个人的名字。一个有意思的情况是,要是测试集里这句话不是“Robert Lin is an apple farmer.”,而是不太常见的词怎么办?要是你看到:“Robert Lin is a durian cultivator.”(Robert Lin是一个榴莲培育家)怎么办?榴莲(durian)是一种比较稀罕的水果,这种水果在新加坡和其他一些国家流行。如果对于一个命名实体识别任务,你只有一个很小的标记的训练集,你的训练集里甚至可能没有durian(榴莲)或者cultivator(培育家)这两个词。但是如果你有一个已经学好的词嵌入,它会告诉你durian(榴莲)是水果,就像orange(橙子)一样,并且cultivator(培育家),做培育工作的人其实跟farmer(农民)差不多,那么你就有可能从你的训练集里的“an orange farmer”(种橙子的农民)归纳出“a durian cultivator”(榴莲培育家)也是一个人。
词嵌入能够达到这种效果,其中一个原因就是学习词嵌入的算法会考察非常大的文本集,也许是从网上找到的,这样你可以考察很大的数据集可以是1亿个单词,甚至达到100亿。通过考察大量的无标签文本,你可以发现orange(橙子)和durian(榴莲)相近,farmer(农民)和cultivator(培育家)相近。嵌入表达把它们都聚集在一块,通过读取大量的互联网文本发现了orange(橙子)和durian(榴莲)都是水果。接下来你可以把这个词嵌入应用到你的命名实体识别任务当中,尽管你只有一个很小的训练集,也许训练集里有100,000个单词,但你可以使用迁移学习,把你从互联网上免费获得的大量的无标签文本中学习到的知识迁移到这个任务中来,让它能够分辨orange(橙子)、apple(苹果)和durian(榴莲)都是水果,然后把这些知识迁移到一个任务中。当然,这里为了简化只画了单向的RNN,事实上如果你想用在命名实体识别任务上,你应该用一个双向的RNN,而不是这样一个简单的单向RNN。
总结一下如何用词嵌入做迁移学习:
- 第一步,先从大量的文本集中学习词嵌入。
你需要一个非常大的文本集,或者可以下载网上预训练好的词嵌入模型,这种模型网上你可以找到不少,词嵌入模型并且都有许可。 - 第二步,你可以用这些词嵌入模型把它迁移到你的新的只有少量标注训练集的任务中。
比如说用这个300维的词嵌入来表示你的单词。这样做的一个好处就是你可以用更低维度的特征向量代替原来的10000维的one-hot向量,现在你可以用一个300维更加紧凑的向量。尽管one-hot向量计算很快,但300维的向量会更加紧凑。 - 第三步,当你在新的任务上训练模型时,比如在命名实体识别任务只有少量的标记数据集上,你可以自己选择要不要继续微调,选择是否用新的数据调整词嵌入。实际中,只有这个第二步中有很大的数据集你才会这样做,如果你标记的数据集不是很大,通常我不会在微调词嵌入上费力气。
当你的任务的训练集相对较小时,词嵌入的作用最明显,所以它广泛用于NLP领域。词嵌入在语言模型、机器翻译领域用的少一些,尤其是你做语言模型或者机器翻译任务时,因为这些任务里你有大量的数据。在其他的迁移学习情形中也一样,如果你从某一任务A迁移到某个任务B,只有A中有大量数据,而B中数据少时,迁移的过程才有用。所以对于很多NLP任务这些都是对的,而对于一些语言模型和机器翻译则不然。
词嵌入与人脸编码之间还有着奇妙的关系。我们上一门课训练了一个Siamese网络结构,这个网络会学习不同人脸的一个128维表示,然后通过比较编码结果来判断两个图片是否是同一个人脸,词嵌入的意思和这个差不多。但两者不同的是:在人脸识别中我们训练一个网络,任给一个人脸照片,甚至是没有见过的照片,神经网络都会计算出相应的一个编码结果。上完后面几节课,你会更明白,我们学习词嵌入则是有一个固定的词汇表,比如10000个词,我们学习向量e1−e10000e_{1} - e_{10000}e1−e10000,学习每一个词汇表的单词的固定嵌入,如果输入了一个未出现的单词,那么我们就标记为未知单词,而不是像人脸识别那样直接进行计算。
2.3 词嵌入的特性
词嵌入还有一个迷人的特性就是它还能帮助实现类比推理,尽管类比推理可能不是自然语言处理应用中最重要的,不过它能帮助人们理解词嵌入做了什么,以及词嵌入能够做什么,让我们来一探究竟。
这是一系列你希望词嵌入可以捕捉的单词的特征表示,假如我提出一个问题,man如果对应woman,那么king应该对应什么?你们应该都能猜到king应该对应queen。能否有一种算法来自动推导出这种关系呢?
当然是有的。
我们用一个四维向量来表示man,同理用四维向量来表示woman,king和queen。一个有趣的特性就是,假如你用两个向量,比如eman,ewomane_{man}, e_{woman}eman,ewoman做减法,即:
类似的,eking,equeene_{king}, e_{queen}eking,equeen做减法:
这个结果表示,man和woman主要的差异是gender(性别)上的差异,而king和queen之间的主要差异,根据向量的表示,也是gender(性别)上的差异。所以得出这种类比推理的结论的方法就是,当算法被问及man对woman相当于king对什么时,算法所做的就是计算两个向量的减法,然后找出向量使得eman−ewoman≈eking−exe_{man}-e_{woman} \approx e_{king} - e_xeman−ewoman≈eking−ex也就是说,当这个新词是queen时,式子的左边会近似地等于右边。这种思想首先是被Tomas Mikolov 和 Wen-tau Yih还有Geoffrey Zweig提出的,这是词嵌入领域影响力最为惊人和显著的成果之一,这种思想帮助了研究者们对词嵌入领域建立了更深刻的理解。
在图中,词嵌入向量在一个可能有300维的空间里,于是单词man代表的就是空间中的一个点,另一个单词woman代表空间另一个点,单词king也代表一个点,还有单词queen也在另一点上。事实上,我们在上个幻灯片所展示的就是向量man和woman的差值非常接近于向量king和queen之间的差值,我所画的这个箭头代表的就是向量在gender(性别)这一维的差,不过不要忘了这些点是在300维的空间里。为了得出这样的类比推理,计算当man对于woman,那么king对于什么。我们需要做的就是找到单词w来使得等式两边相差最小,即Finewordw:argmaxSim(ew,eking−eman+ewomanFine word w : argmax Sim(e_w, e_{king}- e_{man} + e_{woman}Finewordw:argmaxSim(ew,eking−eman+ewoman通过方程找到一个使得相似度最大的单词,如果结果理想的话会得到单词queen。
但是在t-SNE算法中大多数情况下你并不能依靠平行四边形法则,因为这个函数的非线性映射使得得到的向量大多数情况下并不能满足这个法则。
其次,我们可以通过余弦相似度来解决这个问题,测量两个向量的相似度。
与正弦不同的是,余弦相似度在角度很小的时候的值接近于1,而不是0。
词嵌入的一个显著成果就是,可学习的类比关系的一般性。举个例子,它能学会man对于woman相当于boy对于girl,因为man和woman之间和king和queen之间,还有boy和girl之间的向量差在gender(性别)这一维都是一样的。它还能学习Canada(加拿大)的首都是Ottawa(渥太华),而渥太华对于加拿大相当于Nairobi(内罗毕)对于Kenya(肯尼亚),这些都是国家中首都城市名字。它还能学习big对于bigger相当于tall对于taller,还能学习Yen(円)对于Janpan(日本),円是日本的货币单位,相当于Ruble(卢比)对于Russia(俄罗斯)。这些东西都能够学习,只要你在大型的文本语料库上实现一个词嵌入学习算法,只要从足够大的语料库中进行学习,它就能自主地发现这些模式。
2.4 嵌入矩阵
我们应用算法来学习词嵌入的时候,实际上是学习一个嵌入矩阵。
把矩阵E和这个one-hot向量相乘,最后得到的其实就是这个300维的列,即E∗Oj=ejE*O_j = e_jE∗Oj=ej
在下节视频中你将会随机地初始化矩阵E,然后使用梯度下降法来学习这个300×10,000的矩阵中的各个参数,
乘以这个one-hot向量会得到嵌入向量。再多说一点,当我们写这个等式的时候,写出这些符号是很方便的,代表用矩阵E乘以one-hot向量。但当你动手实现时,用大量的矩阵和向量相乘来计算它,效率是很低下的,因为one-hot向量是一个维度非常高的向量,并且几乎所有元素都是0,所以矩阵向量相乘效率太低,因为我们要乘以一大堆的0。所以在实践中你会使用一个专门的函数来单独查找矩阵E的某列,而不是用通常的矩阵乘法来做,但是在画示意图时(上图所示,即矩阵E乘以one-hot向量示意图),这样写比较方便。
2.5 学习词嵌入
这一节主要讲了用机器学习的模型解决学习语言模型,从而学习词嵌入的问题,输入一定的上下文来学习这种模型。
我们的例子依旧是熟悉的按照已经给的上下文来推测下一个可能出现的词语的问题。
我们首先给出的思路就是:
建立一个语言模型来学习词嵌入。
从第一个词I开始,建立一个one-hot向量表示这个单词I。这是一个one-hot向量(上图编号1所示),在第4343个位置是1,它是一个10,000维的向量。然后要做的就是生成一个参数矩阵EEE,然后用E乘以O4343O_{4343}O4343,得到嵌入向量e4343e_{4343}e4343。然后我们对其他的词也进行相同的操作。
于是现在你有许多300维的嵌入向量。
我们能做的就是把它们全部放进神经网络中,经过神经网络以后再通过softmax层,这个softmax也有自己的参数,然后这个softmax分类器会在10,000个可能的输出中预测结尾这个单词。假如说在训练集中有juice这个词,训练过程中softmax的目标就是预测出单词juice,就是结尾的这个单词。这个隐藏层有自己的参数,我这里用W[1]W^{[1]}W[1]和b[1]b^{[1]}b[1]来表示,这个softmax层也有自己的参数W[2]W^{[2]}W[2]和b[2]b^{[2]}b[2]。如果它们用的是300维大小的嵌入向量,而这里有6个词,所以用6×300,所以这个输入会是一个1800维的向量,这是通过将这6个嵌入向量堆在一起得到的。
- 事实上通过这个算法能很好地学习词嵌入,原因是,如果你还记得我们的orange jucie,apple juice的例子,在这个算法的激励下,apple和orange会学到很相似的嵌入,这样做能够让算法更好地拟合训练集,因为它有时看到的是orange juice,有时看到的是apple juice。如果你只用一个300维的特征向量来表示所有这些词,算法会发现要想最好地拟合训练集,就要使apple(苹果)、orange(橘子)、grape(葡萄)和pear(梨)等等,还有像durian(榴莲)这种很稀有的水果都拥有相似的特征向量。
这就是早期最成功的学习词嵌入,学习这个矩阵EEE的算法之一。现在我们先概括一下这个算法,看看我们该怎样来推导出更加简单的算法。
现在我想用一个更复杂的句子作为例子来解释这些算法,
假设在你的训练集中有这样一个更长的句子:“I want a glass of orange juice to go along with my cereal.”。我们在上个幻灯片看到的是算法预测出了某个单词juice,我们把它叫做目标词,它是通过一些上下文,在本例中也就是这前4个词推导出来的。如果你的目标是学习一个嵌入向量,研究人员已经尝试过很多不同类型的上下文。如果你要建立一个语言模型,那么一般选取目标词之前的几个词作为上下文。但如果你的目标不是学习语言模型本身的话,那么你可以选择其他的上下文。
比如说,你可以设定它的上下文是左边和右边的四个词,即把目标词左右各4个词作为上下文。这就意味着算法不仅获得左边4个词,也就是a glass of orange,还有右边四个词to go along with,然后要求预测出中间这个词,这也可以用来学习词嵌入。
或者你想用一个更简单的上下文,也许只提供目标词的前一个词,比如只给出orange这个词来预测orange后面是什么,这将会是不同的学习问题。你可以构建一个神经网络,只把目标词的前一个词或者说前一个词的嵌入向量输入神经网络来预测该词的下一个词。
还有一个效果非常好的做法就是上下文是附近一个单词,它可能会告诉你单词glass是一个邻近的单词。或者说我看见了单词glass,然后附近有一个词和glass位置相近,那么这个词会是什么?这就是用附近的一个单词作为上下文。我们将在下节视频中把它公式化,这用的是一种Skip-Gram模型的思想。这是一个简单算法的例子,因为上下文相当的简单,比起之前4个词,现在只有1个,但是这种算法依然能工作得很好。
研究者发现,如果你真想建立一个语言模型,用目标词的前几个单词作为上下文是常见做法。但如果你的目标是学习词嵌入,那么你就可以用这些其他类型的上下文,它们也能得到很好的词嵌入。