Word2Vec已经几乎成为NLP任务中,肯定会用到的模型,当然现在我们有了更新的Elmo和Bert,但是Word2Vec作为基本的词向量,仍然需要弄明白。
1. 词的Onehot表示:
当我们处理文本的时候,我们首先需要将这些文本进行表示,以前大家常用的就是onehot编码。首先对整个文档建立一个字典,每个字/词和索引一一对应。对于文档中的一句话,比如,“I Like Machine Learning”
。我们就可以根据词典就这句话中的每个词,转化为一个高纬的稀疏向量。向量中只有一个值为1,其他为0。
“Machine”: [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ...]
“Learning”: [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...]
缺点分析
1、向量的维度会随着句子的词的数量类型增大而增大;
2、任意两个词之间都是孤立的,无法表示语义层面上词汇之间的相关信息,而这一点是致命的。
2. 词的分布式表示:
针对Onehot的问题,大家首先想到的就是能不能用比较短的,稠密非稀疏的向量来表示词。中间提出了很多方法,其中一个就是Word2Vec。我们之前做过完形填空,都是利用上下文语义来判断选择哪个答案。所以一个词的语义可以由上下文来表征。
借此,人们提出了词的分布式表示(distributed representation)。Onehot是将一个词用一些高维稀疏向量表示出来,而分布式表示,就是将一个词映射到一个比较短的非稀疏向量中。
2.1 NNLM:
基于神经网络的分布表示又称为词向量或者词嵌入。 2001年, Bengio 等人正式提出神经网络语言模型( Neural Network Language Model ,NNLM),该模型在学习语言模型的同时,也得到了词向量。
典型的神经网络语言模型(NNLM):
- Neural Network Language Model ,NNLM
- Log-Bilinear Language Model, LBL
- Recurrent Neural Network based Language Model,RNNLM
- Collobert 和 Weston 在2008 年提出的 C&W 模型
- Mikolov 等人提出了 Word2Vec(CBOW和Skip-gram模型)
直到Word2Vec模型词向量才真正被我们所关注。
3. 两种训练模式:
CBOW:上下文来预测当前词语;
Skip-gram:当前词来预测上下文。
CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
3.1 CBOW:
CBOW(Continuous Bag-of-Word Model),即连续词袋模型,通过上下文来预测当前词语。
假设 Corpus:{I drink coffee everyday}, Window_size:2 ,Target : Coffee
- 输入层:上下文单词的onehot {设单词向量空间dim为V,上下文单词个数为C};
- 输入层分别乘以共享的输入权重矩阵 W V ∗ N W_{V*N} WV∗N:N为自己设定的数
- 所得的向量相加求平均作为隐层向量 v 1 ∗ N v_{1*N} v1∗N
- 乘以输出权重矩阵 W N ∗ V ′ W'_{N*V} WN∗V′
- 得到向量 s o f t m a x ( u 1 ∗ V 0 ) softmax(u^0_{1*V}) softmax(u1∗V0)
- 计算预测值和和实际label的loss function,然后进行训练
3.2 Skip-gram:
Skip-gram,用当前词来预测预测上下文。我当时看到的时候是感觉非常荒谬的,如何才能用一个词来预测他真的上下文。接下来我们将用多种方式实现,到具体的案例中就容易理解了。
TensorFlow实现:
我们所用的数据来自Cornell大学的电影评论数据。关于数据的下载和导入不再列出,主要写下数据处理的格式和模型的搭建。同其他NLP任务一样,我们首先要建立字典然后将其数字化。
- 产生一个batch的数据:
batch_data = []
label_data = []
while len(batch_data) < batch_size:
# 随机选择一个句子
rand_sentence = np.random.choice(sentences)
# 滑动窗口,产生连续的数据
window_sequences = [rand_sentence[max((ix-window_size),0):(ix+window_size+1)] for ix, x in enumerate(rand_sentence)]
# 窗口的中心词设置为label_indices,
label_indices = [ix if ix<window_size else window_size for ix,x in enumerate(window_sequences)]
# 设置输入tuple(y, X)
if method=='skip_gram':
batch_and_labels = [(x[y], x[:y] + x[(y+1):]) for x,y in zip(window_sequences, label_indices)]
# 将上面的数据展开 (target word,surrounding word)
tuple_data = [(x, y_) for x,y in batch_and_labels for y_ in y]
batch, labels = [list(x) for x in zip(*tuple_data)]
batch_data.extend(batch[:batch_size])
label_data.extend(labels[:batch_size])
- 构建模型:
x_inputs = tf.placeholder(tf.int32, shape=[batch_size])
y_target = tf.placeholder(tf.int32, shape=[batch_size, 1])
valid_dataset = tf.constant(valid_examples, dtype=tf.int32)
# Lookup the word embedding:
embed = tf.nn.embedding_lookup(embeddings, x_inputs)
nce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocabulary_size]))
loss = tf.reduce_mean(tf.nn.nce_loss(nce_weights, nce_biases, embed, y_target, num_sampled, vocabulary_size))
4. gensim训练词向量:
通过gensim可以直接训练word2vec,下面介绍各个参数。
gensim.models.Word2Vec():
- sentences: 要分析的语料,可以是一个列表,或者从文件中遍历读出
- size=100: 词向量的维度。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。
- window=5:即词向量上下文最大距离。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。推荐在[5,10]之间;
- iter=5: 随机梯度下降法中迭代的最大次数。对于大语料,可以增大这个值;
- min_count=5:需要计算词向量的最小词频。可以去掉一些生僻的低频词。如果是小语料,可以调低这个值;
- workers=3:多线程数;
- sg=0: 如果是0, 则是CBOW模型,是1则是Skip-Gram模型
- hs=0: 如果是0, 则是Negative Sampling,是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax
- negative=5:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间
- alpha=0.025: 在随机梯度下降法中迭代的初始步长
- min_alpha:最小的迭代步长值
from gensim.models import Word2Vec
word2vec_model = Word2Vec(sentence, iter=15, min_count=4, size=100, workers=8, negative=8, window=5)
word2vec_model.wv.save_word2vec_format("../data/WordEmbedding/word2vec/words.vector", binary=True)
参考资料:
[1]word2vec原理(一) CBOW与Skip-Gram模型基础
[2]word2vec原理(二) 基于Hierarchical Softmax的模型
[3]word2vec原理(三) 基于Negative Sampling的模型
[4]word2vec前世今生
[5]不懂word2vec,还敢说自己是做NLP?
[6]超详细总结之Word2Vec(一)原理推导
[7] 技术干货 | 漫谈Word2vec之skip-gram模型
[8] 通俗理解word2vec
[10] word2vec 中的数学原理详解(一)目录和前言
[11] 技术干货 | 漫谈Word2vec之skip-gram模型
[15] word2vec是如何得到词向量的? - crystalajj的回答 - 知乎
[16] nlp中的词向量对比:word2vec/glove/fastText/elmo/GPT/bert
[17] Word2Vec教程 - Skip-Gram模型