介绍词向量word2evc概念,及CBOW和Skip-gram的算法实现( 八 )


defforward(self,center_words,target_words,label):
#首先 , 通过embedding_para(self.embedding)参数 , 将mini-batch中的词转换为词向量
#这里center_words和eval_words_emb查询的是一个相同的参数
#而target_words_emb查询的是另一个参数
center_words_emb=self.embedding(center_words)
target_words_emb=self.embedding_out(target_words)
#center_words_emb=[batch_size,embedding_size]
#target_words_emb=[batch_size,embedding_size]
#我们通过点乘的方式计算中心词到目标词的输出概率 , 并通过sigmoid函数估计这个词是正样本还是负样本的概率 。
word_sim=fluid.layers.elementwise_mul(center_words_emb,target_words_emb)
word_sim=fluid.layers.reduce_sum(word_sim,dim=-1)
word_sim=fluid.layers.reshape(word_sim,shape=[-1])
pred=fluid.layers.sigmoid(word_sim)
#通过估计的输出概率定义损失函数 , 注意我们使用的是sigmoid_cross_entropy_with_logits函数
#将sigmoid计算和crossentropy合并成一步计算可以更好的优化 , 所以输入的是word_sim , 而不是pred
loss=fluid.layers.sigmoid_cross_entropy_with_logits(word_sim,label)
loss=fluid.layers.reduce_mean(loss)
#返回前向计算的结果 , 飞桨会通过backward函数自动计算出反向结果 。
returnpred,loss
3.3网络训练
完成网络定义后 , 就可以启动模型训练 。 我们定义每隔100步打印一次Loss , 以确保当前的网络是正常收敛的 。 同时 , 我们每隔10000步观察一下skip-gram计算出来的同义词(使用embedding的乘积) , 可视化网络训练效果 , 代码如下:
#开始训练 , 定义一些训练过程中需要使用的超参数
batch_size=512
epoch_num=3
embedding_size=200
step=0
learning_rate=0.001
#定义一个使用word-embedding查询同义词的函数
#这个函数query_token是要查询的词 , k表示要返回多少个最相似的词 , embed是我们学习到的word-embedding参数
#我们通过计算不同词之间的cosine距离 , 来衡量词和词的相似度
#具体实现如下 , x代表要查询词的Embedding , Embedding参数矩阵W代表所有词的Embedding
#两者计算Cos得出所有词对查询词的相似度得分向量 , 排序取top_k放入indices列表
defget_similar_tokens(query_token,k,embed):
W=embed.numpy()
x=W[word2id_dict[query_token]]
cos=np.dot(W,x)/np.sqrt(np.sum(W*W,axis=1)*np.sum(x*x)+1e-9)
flat=cos.flatten()
indices=np.argpartition(flat,-k)[-k:]
indices=indices[np.argsort(-flat[indices])]
foriinindices:
print('forword%s,thesimilarwordis%s'%(query_token,str(id2word_dict[i])))
#将模型放到GPU上训练(fluid.CUDAPlace(0)) , 如果需要指定CPU , 则需要改为fluid.CPUPlace()
withfluid.dygraph.guard(fluid.CUDAPlace(0)):
#通过我们定义的SkipGram类 , 来构造一个Skip-gram模型网络
skip_gram_model=SkipGram(vocab_size,embedding_size)
#构造训练这个网络的优化器
adam=fluid.optimizer.AdamOptimizer(learning_rate=learning_rate,parameter_list=skip_gram_model.parameters())
#使用build_batch函数 , 以mini-batch为单位 , 遍历训练数据 , 并训练网络
forcenter_words,target_words,labelinbuild_batch(
dataset,batch_size,epoch_num):
#使用fluid.dygraph.to_variable函数 , 将一个numpy的tensor , 转换为飞桨可计算的tensor
center_words_var=fluid.dygraph.to_variable(center_words)
target_words_var=fluid.dygraph.to_variable(target_words)
label_var=fluid.dygraph.to_variable(label)
#将转换后的tensor送入飞桨中 , 进行一次前向计算 , 并得到计算结果
pred,loss=skip_gram_model(
center_words_var,target_words_var,label_var)
#通过backward函数 , 让程序自动完成反向计算
loss.backward()