![深入浅出Embedding:原理解析与应用实践](https://wfqqreader-1252317822.image.myqcloud.com/cover/844/38601844/b_38601844.jpg)
1.2 Word Embedding
因机器无法直接接收单词、词语、字符等标识符(token),所以把标识符数值化一直是人们研究的内容。开始时人们用整数表示各标识符,这种方法简单但不够灵活,后来人们开始用独热编码(One-Hot Encoding)来表示。这种编码方法虽然方便,但非常稀疏,属于硬编码,且无法重载更多信息。此后,人们想到用数值向量或标识符嵌入(Token Embedding)来表示,即通常说的词嵌入(Word Embedding),又称为分布式表示。
不过Word Embedding方法真正流行起来,还要归功于Google的word2vec。接下来我们简单了解下word2vec的原理及实现方法。
1.2.1 word2vec之前
从文本、标识符、独热编码到向量表示的整个过程,可以用图1-2表示。
![015-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/015-1.jpg?sign=1739284148-giAvFxL2yVsmnLiLkvj6a1hFHfKT6jAR-0-b84c11567ed98a26ce2a0efe34382cb0)
图1-2 从文本、标识符、独热编码到向量表示
从图1-2可以看出,独热编码是稀疏、高维的硬编码,如果一个语料有一万个不同的词,那么每个词就需要用一万维的独热编码表示。如果用向量或词嵌入表示,那么这些向量就是低维、密集的,且这些向量值都是通过学习得来的,而不是硬性给定的。至于词嵌入的学习方法,大致可以分为两种。
1. 利用平台的Embedding层学习词嵌入
在完成任务的同时学习词嵌入,例如,把Embedding作为第一层,先随机初始化这些词向量,然后利用平台(如PyTorch、TensorFlow等平台)不断学习(包括正向学习和反向学习),最后得到需要的词向量。代码清单1-1为通过PyTorch的nn.Embedding层生成词嵌入的简单示例。
代码清单1-1 使用Embedding的简单示例
from torch import nn import torch import jieba import numpy as np raw_text = """越努力就越幸运""" #利用jieba进行分词 words = list(jieba.cut(raw_text)) print(words) #对标识符去重,生成由索引:标识符构成的字典 word_to_ix = { i: word for i, word in enumerate(set(words))} #定义嵌入维度,并用正态分布,初始化词嵌入 #nn.Embedding模块的输入是一个标注的下标列表,输出是对应的词嵌入 embeds = nn.Embedding(4, 3) print(embeds.weight[0]) #获取字典的关键字 keys=word_to_ix.keys() keys_list=list(keys) #把所有关键字构成的列表转换为张量 tensor_value=torch.LongTensor(keys_list) #把张量输入Embedding层,通过运算得到各标识符的词嵌入 embeds(tensor_value)
运行结果:
['越','努力','就','越','幸运'] tensor([-0.5117, -0.5395, 0.7305], grad_fn=<SelectBackward>) tensor([[-0.5117, -0.5395, 0.7305], [-0.7689, 0.0985, -0.7398], [-0.3772, 0.7987, 2.1869], [-0.4592, 1.0422, -1.4532]], grad_fn=<EmbeddingBackward>)
2. 使用预训练的词嵌入
利用在较大语料上预训练好的词嵌入或预训练模型,把这些词嵌入加载到当前任务或模型中。预训练模型很多,如word2vec、ELMo、BERT、XLNet、ALBERT等,这里我们先介绍word2vec,后续将介绍其他预训练模型,具体可参考1.6节。
1.2.2 CBOW模型
在介绍word2vec原理之前,我们先看一个简单示例。示例展示了对一句话的两种预测方式:
假设:今天 下午 2点钟 搜索 引擎 组 开 组会。
方法1(根据上下文预测目标值)
对于每一个单词或词(统称为标识符),使用该标识符周围的标识符来预测当前标识符生成的概率。假设目标值为“2点钟”,我们可以使用“2点钟”的上文“今天、下午”和“2点钟”的下文“搜索、引擎、组”来生成或预测目标值。
方法2(由目标值预测上下文)
对于每一个标识符,使用该标识符本身来预测生成其他词汇的概率。如使用“2点钟”来预测其上下文“今天、下午、搜索、引擎、组”中的每个词。
两种预测方法的共同限制条件是,对于相同的输入,输出每个标识符的概率之和为1。
它们分别对应word2vec的两种模型,即CBOW模型(Continuous Bag-Of-Words Model)和Skip-Gram模型。根据上下文生成目标值(即方法1)时,使用CBOW模型;根据目标值生成上下文(即方法2)时,采用Skip-Gram模型。
CBOW模型包含三层:输入层、映射层和输出层。具体架构如图1-3所示。CBOW模型中的w(t)为目标词,在已知它的上下文w(t-2)、w(t-1)、w(t+1)、w(t+2)的前提下预测词w(t)出现的概率,即p(w/context(w))。目标函数为:
![017-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/017-1.jpg?sign=1739284148-MXN5rWJM7ykPeEP9F0dwjZMrhnOWg2Z2-0-6e95b3f39f4d62370b69f24c2660fa36)
![017-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/017-2.jpg?sign=1739284148-p9Um8FQElwpxospVyA8K2ynKlnBeJiIT-0-3df5b5dafc38ca646c8de02a8b5f4796)
图1-3 CBOW模型
CBOW模型其实就是根据某个词前后的若干词来预测该词,也可以看成是多分类。最朴素的想法就是直接使用Softmax来分别计算每个词对应的归一化的概率。但对于动辄十几万词汇量的场景,使用Softmax计算量太大,此时可以使用一种称为二分类组合形式的Hierarchical Softmax(输出层为一棵二叉树)来优化。
1.2.3 Skip-Gram模型
Skip-Gram模型同样包含三层:输入层、映射层和输出层。具体架构如图1-4所示。Skip-Gram模型中的w(t)为输入词,在已知词w(t)的前提下预测词w(t)的上下文w(t-2)、w(t-1)、w(t+1)、w(t+2),条件概率写为p(context(w)/w)。目标函数为:
![018-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/018-1.jpg?sign=1739284148-AIPkXIz26p7IYRi8vpVslr2cOiWnIFe4-0-900ad78fb093fc4594f1aa1bbd42415a)
![018-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/018-2.jpg?sign=1739284148-Hm2aRh4qi5PQoVuBHWeS1s10VLqsoxvL-0-7a47d3721e8a7c6a110a077fd7d20c04)
图1-4 Skip-Gram模型
我们通过一个简单的例子来说明Skip-Gram的基本思想。假设有一句话:
the quick brown fox jumped over the lazy dog
接下来,我们根据Skip-Gram模型的基本思想,按这条语句生成一个由序列(输入,输出)构成的数据集。那么,如何构成这样一个数据集呢?我们首先对一些单词以及它们的上下文环境建立一个数据集。可以以任何合理的方式定义“上下文”,这里是把目标单词的左右单词视作一个上下文,使用大小为1的窗口(即window_size=1)定义,也就是说,仅选输入词前后各1个词和输入词进行组合,就得到一个由(上下文,目标单词)组成的数据集,具体如表1-1所示。
表1-1 由Skip-Gram算法构成的训练数据集
![018-3](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/018-3.jpg?sign=1739284148-b9Y5dmXsNSnvfXUeiZJKbTee2GEHN07l-0-d00214f003f52a899a298bf8279f212d)
1.2.4 可视化Skip-Gram模型实现过程
前面我们简单介绍了Skip-Gram的原理及架构,至于Skip-Gram如何把输入转换为词嵌入、其间有哪些关键点、面对大语料库可能出现哪些瓶颈等,并没有展开说明。而了解Skip-Gram的具体实现过程,有助于更好地了解word2vec以及其他预训练模型,如BLMo、BERT、ALBERT等。所以,本节将详细介绍Skip-Gram的实现过程,加深读者对其原理与实现的理解。对于CBOW模型,其实现机制与Skip-Gram模型类似,本书不再赘述,感兴趣的读者可以自行实践。
1. 预处理语料库
先来看下面的语料库:
text = "natural language processing and machine learning is fun and exciting" corpus = [[word.lower() for word in text.split()]]
这个语料库就是一句话,共10个单词,其中and出现两次,共有9个不同单词。因单词较少,这里暂不设置停用词,而是根据空格对语料库进行分词,分词结果如下:
["natural", "language", "processing", "and", "machine", "learning", "is", "fun", "and", "exciting"]
2. Skip-Gram模型架构图
使用Skip-Gram模型,设置window-size=2,以目标词确定其上下文,即根据目标词预测其左边2个和右边2个单词。具体模型如图1-5所示。
![019-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/019-1.jpg?sign=1739284148-vmFTQQQtZaCiSPfg0QV4MmDHh9emTEHn-0-8d9a072d737807d6c65096c5947cfe5d)
图1-5 Skip-Gram模型架构图
在图1-5中,这里语料库只有9个单词,V-dim=9,N-dim=10(词嵌入维度),C=4(该值为2*window-size)。
如果用矩阵来表示图1-5,可写成如图1-6所示的形式。
![020-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/020-1.jpg?sign=1739284148-GKYz6mbOcHjLzM2c8A30agmMSsmBd4Ua-0-ac6bc94b45111d9701963e69f186d3f6)
图1-6 Skip-Gram模型的矩阵表示
注意
生产环境语料库一般比较大,涉及的单词成千上万。这里为便于说明,仅使用一句话作为语料。
在一些文献中,又将矩阵W V×N称为查找表(look up table)。2.1.1节介绍PyTorch的Embedding Layer时,会介绍查找表的相关内容。
3. 生成中心词及其上下文的数据集
根据语料库及window-size,生成中心词与预测上下文的数据集,如图1-7所示。
![020-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/020-2.jpg?sign=1739284148-BJhQt0QoKWURATk0BUpJqK3tdIAy9IrP-0-e6606237f5c5863efd29f98bedd9b62e)
图1-7 Skip-Gram数据集
图1-7中共有10对数据,X k对应的词为中心词,其左边或右边的词为上下文。
4. 生成训练数据
为便于训练word2vec模型,首先需要把各单词数值化。这里把每个单词转换为独热编码。在前面提到的语料库中,图1-7中显示了10对数据(#1到#10)。每个窗口都由中心词及其上下文单词组成。把图1-7中每个词转换为独热编码后,可以得到如图1-8所示的训练数据集。
![021-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/021-1.jpg?sign=1739284148-e4FrUJI23ZLh1WGAn0HCRtTMzRlgNOoL-0-4a44099c3c710ea601ef597493ed46f6)
图1-8 训练数据集
5. Skip-Gram模型的正向传播
上述1~4步完成了对数据的预处理,接下来开始数据的正向传播,包括输入层到隐藏层、隐藏层到输出层。
(1)输入层到隐藏层
从输入层到隐藏层,用图来表示就是输入向量与权重矩阵W1的内积,如图1-9所示。
![021-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/021-2.jpg?sign=1739284148-XZ0PcSHwJBZvelm1z5tmMmLAAAyAdjam-0-0fd8c5f0c55e8a240e345860cddf6701)
图1-9 输入层到隐藏层
这里将矩阵W 9×10先随机初始化为-1到1之间的数。
(2)隐藏层到输出层
从隐藏层到输出层,其实就是求隐含向量与权重矩阵W2的内积,然后使用Softmax激活函数、得到预测值,具体过程如图1-10所示。
![022-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/022-1.jpg?sign=1739284148-ajgJD2hfn7NogiJ4D6rtoAjuIURqZu9N-0-5577f69774b6de9f3cffc3dac10da5b1)
图1-10 隐藏层到输出层
(3)计算损失值
损失值即预测值与实际值的差,这里以选择数据集#1为例,即中心词为natural,然后计算对应该中心词的输出,即预测值,再计算预测值与实际值的差,得到损失值EI。中心词natural的上下文(这里只有下文)为language和processing,它们对应的独热编码为w_c=1,w_c=2,具体计算过程如图1-11所示。
![022-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/022-2.jpg?sign=1739284148-pcOIrF1BppWyWfcchnMpP5jSyIcv4TJM-0-11bf7dd565a5d9cb6fda531f63a2e1f5)
图1-11 计算损失值
6. Skip-Gram模型的反向传播
我们使用反向传播函数backprop,根据目标词计算的损失值EI,反向更新W1和W2。
为帮助大家更好地理解,这里简单说明一下反向传播的几个关键公式的推导过程。
假设输出值为u,即W'T·h=u,则预测值为:
![022-3](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/022-3.jpg?sign=1739284148-6JaReAtrxhxcraxK1zbjUz26EesHTl4r-0-2278da869fc3539505172eddb77d8409)
(1)定义目标函数
![023-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/023-1.jpg?sign=1739284148-sgP3y3bZZZeA49vennusssgXuH9yhMd2-0-973e567a7420a50ac78b34cc23cb3bd6)
(2)求目标函数关于的偏导数
![023-3](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/023-3.jpg?sign=1739284148-vfaSudRXizZGaGfq1GBa6Tn2bRNFsCbf-0-13183b4207b83d5f66d135548d53d423)
其中是第c个上下文在字典中对应的索引。
![023-5](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/023-5.jpg?sign=1739284148-onnH2zwMgPblXmvRouuoYZF0K4QNyeei-0-f96cf199fd86c6b8cd18b01e69d57b11)
,当
时,t c,j=1,否则,t c,j=0。
,表示预测值与真实值的误差。
的计算过程可用图1-12表示。
![023-10](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/023-10.jpg?sign=1739284148-vJA8BxUu5p8fMWPCBHbH9qxlLTf8YTiS-0-e564bf4894f24d1750cc62b900790c0c)
图1-12 目标函数关于的偏导计算过程示意图
(3)更新矩阵w'(即W2)
利用梯度下降法更新梯度:
![024-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-1.jpg?sign=1739284148-zJjWy8OqoLNFnuTkkrlJ0JfBm0cLFMkq-0-0da9c5331c74ecba3da0054549903bd7)
式(1.8)的计算过程可用图1-13及图1-14表示。
![024-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-2.jpg?sign=1739284148-MBRWkFb5vBZd9GMqnNISaaX5pmEj02bh-0-3c3912cb92c971ab2c9678336d48099d)
图1-13 参数更新示意图(一)
![024-3](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-3.jpg?sign=1739284148-b4guQ0udfdmE3uKKGlA755ys8hNxiFZ9-0-2397f74019ec89d349dac70f01bab2f0)
图1-14 参数更新示意图(二)
(4)求关于W(即W1)的偏导数
![024-4](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-4.jpg?sign=1739284148-bhxNGJKsIaQcOwEiDmvMG607A0T4hPSs-0-73f5781f541b648956674f53dda71e1c)
其中。
所以
![024-6](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-6.jpg?sign=1739284148-EPSK1DiMlXnT4yP27ka06L8OCclVTc40-0-76ec5866b8dd891eee3222fd8d45bac1)
式(1.10)的计算过程可用图1-15和图1-16表示。
![024-7](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/024-7.jpg?sign=1739284148-XuFYNGMVFwoQPFFlEYe09J2TXxsulhlX-0-65527084d9e56c281023540aa21e2471)
图1-15 偏导计算结果(一)
![025-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/025-1.jpg?sign=1739284148-gGzDUMjjmcBxRYPbjALO9oecCFhIbgLy-0-6be4e66774c17ac32192e3bc691f0017)
图1-16 偏导计算结果(二)
更新参数:
![025-2](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/025-2.jpg?sign=1739284148-5v6CdGgGHIMtKXhRdiUETFODCx9DFKeU-0-744c4e5027c6db45c463880ac1834329)
更新权重参数的计算过程可用图1-17和图1-18表示。
![025-3](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/025-3.jpg?sign=1739284148-3HoW0dgL3rUOfCi0AcLFOvAUBch5pI4a-0-23373de119d7e5effddeb0dc661ba33f)
图1-17 权重参数更新结果(一)
![025-4](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/025-4.jpg?sign=1739284148-fq4DmyKNqYFxlEvxv2N4TGl9c2VwXyoo-0-796b0258448db893d30c5a26c5aad248)
图1-18 权重参数更新结果(二)
1.2.5 Hierarchical Softmax优化
结合上面内容,我们需要更新两个矩阵W和W′,但这两个矩阵涉及的词汇量较大(即V较大),所以更新时需要消耗大量资源,尤其是更新矩阵W′。正如前面一直提到的,无论是CBOW模型还是Skip-Gram模型,每个训练样本(或者Mini Batch)从梯度更新时都需要对W′的所有V×N个元素进行更新,这个计算成本是巨大的。此外,在计算Softmax函数时,计算量也很大。为此,人们开始思考如何优化这些计算。
考虑到计算量大的部分都是在隐藏层到输出层阶段,尤其是W′的更新。因此word2vec使用了两种优化策略:Hierarchical Softmax和Negative Sampling。二者的出发点一致,即在每个训练样本中,不再完全计算或者更新W′矩阵,换句话说,两种策略中均不再显式使用W′这个矩阵。同时,考虑到上述训练和推理的复杂度高是因Softmax分母上的∑(求和)过程导致,因此上述的两种优化策略是对Softmax的优化,而不仅仅是对word2vec的优化。
通过优化,word2vec的训练速度大大提升,词向量的质量也几乎没有下降,这也是word2vec在NLP领域如此流行的原因。
Hierarchical SoftMax(以下简称HS)并不是由word2vec首先提出的,而是由Yoshua Bengio在2005年最早提出来的专门用于加速计算神经语言模型中的Softmax的一种方式。这里主要介绍如何在word2vec中使用HS优化。HS的实质是基于哈夫曼树(一种二叉树)将计算量大的部分变为一种二分类问题。如图1-19所示,原来的模型在隐藏层之后通过W′连接输出层,经过HS优化后则去掉了W′,由隐藏层h直接与下面的二叉树的根节点相连。
![026-1](https://epubservercos.yuewen.com/50C85D/20308228701714006/epubprivate/OEBPS/Images/026-1.jpg?sign=1739284148-9yJ1SaCIL0kEx4QROOKS2SGWZJCrF8kL-0-6333cdb1d03536ea139f3dc428922aa7)
图1-19 哈夫曼树示意图
其中,白色的叶子节点表示词汇表中的所有词(这里有V个),黑色节点表示非叶子节点,每一个叶子节点其实就是一个单词,且都对应唯一的一条从根节点出发的路径。我们用n(w,j)表示从根节点到叶子节点w的路径上的第j个非叶子节点,并且每个非叶子节点都对应一个向量,其维度与h相同。
1.2.6 Negative Sampling优化
训练一个神经网络意味着要输入训练样本并不断调整神经元的权重,从而不断提高对目标预测的准确性。神经网络每训练一个样本,该样本的权重就会调整一次。正如上面所讨论的,vocabulary的大小决定了Skip-Gram神经网络的权重矩阵的具体规模,所有这些权重需要通过数以亿计的训练样本来进行调整,这是非常消耗计算资源的,并且在实际训练过程中,速度会非常慢。
Negative Sampling(负采样)解决了这个问题,它可以提高训练速度并改善所得到词向量的质量。不同于原本需要更新每个训练样本的所有权重的方法,负采样只需要每次更新一个训练样本的一小部分权重,从而在很大程度上降低了梯度下降过程中的计算量。