Neural Turing Machine - 神经图灵机

Neural Turing Machine - 神经图灵机

论文原文地址: http://arxiv.org/pdf/1410.5401.pdf

一般的神经网络不具有记忆功能,输出的结果只基于当前的输入;而LSTM网络的出现则让网络有了记忆:能够根据之前的输入给出当前的输出。但是,LSTM的记忆程度并不是那么理想,对于比较长的输入序列,LSTM的最终输出只与最后的几步输入有关,也就是long dependency问题,当然这个问题可以由注意力机制解决,然而却不能从根本上解决长期记忆的问题,原因是由于LSTM是假设在时间序列上的输入输出:由t-1时刻得到t时刻的输出,然后再循环输入t时刻的结果得到t+1时刻的输出,这样势必会使处于前面序列的输入被淹没,导致这部分记忆被“丢掉“。

神经图灵机通过引入外部记忆解决了这个问题。 举个简单的例子,我们人类在记忆一些事情的时候,除了用脑袋记,还会写在备忘录上,当我们想不起来的时候,就可以去翻阅备忘录,从而获得相关的记忆。神经图灵机模仿人类记忆的过程:其中的控制器(controller)相当于我们人类的大脑,用于把输入事物的特征提取出来;外部记忆(memory)相当于我们的备忘录,把事物的特征记录在上面,那么完整的过程就是:控制器将当前输入转化为特征,写入记忆,再读取与当前输入特征有关的记忆作为最后的输出。整个过程与图灵机的读写很像,只不过神经图灵机这里让所有的读写操作都可微分化,因此可以用神经网络误差后向传播的方式去训练模型。

那么问题就来了,当获得一个输入的特征后,我们如何确定在记忆中储存的位置,而且如何从记忆中获取与当前输入相关的信息呢?这就是接下来要分析的神经图灵机主要工作。

Neural Turning Machine

1. 读记忆 (Read Heads)

我们把记忆看作是一个$N × M$的矩阵$M_t$,t表示当前时刻, 表示记忆会随着时间发生变化。我们的读过程就是生成一个定位权值向量$w_t$,长度为$N$,表示N个位置对应的记忆权值大小,最后读出的记忆向量$r_t$为:

$$r_t= \displaystyle\sum^N_i{w_t(i)M_t(i)}$$

其中权值向量的和为1: $\sum_i{W_t(i)}=1$,本质上是一个对N条记忆进行一个加权求和的思想。

2. 写记忆(Write Heads)

神经图灵机的写过程参考了LSTM的门的概念:先用输入门决定增加的信息,再用遗忘门决定要丢弃的信息,最后用更新门加上增加的信息并减去丢弃的信息。具体来说,神经图灵机会生成一个擦除向量$e_t$ (erase vector) 和一个增加向量$a_t$ (add vector),长度都为$N$,向量中每个元素的值大小范围从0到1,表示要增加或者删除的信息。对于写记忆过程,神经图灵机首先执行一个擦除操作,擦除程度的大小同样由向量$w_t$决定:

$$M_t^′=M_{t-1}(i)(1-w_t(i)e_t(i))$$

这个操作表示从$t?1$时刻的记忆中丢弃了一些信息,若$w_t$和$e_t$同时为0,则表示记忆没有丢弃信息,当前记忆与$t?1$时刻保持不变。执行完擦除后,然后执行增加操作:
$$M_t(i)=M_t^,(i)+w_t(i)a_t(i)a$$

这步表示在丢弃一些信息后需要新增的信息,同样,若$w_t$和$a_t$都为0,表示当前记忆无新增,与擦除后的记忆保持一致。其中,$e_t$和$a_t$都是由控制器给出,而控制器基本上由神经网络实现,可以是LSTM,也可以是MLP。

由于整个过程都是都是矩阵的加减乘除,所有的读写操作都是可微分的,因此我们可以用梯度下降法训练整个参数模型。但是接下来,我们需要确定$w_t$定位向量,由于这个向量直接决定着当前输入与记忆的相关性,因此神经图灵机在生成$w_t$向量上做了很多工作。

3. 定位机制(Addressing Mechanism)

关于决定其相关性的方法有很多,主要分为两大类: 基于内容的(content-based)和基于位置的(location-based)。神经图灵机结合了这两个方法提出一个定位机制用于生成定位向量$w_t$,具体来说,先用基于内容的方法,再用基于位置的方法。

3.1 Content-based Addressing

基于内容的定位计算主要基于余弦相似度:首先控制器给出一个$k_t$向量作为查询的key,然后计算$k_t$与$M_t$中各个记忆向量的余弦相似度,最后经过一个softmax操作得到基于内容的定位向量$w_t^c$:

$$w_t^c(i)=\frac{exp(\beta_tK[k_t,M_t(i)])}{\sum_jexp(\beta_tK[k_t,M_t(j)}$$

其中$K[..,.]$是余弦相似度计算:

$$K[u,v]=\frac{u?v}{||u||?||u||}$$

3.2 Location-based Addressing

3.2.1. Interpolation(插值)

控制器生成一个阈值$g_t$对当前的内容定位向量$w_t^c$与$t-1$时刻的定位向量$w_{t-1}$进行一个插值操作,插值的结果即为输出值$w_t^g$:

$$w_t^g=g_tw_t^c+(1-g_t)w_{t-1}$$

这里的插值操作可以理解为LSTM的更新门,结合过去的$w$权值计算新的$w$

3.2.2. shift(偏移)

对于$w_t^g$中的每个位置元素$w_t^g(i)$ ,我们考虑它相邻的k个偏移元素,认为这k个元素与$w_t^g(i)$相关,如当k=3时,三个相邻元素分别是:$w_t^g(i)$本身和位置偏移为1的元素$w_t^g(i-1)$和$w_t^g(i+1)$,此时,我们希望新的位置为i的元素能包含这三个元素,因此用一个长度为3的偏移权值向量$s_t$来表示这三个元素的权重,然后权值求和得到输出值$w_t^′$:

$$w_t^′(i)=\displaystyle\sum_{j=-1}^{1}{w_t^g(i+j)s(j+1)}$$

这里的偏移操作在原文中用的是循环卷积(circular convolution)公式表示的,我们可以理解为把向量$w_t^g$首尾相连形成一个环状,然后在环中用$s_t$作为卷积核做一维卷积操作。本质上是假设当前元素与相邻的偏移元素相关。

3.2.3. Sharping(重塑)

当偏移操作中的权值比较平均的时候,上述的卷积操作会导致数据的分散(dispersion)和泄漏(leakage),就像把一个点的信息分散在三个点中,权值如果太平均会使三个点包含的值太模糊(个人理解),因此需要把权值大小的区别进行强化,也就是sharping。具体来说,控制器生成一个参数$\gamma_t>1$,然后对各个权值进行$\gamma_t$指数然后归一化:

$$w_t(i)=\frac{w_t^′(i)^{\gamma_t}}{\sum_jw^′_t(j)^{\gamma_t}}$$

最后我们得出了最终的$w_t$用于提取和储存记忆。

Pytorch实现

我将原代码中最重要的NTM模块单独取出,并增加了如何简单使用的代码,读者可以直接下载加入到自己的模型中使用,代码已经上传到我的Github,点击这里查看————》NTM代码

这里代码基于的是pytorch-ntm,代码写的相当工整,可读性很高,这里只分析一些重要的步骤:

读过程

读过程就是从控制器(LTSM)输出的值提取我们需要的k, beta, g, s, gama值,然后调用_address_memory获得当前的定位权值向量w, 再用矩阵乘法获得读过程的输出 :

def forward(self, embeddings, w_prev):
    """NTMReadHead forward function.

    :param embeddings: input representation of the controller.
    :param w_prev: previous step state
    """
    o = self.fc_read(embeddings)
    k, beta, g, s, gama = _split_cols(o, self.read_lengths)

    # Read from memory
    w = self._address_memory(k, beta, g, s, gama, w_prev)
    r = self.memory.read(w)

    return r, w

 def read(self, w):
     """Read from memory (according to section 3.1)."""
     return torch.matmul(w.unsqueeze(1), self.memory).squeeze(1)

写过程

写过程同样是获得定位机制需要的k,beta, g, s, gama以及需要擦除的向量e和增加的向量a,然后调用_address_memory获得定位向量w,然后根据e和a计算得出最后的写入向量 :

def forward(self, embeddings, w_prev):
    """NTMWriteHead forward function.

    :param embeddings: input representation of the controller.
    :param w_prev: previous step state
    """
    o = self.fc_write(embeddings)
    k, beta, g, s, gama, e, a = _split_cols(o, self.write_lengths)

    # e should be in [0, 1]
    e = F.sigmoid(e)

    # Write to memory
    w = self._address_memory(k, beta, g, s, gama, w_prev)
    self.memory.write(w, e, a)

    return w

def write(self, w, e, a):
    """write to memory (according to section 3.2)."""
    self.prev_mem = self.memory
    self.memory = Variable(torch.Tensor(self.batch_size, self.N, self.M))
    erase = torch.matmul(w.unsqueeze(-1), e.unsqueeze(1))
    add = torch.matmul(w.unsqueeze(-1), a.unsqueeze(1))
    self.memory = self.prev_mem * (1 - erase) + add

Addressing Mechanism

定位机制的计算非常直观,首先_similarity方法计算余弦相似读获得wc,然后调用_interpolate与过去的w_prev进行插值操作,接着_shift偏移操作,这里实际上调用的是_convolve循环卷积方法,最后进行_sharpen操作获得最终的w :

def address(self, k, beta, g, s, gama, w_prev):

    # Content focus
    wc = self._similarity(k, beta)

    # Location focus
    wg = self._interpolate(w_prev, wc, g)
    w1 = self._shift(wg, s)
    w = self._sharpen(w1, gama)

    return w

def _similarity(self, k, beta):
    k = k.view(self.batch_size, 1, -1)
    w = F.softmax(beta * F.cosine_similarity(self.memory + 1e-16, k + 1e-16, dim=-1), dim=1)
    return w

def _interpolate(self, w_prev, wc, g):
    return g * wc + (1 - g) * w_prev

def _shift(self, wg, s):
    result = Variable(torch.zeros(wg.size()))
    for b in range(self.batch_size):
        result[b] = _convolve(wg[b], s[b])
    return result

def _sharpen(self, w1, gamma):
    w = w1 ** gamma
    w = torch.div(w, torch.sum(w, dim=1).view(-1, 1) + 1e-16)
    return w

def _convolve(w, s):
    """Circular convolution implementation."""
    assert s.size(0) == 3
    t = torch.cat([w[-1:], w, w[:1]])
    c = F.conv1d(t.view(1, 1, -1), s.view(1, 1, -1)).view(-1)
    return c

训练过程

首先输入一系列的数据,每次输入一个样本,都先后进行读和写过程,然后在不给定输入的情况下,获得一系列输出值,每次获得一个输出值时,同样先后进行着读和写过程;只不过输出的时候控制器接受的是0向量,而输入数据的时候控制器接受的是样本x值。我们可以根据输出的值与样本label的差距计算loss,对于copy任务来说,输入样本和label都是样本本身,损失可以使用binary entropy loss,最后梯度下降法更新整合模型参数:

def train_batch(net, criterion, optimizer, X, Y):
    """Trains a single batch."""
    optimizer.zero_grad()
    inp_seq_len = X.size(0)
    outp_seq_len, batch_size, _ = Y.size()

    # New sequence
    net.init_sequence(batch_size)

    # Feed the sequence + delimiter
    for i in range(inp_seq_len):
        net(X[i])

    # Read the output (no input given)
    y_out = Variable(torch.zeros(Y.size()))
    for i in range(outp_seq_len):
        y_out[i], _ = net()

    loss = criterion(y_out, Y)
    loss.backward()
    clip_grads(net)
    optimizer.step()

    y_out_binarized = y_out.clone().data
    y_out_binarized.apply_(lambda x: 0 if x < 0.5 else 1)

    # The cost is the number of error bits per sequence
    cost = torch.sum(torch.abs(y_out_binarized - Y.data))

    return loss.data[0], cost / batch_size

# 每次调用net(x)或者net()获得输出值的forward方法
def forward(self, x, prev_state):
    """NTM forward function.

    :param x: input vector (batch_size x num_inputs)
    :param prev_state: The previous state of the NTM
    """
    # Unpack the previous state
    prev_reads, prev_controller_state, prev_heads_states = prev_state

    # Use the controller to get an embeddings
    inp = torch.cat([x] + prev_reads, dim=1)
    controller_outp, controller_state = self.controller(inp, prev_controller_state)

    # Read/Write from the list of heads
    reads = []
    heads_states = []
    for head, prev_head_state in zip(self.heads, prev_heads_states):
        if head.is_read_head():
            r, head_state = head(controller_outp, prev_head_state)
            reads += [r]
        else:
            head_state = head(controller_outp, prev_head_state)
        heads_states += [head_state]

    # Generate Output
    inp2 = torch.cat([controller_outp] + reads, dim=1)
    o = F.sigmoid(self.fc(inp2))

    # Pack the current state
    state = (reads, controller_state, heads_states)

    return o, state

关于训练结果,可以去github里看,目前只有copy和deepcopy两个任务,应该是分开训练,但是按照前面分析的,神经图灵机应该是可以先后训练多个任务,并且保持新的任务不会覆盖旧的任务,从理论上分析,如果让记忆矩阵非常大,那么就可以把每个任务储存到记忆中不同的块中,保持记忆矩阵的稀疏性,是可以做到任务间不互相干涉,因此让模型达到能学习多个任务的能力。谷歌16年在Nature中提出的DNC其实也就是神经图灵机,论文里介绍了一些现在神经图灵机可以完成的通用任务,想了解神经图灵机具体应用的可以去看看。下面放出论文地址和代码地址:

神经图灵机(NTM):https://arxiv.org/abs/1410.5401

DNC: https://www.nature.com/articles/nature20101

参考代码:https://github.com/loudinthecloud/pytorch-ntm

————————————————
版权声明:本文为CSDN博主「ppp8300885」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ppp8300885/article/details/80383246

原文地址:https://www.cnblogs.com/jinchengll/p/11766377.html

时间: 2024-10-08 03:16:02

Neural Turing Machine - 神经图灵机的相关文章

Neural Turing Machines-NTM系列(三)ntm-lasagne源码分析

Neural Turing Machines-NTM系列(三)ntm-lasagne源码分析 在NTM系列文章(二)中,我们已经成功运行了一个ntm工程的源代码.在这一章中,将对它的源码实现进行分析. 1.网络结构 1.1 模块结构图 在图中可以看到,输入的数据在经过NTM的处理之后,输出经过NTM操作后的,跟之前大小相同的数据块.来看下CopyTask的完整输出图: 图中右侧的Input是输入数据,Output是目标数据,Prediction是通过NTM网络预测出来的输出数据,可以看出预测数据

Neural Turing Machines-NTM系列(一)简述

Neural Turing Machines-NTM系列(一)简述 NTM是一种使用Neural Network为基础来实现传统图灵机的理论计算模型.利用该模型,可以通过训练的方式让系统"学会"具有时序关联的任务流. 论文:http://arxiv.org/abs/1410.5401 中文翻译:http://www.dengfanxin.cn/?p=60 ppt:http://llcao.net/cu-deeplearning15/presentation/NeuralTuringMa

神经网络图灵机(Neural Turing Machines, NTM)

近期,Google Deep Mind团队提出了一个机器学习模型,并起了一个特别高大上的名字:神经网络图灵机,我为大家翻译了这篇文章,翻译得不是特别好,有些语句没读明白,欢迎大家批评指正  原论文出处:http://arxiv.org/pdf/1410.5401v1.pdf. 版权所有,禁止转载. 神经网络图灵机 Alex Graves [email protected]Greg Wayne [email protected]Ivo Danihelka [email protected] Goo

机器学习(Machine Learning)&amp;amp;深度学习(Deep Learning)资料

机器学习(Machine Learning)&深度学习(Deep Learning)资料 機器學習.深度學習方面不錯的資料,轉載. 原作:https://github.com/ty4z2008/Qix/blob/master/dl.md 原作作者會不斷更新.本文更新至2014-12-21 <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍非常全面.从感知机.神经网络.决策树.SVM.Adaboost到随机森林.Deep L

Attention and Augmented Recurrent Neural Networks

Attention and Augmented Recurrent Neural Networks CHRIS OLAHGoogle Brain SHAN CARTERGoogle Brain Sept. 8 2016 Citation: Olah & Carter, 2016 Recurrent neural networks are one of the staples of deep learning, allowing neural networks to work with seque

The Brain as a Universal Learning Machine

The Brain as a Universal Learning Machine This article presents an emerging architectural hypothesis of the brain as a biological implementation of a Universal Learning Machine.  I present a rough but complete architectural view of how the brain work

关于机器学习和深度学习的资料

声明:转来的,原文出处:http://blog.csdn.net/achaoluo007/article/details/43564321 编者按:本文收集了百来篇关于机器学习和深度学习的资料,含各种文档,视频,源码等.而且原文也会不定期的更新,望看到文章的朋友能够学到更多. <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost 到随机森林.Deep Learning. &

(转) 干货 | 图解LSTM神经网络架构及其11种变体(附论文)

干货 | 图解LSTM神经网络架构及其11种变体(附论文) 2016-10-02 机器之心 选自FastML 作者:Zygmunt Z. 机器之心编译  参与:老红.李亚洲 就像雨季后非洲大草原许多野生溪流分化成的湖泊和水洼,深度学习已经分化成了各种不同的专门架构. 并且,每个架构都会有一个图解,这里将详细介绍它们. 神经网络在概念上很简单,并且它们十分动人.在层级上,有着一堆同质化的元素和统一的单位,并且它们之间还存在在一系列的加权连接.这就是神经网络的所有,至少从理论上来说是这样.然而,时间

语音语义的深度学习

深度学习系列 | 诺亚面向语音语义的深度学习研究进展 编者:本文来自华为诺亚方舟实验室资深专家刘晓华在携程技术中心主办的深度学习Meetup中的主题演讲,介绍了华为诺亚面向语音语义的深度学习进展.关注“携程技术中心”微信公号(ctriptech),可获知更多技术分享信息哦. 本次演讲简要回顾了深度学习近十年进展,重点介绍华为诺亚方舟实验室最近两年内和深度学习相关的研究成果,并探讨了深度学习的未来趋势. 一.深度学习的近十年进展 深度学习为什么现在这么火?大数据,算法突破和计算能力.算法上有什么样