R-Net模型tensorflow实现

本文详细介绍了R-Net模型在TensorFlow中的实现过程,包括输入输出的定义,RNN编码层,Question-Passage匹配层,Self-Matching Attention层以及Output Layer的Pointer-Net机制。内容涵盖RNN单元的定义,attention机制,self-attention机制,以及如何通过 Pointer-Net 指示答案的起始和结束位置。
摘要由CSDN通过智能技术生成

R-Net模型tensorflow实现过程

输入输出

在搭建模型之前,先弄清楚模型的输入输出,并采用tensorflow中的占位符预留位置:
在R-Net模型中
输入内容为:文段p和问题q
输出内容为答案的初始位置s和结束位置e:

  • 输入:R-Net 模型将利用Glove作embedding处理的句子p、q作为输入,每次输入batch_size个p矩阵*(形状为[p_length,embedding_dim])和q矩阵(形状为[q_length,embedding_dim])*
# -输入
paragraph = tf.placeholder(
shape=
[opts['batch_size'], opts['p_length'], opts['word_emb_dim']], 
dtype=tf.float32)

question = tf.placeholder(
shape=
[opts['batch_size'], opts['q_length'], opts['word_emb_dim']], 
dtype=tf.float32)
  • 输出:模型以答案开始位置的下标s和结束的下标e作为输出,每次输出batch_size个答案,每个答案用one_hot形式表示,于是输出batch_size个s或e的one_hot矩阵*(由于答案要从文章p中选取下标,one_hot的长度为文章p的长度p_length)*。采用占位符的表示形式如下
 # -输出
 answer_si = tf.placeholder(
 shape=[opts['batch_size'], opts['p_length']],
 dtype=tf.float32)
 
 answer_ei = tf.placeholder(
 shape=[opts['batch_size'], opts['p_length']],
 dtype=tf.float32)

Layer1: Question and Paragraph Encoding Layer

限于计算能力,本层没有考虑字符串级别的编码,直接将经过embedding处理的文段paragraph和问题question作为模型的输入

print("Layer1: Question and Paragraph Encoding Layer")
# 省略了字符级别的embedding
eQcQ = question
ePcP = paragraph

接着,Encoding层采用一个RNN网络对文段paragraph(eQcQ)和问题question(ePcP)进行了编码:

  • 变形
    我们希望RNN编码顺着文段p和问题q的步长(timestep)逐层进行,好让RNN的最后一层能够包含整个句子的特征,然而,目前的文本张量以batch_size作第一个维度(形状为[b,q,d]或者[b,p,d], 后续用b表示batch_size、用q表示q_length、p表示p_length,d表示embedding_dim,h表示hidden_size),我们需要在将eQcQ和ePcP放进RNN之前对它们作变形操作,使张量以q_length或者p_length作为第一个维度。
    具体的操作过程如下:
# [ batch,q_length,dim] => q_length 个 [batch,dim]
unstacked_eQcQ = tf.unstack(value=eQcQ, axis=1) 

tf.unstack函数旨在将axis上指定的维度分解出来,形如[b,q,d]的张量在unstack之后会变成[[b,d],[b,d],[b,d]…[b,d],[b,d]] 共q个[b,d]张量。所以变形之后得到的会是一个以q开头的张量[q,b,d]让RNN能够在q方向上进行编码

对paragraph文本作相同的unstack操作

unstacked_ePcP = tf.unstack(value=ePcP, axis=1) 
  • 定义RNN单元
    在tensorflow定义RNN的过程中,先要定义RNN的单元,此过程可以借助tensorflow库函数完成:
cell = tf.nn.rnn_cell.BasicLSTMCell(hidden_size, 
       forget_bias=1.0, state_is_tuple=True, name=name)

在定义cell的基础上我们给cell添加上用于正则化的dropout层,最终将这一步骤封装成一个函数用于之后定义其它单元:
注意:定义cell的步骤需要在 with tf.variable_scope("xxx"):的作用域下,否则,在下一次定义cell时会报错

 def DropoutWrappedLSTMCell(self, hidden_size, in_keep_prob, name=None):
        cell = tf.nn.rnn_cell.BasicLSTMCell(hidden_size, forget_bias=1.0, state_is_tuple=True, name=name)
        cell = tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=in_keep_prob)
        return cell

借助上述定义的DropoutWrappedLSTMCell函数,给RNN定义正想和反向的RNN单元,实现双向神经网络

stacked_enc_fw_cells = [self.DropoutWrappedLSTMCell(
                hidden_size=opts["hidden_size"],
                in_keep_prob=opts["in_keep_prob"]) 
				# 包含两个forward LSTM 单元的列表
                
stacked_enc_bw_cells = [self.DropoutWrappedLSTMCell(
                hidden_size=opts["hidden_size"],
                for _ in range(2)]  
                # 包含两个backward LSTM 单元的列表
                
  • 编码
    编码过程可以借助 tf.contrib.rnn.stack_bidirectional_rnn函数实现,最终输出神经网络的整个序列([q,b,2h])和 正向末状态([b,h]),反向末状态由于此处实现的是双向神经网络,完整序列的形状末尾为2h*
    对于问题q:
q_enc_outputs, q_enc_final_fw, q_enc_final_bw = 
tf.contrib.rnn.stack_bidirectional_rnn(
                stacked_enc_fw_cells, 
				unstacked_eQcQ,
				dtype=tf.float32, 
				scope="context_encoding")

对文章p作类似操作

p_enc_output, p_enc_fianl_fw, p_enc_final_bw = 
tf.contrib.rnn.stack_bidirectional_rnn(
                stacked_enc_fw_cells, 
				unstacked_ePcP, 
				dtype=tf.float32, scope="context_encoding"
            ) 
  • 还原
    最终将在第一步中变换为(q,b,d)和(p,b,d)的问题和文段利用stack操作*(unstack的逆操作,将列表合并到axis指定的维度上)*还原为(b,q/p,2h)经过RNN后原本以d结尾的张量变成了以2h结尾
u_Q = tf.stack(q_en
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值