Word2Vec已经几乎成为NLP任务中,肯定会用到的模型,当然现在我们有了更新的Elmo和Bert,但是Word2Vec作为基本的词向量,仍然需要弄明白。
当我们处理文本的时候,我们首先需要将这些文本进行表示,以前大家常用的就是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、任意两个词之间都是孤立的,无法表示语义层面上词汇之间的相关信息,而这一点是致命的。
针对Onehot的问题,大家首先想到的就是能不能用比较短的,稠密非稀疏的向量来表示词。中间提出了很多方法,其中一个就是Word2Vec。我们之前做过完形填空,都是利用上下文语义来判断选择哪个答案。所以一个词的语义可以由上下文来表征。
借此,人们提出了词的分布式表示(distributed representation)。Onehot是将一个词用一些高维稀疏向量表示出来,而分布式表示,就是将一个词映射到一个比较短的非稀疏向量中。
基于神经网络的分布表示又称为词向量或者词嵌入。 2001年, Bengio 等人正式提出神经网络语言模型( Neural Network Language Model ,NNLM),该模型在学习语言模型的同时,也得到了词向量。
典型的神经网络语言模型(NNLM):
直到Word2Vec模型词向量才真正被我们所关注。
CBOW:上下文来预测当前词语;
Skip-gram:当前词来预测上下文。
CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
CBOW(Continuous Bag-of-Word Model),即连续词袋模型,通过上下文来预测当前词语。
假设 Corpus:{I drink coffee everyday}, Window_size:2 ,Target : Coffee
Skip-gram,用当前词来预测预测上下文。我当时看到的时候是感觉非常荒谬的,如何才能用一个词来预测他真的上下文。接下来我们将用多种方式实现,到具体的案例中就容易理解了。
我们所用的数据来自Cornell大学的电影评论数据。关于数据的下载和导入不再列出,主要写下数据处理的格式和模型的搭建。同其他NLP任务一样,我们首先要建立字典然后将其数字化。
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))
通过gensim可以直接训练word2vec,下面介绍各个参数。
gensim.models.Word2Vec():
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模型