前两天在看MemN2N的代码,自己动手又实现了一遍,收获挺多,自己也写了挺多注释,应该对理解有帮助,而且之后的Gate MemNN、KVMemNN等Memory Network都可以在此基础上进行改进,需要的同学自取:
caijie12138/Memory-Networksgithub.com
前言
在Memory Networks这个大家庭中有很多成员,我们介绍了MemN2N,GMemNN(给神经网络增强记忆|一文看懂Gate Memory NN的原理与实现),今天我们来聊聊从阅读文章开始就能回答问题的KV-MemNN模型。
论文地址:Key-Value Memory Networks for Directly Reading Documents
基于Knowledge Base(KB)的问答在限定域问答系统中是很有效的,但是在开放域问答就不是很适用(由于数据的稀疏性等原因无法创建一个包含所有领域的KB),那为啥不能根据具体的文章建立具体的KB,从而实现针对各领域的问答呢(感觉ELMo解决词向量多义性问题的思路和这个有点像,根据具体的上下文来fine-tuning词向量)?
我们都知道结构化数据相比纯文本数据有很多优点:直接、无歧义以及多文本之间会有关联。因此在结构化数据中寻找问题的答案比在纯文本中寻找会容易得多。聊完这些想必你已经对KV-MemNN要做的事有了一个感性的认识,接下来正式开始理性部分:
1. KV-MemNN
按照惯例还是先上模型图:
增加了KV memories,addressing部分主要用到的是memories的key部分,reading部分主要用到的是memories的value部分,整个模型能够带着转换过程整体训练。
模型是基于我们上一篇文章中提到的MemN2N(蔡杰:Memory Networks之MemN2N)的。在MemN2N中我们只是简单的把context线性变换成了一个整体的memory,而KV-MemNN的不同之处在于将其中的memory变成了(key, value)键值对,操作memory的方式变成了以下的步骤:
1.1 Key Hashing
由于Key-Value Memories来源于Knowledge Source,因此memories的数量会很庞大,但是大部分都是和当前query无关的记忆,所以需要先大部分无关的memories,这个过程就是Key Hashing。原文在这里使用的是倒排索引的方法,选择一个大小为N的k-v对集合,还要在消除停用词的情况下(出现频率<F = 1000)保证key对应的单词在query中出现。原文如下:
1.2 Key Addressing
Addressing阶段主要是利用Hashing的结果(candidate memories)去和query经过线性变换后的结果计算一个相关概率(relevance probability):
query使用x表示,phiX和phiK是一个D维的feature maps(在后面会有介绍),A是一个dxD的矩阵,k_hi是kv-memories中的第hi项
1.3 Value Reading
在文章中,key被设计的和query相关,value被设计的和answer相关,所以使用Addressing得到的probability和kv中的v进行weight sum操作:
phiV和上面的phiX和phiK一样是一个D维的feature maps
之后和MemN2N一样要经过多个hop,因为query被表示为:
多个hop的q会变化,具体的操作如下(具体参见模型图):
R_1是一个可学习的dxd矩阵,在每一个hop j都使用不同的矩阵R_j
p_hi也根据更新后的q进行更新:
最后的计算答案步骤:
H表示一共经过H个hop,B与A类似是一个可学习矩阵
2. Key-Value Memories
之前提到转换query和candidates的phi_x和phi_y,文中表明为了简单起见用的是BoW(Bag-of-words)。主要的探索还是在phi_k和phi_v上,这两个值作者尝试了以下几种形式:
2.1 KB Triple
该方式就是简单的“subject-relation-object”的形式,可以看如下例子:
此外,作者还把知识库做了一个double,考虑了实体之间的逆向关系,比如“Blade Runner directed_by Ridley Scott”还可以表示为“Ridley Scott !directed_by Blade Runner”。有了这样的两对实体关系之后,可以适应不同类型的问句(“Who directed Blade Runner?” vs. “What did Ridley Scott direct?”)。
2.2 Sentence Level
之前的方法是从文本中抽取出kv对,存到memory slots中。Sentence Level的思想是把文章分成一句句话,每一句话抽取出一个kv对,其中k和v都是用整个句子的BoW来表示,这个方法其实就是MemN2N的用法。
2.3 Window Level
一篇文章可以划分为多个大小为W的window,将window的方法用于MemN2N也有不错的效果,但是本文中作者使用的是将每个window的BoW表示作为key,每个window的center word作为value,因为每个问题和window内的句子具有更强的关联性。
2.4 Window + Center Encoding
相当于是对上一种方法的扩展,首先把dictionary的大小加倍,通过加倍后的字典重新对key和value进行编码,作者说这样有助于找出中心词与其周围词的相关性。
2.5 Window + Title
文章的标题通常是和文章相关问题的答案,比如“What did Harrison Ford star in?”可以通过“Blade Runner”这个标题来回答。所以作者在之前Window Level的基础上添加了新的kv对,其中key还是用整个window的BoW,value使用title来表示,使用“_window_” or “_title_”来区分两种不同的kv对。
3. Experiment
数据集简介如下:
实验对比了几种流行的模型,其中Key-Value Memory Network达到了最好效果。
4. 基于Keras的实现
核心代码:
https://zhuanlan.zhihu.com/p/59043894
需要代码的朋友自取: