图学习参考资料 词向量word2vec( 七 )

3.2网络定义定义skip-gram的网络结构,用于模型训练 。在飞桨动态图中,对于任意网络,都需要定义一个继承自fluid.dygraph.Layer的类来搭建网络结构、参数等数据的声明 。同时需要在forward函数中定义网络的计算逻辑 。值得注意的是,我们仅需要定义网络的前向计算逻辑,飞桨会自动完成神经网络的后向计算,代码如下:
#这里我们使用的是paddlepaddle的1.8.0版本#一般来说,在使用fluid训练的时候,我们需要通过一个类来定义网络结构,这个类继承了fluid.dygraph.Layerclass SkipGram(fluid.dygraph.Layer):def __init__(self, vocab_size, embedding_size, init_scale=0.1):#vocab_size定义了这个skipgram这个模型的词表大小#embedding_size定义了词向量的维度是多少#init_scale定义了词向量初始化的范围,一般来说,比较小的初始化范围有助于模型训练super(SkipGram, self).__init__()self.vocab_size = vocab_sizeself.embedding_size = embedding_size#使用paddle.fluid.dygraph提供的Embedding函数,构造一个词向量参数#这个参数的大小为:[self.vocab_size, self.embedding_size]#数据类型为:float32#这个参数的名称为:embedding_para#这个参数的初始化方式为在[-init_scale, init_scale]区间进行均匀采样self.embedding = Embedding(size=[self.vocab_size, self.embedding_size],dtype='float32',param_attr=fluid.ParamAttr(name='embedding_para',initializer=fluid.initializer.UniformInitializer(low=-0.5/embedding_size, high=0.5/embedding_size)))#使用paddle.fluid.dygraph提供的Embedding函数,构造另外一个词向量参数#这个参数的大小为:[self.vocab_size, self.embedding_size]#数据类型为:float32#这个参数的名称为:embedding_para_out#这个参数的初始化方式为在[-init_scale, init_scale]区间进行均匀采样#跟上面不同的是,这个参数的名称跟上面不同,因此,#embedding_para_out和embedding_para虽然有相同的shape,但是权重不共享self.embedding_out = Embedding(size=[self.vocab_size, self.embedding_size],dtype='float32',param_attr=fluid.ParamAttr(name='embedding_out_para',initializer=fluid.initializer.UniformInitializer(low=-0.5/embedding_size, high=0.5/embedding_size)))#定义网络的前向计算逻辑#center_words是一个tensor(mini-batch),表示中心词#target_words是一个tensor(mini-batch),表示目标词#label是一个tensor(mini-batch),表示这个词是正样本还是负样本(用0或1表示)#用于在训练中计算这个tensor中对应词的同义词,用于观察模型的训练效果def forward(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计算和cross entropy合并成一步计算可以更好的优化,所以输入的是word_sim,而不是predloss = fluid.layers.sigmoid_cross_entropy_with_logits(word_sim, label)loss = fluid.layers.reduce_mean(loss)#返回前向计算的结果,飞桨会通过backward函数自动计算出反向结果 。return pred, loss3.3网络训练完成网络定义后,就可以启动模型训练 。我们定义每隔100步打印一次Loss,以确保当前的网络是正常收敛的 。同时,我们每隔10000步观察一下skip-gram计算出来的同义词(使用 embedding的乘积),可视化网络训练效果,代码如下:

经验总结扩展阅读