word2vec之Skip-Gram模型的tensorflow实现

gensim里内置了word2vec模型,训练和使用都很方便。但word2vec自己这个模型的设计是很精妙的,本身从头使用tensorflow实现一遍颇有意义。python

http://mattmahoney.net/dc/text8.zip
python能够直接读zip文件,里边是一个命名为text8的文件,约100M,总共就一行,以
空格分词
from aipack.datasets import text8
words = text8.load_text8_dataset()#就是词列表,约1700W
data_size = len(words)
print(data_size)  # 17005207
print(words[0:10])  # ['anarchism', 'originated', 'as', 'a', 'term', 'of', 'abuse', 'first', 'used', 'against']

data, count, dictionary, reverse_dictionary = build_words_dataset(words, vocabulary_size=50000)
#下标,词频dict,词序dict,序对词didct
print('Most 5 common words (+UNK)', count[:5])
print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])

读进来的text8约有1700W个词,排重后获得25W+个词,咱们只保留50000个高频的,其他用UNK代替。数组

build_words_dataset返回:data:词的下标list,count:{词:词频},dictionary:{词:词下标},reverse_dictionary:{词下标:词}函数

有了原始的数据集,那就能够开始建模。ui

Word2Vec模型中,主要有Skip-Gram和CBOW两种模型,从直观上理解,Skip-Gram是给定input word来预测上下文。而CBOW是给定上下文,来预测input word,以下图:人工智能

 

batch, labels, data_index = generate_skip_gram_batch(data=data,batch_size=8,num_skips=4,skip_window=2,data_index=0)

data就是以前取出来的word_list的下标数组,每批取的pair数batch_size=8,num_skip=4是以这个词为中心,取对的次数.net

skip_window=2,是以当前词为中心,先后两个词(往前看包含当前词自己)。设计

下面是建模,官方示例损失函数用到了以下这个:orm

def nce_loss(vocab_size,embedding_size,embed,train_labels,num_sampled):
    # 模型内部参数矩阵,初始为截断正太分布
    nce_weight = tf.Variable(tf.truncated_normal([vocab_size, embedding_size],
                                                      stddev=1.0 / math.sqrt(embedding_size)))
    nce_biases = tf.Variable(tf.zeros([vocab_size]))

    # 获得NCE损失(负采样获得的损失)
    loss = tf.nn.nce_loss(
        weights=nce_weight,  # 权重
        biases=nce_biases,  # 误差
        labels=train_labels,  # 输入的标签
        inputs=embed,  # 输入向量
        num_sampled=num_sampled,  # 负采样的个数
        num_classes=vocab_size  # 类别数目
    )
    print(loss)
    nce_loss = tf.reduce_mean(loss)
    return nce_loss

输入N*embedding_size的词嵌入以后的向量,与input_labels=[N,1]之间的loss。按常规状况,input_labels用one_hot得扩展成[N,vocab_size]维,但vocab_size-1维都是负样本。这样使用负采样,主要是减小计算量为[N,64]。ip

后面的训练就是正常输入数据,反向传播,迭代了。input

在迭代25W轮以后,看下类似度,仍是不错的:

从直观的视角,还原一下skip-gram的原理:

1,每批选择N个字的下标,对应的指望输出是这N个字周围的字(下标)。

2,对输入进行embedding,获得[N,embedding_size]的矩阵。

3,对这个embdding的结果,与指望输出[N,1]计算负采样损失。

 

关于做者:魏佳斌,互联网产品/技术总监,北京大学光华管理学院(MBA),特许金融分析师(CFA),资深产品经理/码农。偏心python,深度关注互联网趋势,人工智能,AI金融量化。致力于使用最前沿的认知技术去理解这个复杂的世界。

扫描下方二维码,关注:AI量化实验室(ailabx),了解AI量化最前沿技术、资讯。

相关文章
相关标签/搜索