碎碎语
在我的word2vec上中我们已经较为详细的介绍过了统计语言模型和神经网络语言模型,但是那些也只是我们Word2vec学习的前的一些开胃小菜,加下来我们终于要进入Word2vec的学习了。
Word2Vec
其实在学习NLP的过程中我越发的发现,很多模型的处理方式很我们人类的正常思考方式很相似。在语言的处理方面也是,因为我们人类的语言系统中我们是从字-->词语-->句子-->段落-->文章。但是呢,因为我们的计算机是无法直接理解我们的语言,因此计算机需要先将我们的人类语言计算机化,也就是将我们的语言转化成数字,在我们这里也就是向量,进而通过向量去理解我们的上下文。
在我们Word2Vec上的讲解中我们说过N-gram,它本质上就是就是统计我们共现词出现的频率,进而预测我们的下一个要输出什么,而我们的word2vec则是通过观察和学习大量的句子,从而培养语感,从而具有一定的预测能力。
一. Word2Vec到底解决什么问题?
假设我们的语料库:
在这其中每一个都是一个token,在传统NLP中我们会使用one-hot。
这时候就会有人问什么是one-hot呀?(其实这个应该在Word2Vec上的部分就写完的,但是因为我忘了,在此补充一下)
one-hot简单点来说就是给我们的每个词贴的唯一标签,他本身是无法表达词的含义,只能去表达词的一个顺序位置,例如:
假设我们单词表有五个词:“我” “喜欢” “吃” “苹果” “香蕉”
那么我们就可以使用长度为5的向量来表示我们的这五个词:
“我” [1,0,0,0,0]
“喜欢” [0,1,0,0,0]
“吃” [0,0,1,0,0]
“苹果” [0,0,0,1,0]
“香蕉” [0,0,0,0,1]
我们会发现我们的每个向量只有一个位置是1,其余位置都是0,而且那个是1的位置正好就是我们每个词语在句子中的位置。这便是我们的One-Hot。
但是如果你真的理解语言模型,你就会发现我们的One-Hot有一个非常致命的问题,虽然我们可以通过One-Hot将我们的token转换成向量,但是这个向量他只能去表示我们token的位置,对于token和token之间的关系他一无所知,在数学上这个关系的体现一般会使用点积。
[0,0,0,1,0]
[0,0,0,0,1]
*
= 0
这说明在我们的one-hot下我们的苹果和香蕉没有任何关系,本质上就是one-hot标签无法去表示token和token之间的内在联系。补充完了我们的one-hot,我们回归主题。
正是因为我们的One-Hot标签无法去理解词和词的内在联系,因此我们的Word2Vec希望有一种方法可以用向量来表示我们的token,既可以表示词和词之间的关系,也尽可能的保持低维度,因为低维度可以降低计算复杂度。
Word2Vec 希望学习一个映射:
其中:
例如: king --> [0.21,-0.31,0.72......]
我们希望较大,而
较小,本质上就是我们希望相似的词他们的词向量尽可能的相近,不相似的词他们的词向量尽可能的相离。这里的相似和相离只要计算两个向量的余弦相似值即可。因此我们的Word2Vec本质上就是让计算机理解词与词之间的关系。
二.Word2Vec 的核心理论
在前面我说过Word2Vec本质上就是一种基于神经网络训练,来让计算机理解词与词之间的关系,但是在Word2Vec中最重要的理论是Distributional Hypothesis(分布假设)。
那什么是分布假设(Distributional Hypothesis)?
简单点来讲就是:一个词的语义,可以由它所处的上下文决定。
例如:
I drink coffee every morning.
I drink tea every morning.
I drink milk every morning.
那么:和
可能具有相似的分布
因此这个分布式假设可以简单总结成:语义相似上下文分布相似
因此我们的Word2Vec的本质就是尝试把这个思想参数化成一个神经网络优化问题。
参数化:
简单点来说就是不要只凭人观察或者说直觉,而是用一堆可以学习的数字来表示。
神经网络优化:
Loss——>反向传播——>优化器——>更新参数,具体内容请参考我们我Word2Vec(上)
总结:
我们认为“词的意义可以通过上下文体现”,于是把每个词表示成一组可以学习的数字,然后设计一个“根据词预测上下文”的任务,通过损失函数、反向传播和优化器不断调整这些数字,最终得到有语义关系的词向量。
三.Word2Vec的核心框架
我们以skip-gram和Nagetive Sampling为例子:
训练语料 → 构造训练样本(中心词,上下文词) → Embedding Lookup → 词向量 ,计算点积(Score) → Negative Sampling → Sigmoid → Loss → 反向传播 → 参数更新 → W、W′更新 → 最终 Embedding
Word2Vec 并不是直接“计算出”Embedding,而是通过一个“预测上下文”的任务,让Embedding矩阵里的参数在训练过程中不断被优化,最后得到含有语义信息的词向量。
1.训练语料
假如我们有:
我 喜欢 吃 苹果
我 喜欢 吃 香蕉
Word2Vec首先需要大量这样的文本,但是呢,我们的Word2Vec本身又不能理解我们的纯文本,因此需要我们把文本转换成训练样本。
2.构造训练样本(构造 Skip-gram 训练数据)
假设:
我 喜欢 吃 苹果
window(窗口) = 1
含义:中心词往左或者往右只关注一个最近的词。(有点想我当年学过的滑动窗口)
假设“喜欢”是我们的中心词,那么“我”和“吃”都会在我们的窗口中出现,而这两个在窗口中会出现的词语表示的就是我们的上下文词。因此我们就会得到(喜欢,我)和(喜欢,吃)这两个样本。
所以我们的Skip-gram 训练数据就是我们大量的(中心词,上下文词)对。不过因为我们的计算机只能去理解0和1,所以我们还是需要帮我们的训练数据数字化,变成计算机可以理解的语言。
其实学到这里很多人会产生疑问,我们学过了N-gram (可以看看我的Word2Vec),现在又学习了skip-gram,好像在word2vec中还有一个CBOW,这些技术到底是用来干啥的,为啥要搞这么多的算法?
skip-gram:他关心的是一个词(中心词)他的周围会出现那些词。
CBOW:他关心的是已知周围的词(上下文词),他的中心词是什么。
N-gram:本质上是根据词与词共现的一个频率,来估计我们的条件概率。
简单总结一下:
| CBOW | Skip-gram | |
| 输入 | 上下文 | 中心词 |
| 输出 | 中心词 | 上下文 |
| 方向 | context-target | target-context |
| 训练样本 | 一个上下文组合->中心词 | 一个中心词->多个上下文组合 |
| 核心目的 | 学习词向量 | 学习词向量 |
如果以后你面试的时真的被询问:
“N-gram、CBOW、Skip-gram 有什么区别?”“N-gram 主要通过统计固定长度的局部词序列来估计条件概率,例如根据前 N-1 个词预测下一个词;CBOW 和 Skip-gram 都属于 Word2Vec,通过上下文预测任务学习词的分布式表示,其中 CBOW 是由上下文预测中心词,而 Skip-gram 是由中心词预测上下文词。N-gram 更关注显式的词序概率,而 Word2Vec 更关注词之间的分布式语义关系。”
3.Embedding Lookup
简单点来说就是查表,这个embedding lookup会在后面频繁的使用到。
我们有一个embedding 矩阵:
比如:
那么“吃”这个词的id = 2,我们去词向量表中找第二行,进而我们就会得到= [0.2,-0.1,0.5].
这个过程就被叫做Embedding Lookup,根据词 ID,从 Embedding 矩阵中取出这个词当前的向量。
4.词向量 ,计算点积(Score)或者说是Logit
在我们经历过了Embedding Lookup之后我们就会得到两个矩阵(W)和
(W'),也就是我们的中心词矩阵和我们的上下文矩阵。
所以对于(喜欢,我)我们很容易查表得到和
,最开始这两个向量是随机化初始的,我们训练的过程就是不断的修正他们。
我们得到了中心词和上下文词之后我们就可以计算我们的点积,从而得到我们的score{计算(中心词,上下文词)到底有多匹配}
例如:,
Score(Logit) =*
通过计算,如果我们的点积比较大,说明这两个词较为匹配,反之则相反。
5.Negative Sampling
其实这个东西算是一种优化策略,但是我感觉未来可能随着算力的不断提高,很多优化的策略也许使用暴力的堆叠可能也会有不同的结果。
假设词表:
如果我们要预测“吃”的上下文是不是“苹果”最简单的方法就是遍历所有的词,分别算出条件概率,但是这太慢了,O(N)效率太低了。Negative Sampling的想法就是我不需要拿整个词表比较,只随机挑几个“错误答案”来比较。也就是在我们学习正样本的同时,会提供给模型一些负样本,进而提高我们模型的学习效率。如果未来我真的有时间的话,我感觉可以把我看的Clip那篇论文简单的讲一下,我相信各位正在学习大模型或者是NLP的同志们一定会有不同的收获。
作用:把原本昂贵的“整个词表上的多分类问题”,转化成少量样本上的二分类问题。
6.Sigmoid(激活函数)
现在的我们在经过上面的点积计算过后,我们已经得到了:
Score =*
我们需要把这Score分数变成0~1之间的数字:
这时候就会有好奇宝宝问:“为什么我们需要将我们的这个Score分数计算前统一到0~1的范围之内,这样做有什么好处?”
我们在上面计算点积是得到是一个数,他并不是一个概率,而我们在后续的计算和训练时都需要的是条件概率,因此我们的激活函数Sigmoid负责把“匹配程度”转换成“这个样本是真实上下文的概率”。
那这时候好奇宝宝又开始提问题了,为什么这里激活函数使用Sigmoid而不去使用别的激活函数呢?
这其实就和我们的Negative Sampling有点关系了,由于我们的Word2Vec会采用到负样本训练的缘故,我们的模型训练的本质上就是判断“中心词 + 上下文词”这个组合是真的还是假的。也就是我们所谓的二分类问题。
7.Loss(损失值)
我们的模型在经过预测之后,我们该如何评价模型预测的效果呀,这就要使用到我们的Loss了,衡量我们模型给出的预测到底怎么样。
例如:
如果:
那么:
这就说明模型预测的很好,反之则说明我们的模型训练效果一般。
8.反向传播和参数更新
反向传播简单点来说就是探寻我们参数往什么方向去修改,可以去降低我们的Loss值。
在反向传播的过程中会用到链式法则计算偏导数。具体内容可以参看我的上一篇博客。
至于参数更新就要使用到我们的优化器(说法很多,我自己现在也只用过几个简单点的,后续等我完全弄明白了再来补充一下这里的部分内容)。
9.更新Embedding矩阵W、W′
原来的 W和W' --》反向传播得到的梯度--》优化器 --》新的W和W’
至此我们就得到了我们最终的Word2Vec Embedding。
我们的Embedding在训练的过程中蕴含了大量的词-上下文关系。
至此我们的Word2Vec的完整架构就已经讲完了,但是其实还是会有很多细节内容没有完全讲清,如果真的想要学明白,最好自己去推到一些那个数学公式,视频在cs224n第一节课的最后10min.
如果对别的部分的数学推导感兴趣我推荐你看一下这篇《word2vec中的数学原理详解》。
四.未来
One-Hot → N-gram → Word2Vec → Contextual Embedding→
Transformer → BERT / GPT → LLM
虽然我们的Word2Vec距离现在已经过去很久了,但是我觉得一种算法也好,模型也罢,我们在学习他的时候更多的是学习一种思考的方式,没有必要一直追着我们所谓的前沿去追寻,当然如果你着急去实习的话,那就另说了,那还是及时做点和你想去岗位垂直的实习,方便你入职。
如果你能认真的看完我写的这两篇文章,我相信你们一定会有所收获。
博观而约取,厚积而薄发。