简介
“i do not love coding”,对于这样一句话,计算机是看不懂的,也不能直接进行输入,所以我们需要对他进行编码,让计算机能够看懂。
那么可能我们会第一时间想到onehot,是的经过onehot之后计算机确实可以进行处理了,但是会存在下面这个问题:
假设我们现在的语料库只有这五个单词,那么vocab_size = 5
下面这张图请大家忽略一些nlp上面的预处理问题,我为了给大家说明白所以举的例子比较直白,另外coding和like是我故意换的位置,我怕和pos_embedding弄混了,如果不懂什么是position emb的也没关系。
上图可以看出,通过one-hot编码之后的每个词。
看着挺好的呀,但是其实缺少了很重要的一点就是相似度问题,similarity(boy, girl)应该是不等于similarity(boy, hippo)的。
但是通过这种编码之后cosine-similarity都是零:
这个问题非常严重,所以才有了word embedding技术。
而其中:
- 2013年提出 Word2Vec
- 2014年提出 Glove
- 2017年提出 FastText
首先先看一下W2V之后的每个词会是什么样子:
这里我们语料只放这句话:
然后设置embedding_size = 2,然后画图出来:
可以看到每个词和其他词语之间的相似度关系,这对于我们后面的任务具有非常大的帮助。
大家不要关注这个和常识是不是贴近,因为我们的语料是非常畸形的。
原理
Word2Vec的原理有太多的blog去讲了,我尽量说的浅显。
这里我们说skip_gram,我认为这其实就是一种中心词预测上下文的一个问题,叫做skip_gram。
我们用上面的那个例子去说,我们是怎么给“I do not love coding”去做word2vec embedding的。
我们想要预测一个词输入进来吧,他的上下文的词语的概率,就需要输入每个词和他context作为训练数据给到nn网络。
- 生成训练数据
假设现在center是love:
设定一个窗口值C = 1,也就是love左边一个w和右边一个w是他的context,
然后我们就得到了训练数据:
(not, love)
(coding, love)
NOTE: 应该用word_id去表示,这里建立word2idx等过程省略。
然后我们就将上面的数据输入的网络当中,
这其中的过程可以这么理解:
我们希望特征center 和标签 context_word尽可能的相似,训练的过程就是最小化loss(最大化similarity(c, v)),的过程。
然后nn.Parameters()就是我们需要的word_embedding向量。
其中有一些重要的而数学公式和变化在代码分析部分我会简明扼要的提到一些。
代码分析
这一部分我们来详细地分析一个用pytorch实现的Word2Vec类:
首先是__init__初始化,这里输入两个参数
- vocab_size: 语料库的size,注意去重
- embedding_size: 每个word用多少维度的向量去表示
然后我们定义了两个embedding层,这里其实也困扰了我很久,一开始我就想为什么要定义两个embedding呢?
这里我给举一个例子:
我在我们班(全班一共有5个人,分别是Tom, Lucy, Neo,Tiffany还有我Braylon),好了现在我们要表示我自己,其实有两种方法:
1.
我 = [Braylon]
2.
我 = [Tom, Lucy, Neo, Tiffany]
所以, 对于一个word,有可能作为center,也有可能作为context,而这两种都可以表示这个word。所以就有两个emb分别训练。
下一步,重写forward方法:
输入三个参数:
- inputs: 就是center word,注意是word_id
- pos_labels: context words,注意不是一个词,因为一个center对应很多context word
- neg_labels:非context word,我们称为负样本,是为了更快的进行优化,后面讲到
其中注意neg_embs的维度,k表示的是每个单词对应需要多少个负样本。
上面这段代码的逻辑是首先将input_embs和pos_embs的维度统一,然后进行bmm相乘,
bmm
除了batch_size,将后面的维度进行矩阵相乘。
这个逻辑就是获得了中心词和上下文词的向量乘积。
同上,获得了中心词和负样本之间的向量乘积。
这两行的逻辑就是实现负采样中的损失函数表示,然后最后返回:
实现了下面这个损失函数:
最后
关于word2vec,明白他的原理是非常重要的,但是在真正的应用中没有必要自己实现,而且自己写的效果肯定不如专业的库。所以在处理时序或者nlp工程中还是推荐大家使用gensim进行word2vec.
后面我会分享gensim在处理时序数据中的应用。
大家共勉~
写的仓促,欢迎大家交流,或者批评指正。