您的位置:首页 > 理论基础 > 计算机网络

记忆网络模型系列之End to End Memory Network

2018-01-19 21:55 453 查看
上文记忆网络介绍模型并非端到端的QA训练,该论文End-To-End Memory Networks就在上文的基础上进行端到端的模型构建,减少生成答案时需要事实依据的监督项,在实际应用中应用意义更大。

本文分为三个部分,分别是数据集处理、论文模型讲解及模型构造、模型训练。主要参考代码为MemN2N

数据集处理

==

论文中使用了babi数据集,关于本数据集在文章Ask Me Anything: Dynamic Memory Networks for Natural Language Processing 阅读笔记及tensorflow实现中有详细介绍并有处理流程,因此在这里也不再赘述。

模型讲解及构建

模型的结构如下图所示。图(a)是单层的模型,图(b)是多层模型(三层)。



单层记忆网络

以图(a)为例,输入有两个部分,

使用输入集合S={x1,x2,...xi,...,xn}表示上下文知识,使用输入向量q表示问题,使用输出向量aˆ表示预测答案。记忆网络模型通过对上下文集合S和问题向量q的数学变换,得到对应于问题的答案。

首先,上下文集合S通过隐含层矩阵Embedding A∈Rd∗v 得到记忆向量的编码向量 。同样的,问题向量q通过隐含层矩阵Embedding B∈Rd∗v 得到问题向量的编码向量u,然后计算两者的内积:

pi=Softmax(uTmi)

其中,Softmax(zi=ezi/∑j),那么 pi 就为输入向量的概率。

然后,每个输入xi 都有一个输出向量 ci,ci 和 mi得到的方式是类似的,ci 是通过隐含层矩阵Embedding C∈Rd∗v 得到的。将 pi与ci 相乘求和,得到答案向量的编码向量o。

o=∑ipici

答案向量的编码向量o以后,需要解码生成预测的答案,通过一个待训练矩阵W∈Rd∗v ,得到预测答案aˆ 。

aˆ=Softmax(W(o+u))

多层记忆网络

如图(b)所示,多层记忆网络和单层的基本结构是类似的,有一些小的细节需要改变,以将几个单层网络连接起来。

1、将uk与ok相加作为下一层的问题编码,即:

uk+1=uk+ok

2、每一层都有嵌入矩阵Ak,Ck来将x映射到记忆单元和编码单元。但是这样参数数量就会随模型层数的增加呈倍数增长,为了减少参数数量,使训练能够方便进行,论文中提出了两种减少参数的方法:

2.1相邻的嵌入矩阵相同,这样比着之前减少了一般参数,即

Ak+1=Ck+1

WT=CK

B=A1

2.2层间共享参数,即

A1=A2=...=AK

C1=C2=...=CK

论文中也提到2.1的方式比2.2的方式训练效果要好很多。

模型构建代码

按照代码的逻辑捋一下训练时需要注意的重要参数:

story:[None,10,7] –Sentences最多有10句话,每句话最多有7个单词。

query:[None,7] –q问题最多有7个单词。

m_emb_A:[None,10,7,20] –story通过一个[vocab_size, embedding_size]的嵌入矩阵。

q_emb:[None,7,20] –query通过一个[vocab_size,embedding_size]的嵌入矩阵。

u_0:[None,20] –q_emb通过位置编码,具体细节详见4.1章,得到u_0代表问题的向量表示。

u_temp:[None,1,20] –u_0拓展维度变为[None,20,1],并且将第一维和第二维进行transpose得到[None,1,20]。

m_A:[None,10,20] –得到10句话的向量表示。

dotted:[None,10] –将u_temp与m_A点乘,并求和,得到记忆单元中10句话的权重。

probs:[None,10] –得到softmax概率。

probs_temp:[None,1,10]

m_emb_C:[None,10,7,20] –同m_emb_A

m_C:[None,10,20] –同m_A

c_temp:[None,20,10]

o_k:[None,20] –得到输出编码向量

with tf.variable_scope(self._name):
# Use A_1 for thee question embedding as per Adjacent Weight Sharing
# 将问题变量queries通过嵌入矩阵A_1得到问题向量q_emb
# 然后将q_emb与其位置编码变量_encoding加权求和得到u_0
# self._encoding是位置编码向量,就是对词出现的顺序进行编码,具体细节详见4.1章
q_emb = tf.nn.embedding_lookup(self.A_1, queries)
u_0 = tf.reduce_sum(q_emb * self._encoding, 1)
u = [u_0]

# 总共三层,待训练的参数有四个矩阵,分别是A_1,C_1,C_2,C_3
for hopn in range(self._hops):
# 对于第一层,记忆单元的嵌入矩阵为A_1
if hopn == 0:
m_emb_A = tf.nn.embedding_lookup(self.A_1, stories)
m_A = tf.reduce_sum(m_emb_A * self._encoding, 2)
# 对于第二层和第三层,记忆单元的嵌入矩阵分别为C_1和C_2
else:
with tf.variable_scope('hop_{}'.format(hopn - 1)):
m_emb_A = tf.nn.embedding_lookup(self.C[hopn - 1], stories)
m_A = tf.reduce_sum(m_emb_A * self._encoding, 2)

# hack to get around no reduce_dot
u_temp = tf.transpose(tf.expand_dims(u[-1], -1), [0, 2, 1])
dotted = tf.reduce_sum(m_A * u_temp, 2)

# Calculate probabilities
probs = tf.nn.softmax(dotted)

probs_temp = tf.transpose(tf.expand_dims(probs, -1), [0, 2, 1])
with tf.variable_scope('hop_{}'.format(hopn)):
m_emb_C = tf.nn.embedding_lookup(self.C[hopn], stories)
m_C = tf.reduce_sum(m_emb_C * self._encoding, 2)

c_temp = tf.transpose(m_C, [0, 2, 1])
o_k = tf.reduce_sum(c_temp * probs_temp, 2)

# Dont use projection layer for adj weight sharing
# u_k = tf.matmul(u[-1], self.H) + o_k

u_k = u[-1] + o_k

# nonlinearity
if self._nonlin:
u_k = nonlin(u_k)

u.append(u_k)

# Use last C for output (transposed)
with tf.variable_scope('hop_{}'.format(self._hops)):
return tf.matmul(u_k, tf.transpose(self.C[-1], [1,0]))


模型训练

模型训练部分就是一些熟悉的代码,这里不再赘述,大概经过100个epochs的训练,训练效果如下:



总体来说,端到端的记忆网络的提出,使记忆网络变得更加实用,不再需要对支持事实这一监督项,因此可用的数据集就变得更多。本篇代码使用的babi数据集,训练集和测试集各1000个,词表总共才30个,因此是一个极度简单的模型。因此在接下来的几篇文章中,将会采用较大的数据集对记忆网络以后发展的模型进行说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: