前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >递归神经网络不可思议的有效性(下)

递归神经网络不可思议的有效性(下)

作者头像
用户1737318
发布2018-06-05 14:38:57
4960
发布2018-06-05 14:38:57
举报
文章被收录于专栏:人工智能头条人工智能头条

代数几何(Latex)

以上结果表明,该模型在学习复杂句法结构方面表现得相当不错。这些结果令人印象深刻,我的实验伙伴( Justin Johnson )和我打算在结构上再深入研究,我们使用这本关于代数栈/几何的 书 。我们下载了Latex的源文件(16MB),然后训练了一个多层的LSTM。令人惊讶的是,由Latex产生的样本几乎是已经汇总好了的。我们不得不介入并手动修复了一些问题,这样你就得到了合理的数学推论,这是相当惊人的:

代数几何样本(假的), 真正的PDF文件在这 。

这是另一份样本:

产生了更多假的代数几何,尝试处理图像(右)

正如上面你所看到的那样,有些时候这个模型试图生成LaTeX图像,但很明显它并不明白图像的具体意思。同样我很喜欢模型选择跳过证明过程的那部分(“Proof omitted”,左上角)。当然,Latex有相对困难的结构化句法格式,我自己都还没有完全掌握。为举例说明,下面是模型中的一个原始样本(未被编辑):

代码语言:javascript
复制
\begin{proof}
We may assume that $\mathcal{I}$ is an abelian sheaf on $\mathcal{C}$.
\item Given a morphism $\Delta : \mathcal{F} \to \mathcal{I}$
is an injective and let $\mathfrak q$ be an abelian sheaf on $X$.
Let $\mathcal{F}$ be a fibered complex. Let $\mathcal{F}$ be a category.
\begin{enumerate}
\item \hyperref[setain-construction-phantom]{Lemma}
\label{lemma-characterize-quasi-finite}
Let $\mathcal{F}$ be an abelian quasi-coherent sheaf on $\mathcal{C}$.
Let $\mathcal{F}$ be a coherent $\mathcal{O}_X$-module. Then
$\mathcal{F}$ is an abelian catenary over $\mathcal{C}$.
\item The following are equivalent
\begin{enumerate}
\item $\mathcal{F}$ is an $\mathcal{O}_X$-module.
\end{lemma}

这份样本来自一个相对合适的模型,其中显示出了一些常见错误。比如,模型打开了一个\begin{proof}环境,但是却以\end{lemma}结束。这个问题我们必须手动修复,这可能是由于依赖关系太长而导致的:当这个模型做完了 proof过程,它就忘记了它是在做proof还是lemma了。同样的,当模型打开了一个\begin{enumerate}环境,然后却忘记关闭它了。我们发现,当我们使用更大/更好的模型的时候,这种情况出现得就较少了,尽管如此,这些问题还是会出现。

Linux源代码

我想看看这个模型处理结构化数据的极限,所以为了这一终极目标,我打算开始编写一些代码,特别的,我浏览了 Github上Linux repo 所有的原始资料和头文件,把它们串在一起形成一个单一的巨大文件(474MB大小的C代码)(我本来打算只训练内核,但是它只有16MB)。然后,我花了几天时间训练出了大小刚好适合我GPU的3层LSTM网络。这些模型有大约1000万个参数,然而这对于RNN网络来说还是微不足道的。结果非常有趣:

代码语言:javascript
复制
/*
 * Increment the size file of the new incorrect UI_FILTER group information
 * of the size generatively.
 */
static int indicate_policy(void)
{
  int error;
  if (fd == MARN_EPT) {
    /*
     * The kernel blank will coeld it to userspace.
     */
    if (ss->segment < mem_total)
      unblock_graph_and_set_blocked();
    else
      ret = 1;
    goto bail;
  }
  segaddr = in_SB(in.addr);
  selector = seg / 16;
  setup_works = true;
  for (i = 0; i < blocks; i++) {
    seq = buf[i++];
    bpf = bd->bd.next + i * search;
    if (fd) {
      current = blocked;
    }
  }
  rw->name = "Getjbbregs";
  bprm_self_clearl(&iv->version);
  regs->new = blocks[(BPF_STATS << info->historidac)] | PFMR_CLOBATHINC_SECONDS << 12;
  return segtable;
}

这代码整体上看起来非常棒。我认为它不会马上就能编译通过,但是当你滚动查看这些代码的时候给你的感觉是这是一个非常强大的C代码库。注意到,RNN到处随机生成代码片段和注释。它很少会犯语法错误。比如,它适当的使用了字符类型、指针概念等。同样它正确打开和关闭了代码块{[,并且学习将代码缩进。一处常见的错误就是它不能跟踪变量名:它常常会使用未定义的变量(比如上面出现的rw),或者声明它从来不用的变量(比如上面的int error),或者返回一个不存在的变量。让我们来看看更多的案例。下面是另外一个代码片段,显示了RNN学习操作数组的情况:

代码语言:javascript
复制
/*
 * If this error is set, we will need anything right after that BSD.
 */
static void action_new_function(struct s_stat_info *wb)
{
  unsigned long flags;
  int lel_idx_bit = e->edd, *sys & ~((unsigned long) *FIRST_COMPAT);
  buf[0] = 0xFFFFFFFF & (bit << 4);
  min(inc, slist->bytes);
  printk(KERN_WARNING "Memory allocated x/x, "
    "original MLL instead\n"),
    min(min(multi_run - s->len, max) * num_data_in),
    frame_pos, sz + first_seg);
  div_u64_w(val, inb_p);
  spin_unlock(&disk->queue_lock);
  mutex_unlock(&s->sock->mutex);
  mutex_unlock(&func->mutex);
  return disassemble(info->pending_bh);
}

static void num_serial_settings(struct tty_struct *tty)
{
  if (tty == tty)
    disable_single_st_p(dev);
  pci_disable_spool(port);
  return 0;
}

static void do_command(struct seq_file *m, void *v)
{
  int column = 32 << (cmd[2] & 0x80);
  if (state)
    cmd = (int)(int_state ^ (in_8(&ch->ch_flags) & Cmd) ? 2 : 1);
  else
    seq = 1;
  for (i = 0; i < 16; i++) {
    if (k & (1 << 1))
      pipe = (in_use & UMXTHREAD_UNCCA) +
        ((count & 0x00000000fffffff8) & 0x000000f) << 8;
    if (count == 0)
      sub(pid, ppc_md.kexec_handle, 0x20000000);
    pipe_set_bytes(i, 0);
  }
  /* Free our user pages pointer to place camera if all dash */
  subsystem_info = &of_changes[PAGE_SIZE];
  rek_controls(offset, idx, &soffset);
  /* Now we want to deliberately put it to device */
  control_check_polarity(&context, val, 0);
  for (i = 0; i < COUNTER; i++)
    seq_puts(s, "policy ");
}

注意到,在第二个函数中,模型进行了这样的比较tty == tty,这是永远成立的。但是,至少这次变量tty只在这个函数中起作用!最后一个函数,注意到代码没有返回任何值,但是这是正确的因为函数的返回值声明成了void。但是,前两个函数同样声明成了void返回类型,却返回了数值。这又是一个由于长期迭代导致的常见错误。

有些时候模型会决定现在是时候产生一个新的文件了。这通常是有趣的部分:首先模型一个一个字符记住GNU许可证,然后include几个头文件,声明一些宏,然后就开始生成代码部分:

代码语言:javascript
复制
/*
 *  Copyright (c) 2006-2010, Intel Mobile Communications.  All rights reserved.
 *
 *   This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 *        This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software Foundation,
 *  Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/kexec.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/multi.h>
#include <linux/ckevent.h>

#include <asm/io.h>
#include <asm/prom.h>
#include <asm/e820.h>
#include <asm/system_info.h>
#include <asm/setew.h>
#include <asm/pgproto.h>

#define REG_PG    vesa_slot_addr_pack
#define PFM_NOCOMP  AFSR(0, load)
#define STACK_DDR(type)     (func)

#define SWAP_ALLOCATE(nr)     (e)
#define emulate_sigs()  arch_get_unaligned_child()
#define access_rw(TST)  asm volatile("movd %%esp, %0, %3" : : "r" (0));   \
  if (__type & DO_READ)

static void stat_PC_SEC __read_mostly offsetof(struct seq_argsqueue, \
          pC>[1]);

static void
os_prefix(unsigned long sys)
{
#ifdef CONFIG_PREEMPT
  PUT_PARAM_RAID(2, sel) = get_state_state();
  set_pid_sum((unsigned long)state, current_state_str(),
           (unsigned long)-1->lr_full; low;
}

这里有太多有趣的地方可以讲述了,关于这部分我可能可以写一篇完整的博客来讲述。但是在这里我就省略这部分了,如果你有兴趣查看,请点击 1MB of sampled Linux code

了解到底发生了什么

我们可以看出,最终训练出的结果是令人印象深刻的,但是这一切都是如何工作的?让我们通过运行两个快速的实验来简要探索下。

训练中样本的演变

首先,探索模型训练过程中样本文本是如何演变的是件有趣的事,比如,我用列夫·托尔斯泰的《战争与和平》训练了一个LSTM网络,然后每100次迭代训练就生成样本。100次迭代后模型生成了随机、混乱的样本:

代码语言:javascript
复制
tyntd-iafhatawiaoihrdemot  lytdws  e ,tfti, astai f ogoh eoase rrranbyne 'nhthnee e 
plia tklrgd t o idoe ns,smtt   h ne etie h,hregtrs nigtike,aoaenns lng

但是,注意到模型最少知道了要在每个“单词”间加上空格。有些时候会加上两个空格。同样模型不知道逗号后面通常跟着空格。300次迭代后我们可以看到模型开始有了引号和句号的概念:

代码语言:javascript
复制
"Tmont thithey" fomesscerliund
Keushey. Thom here
sheulke, anmerenith ol sivh I lalterthend Bleipile shuwy fil on aseterlome
coaniogennc Phe lism thond hon at. MeiDimorotion in ther thize."

这次单词之间同样由空格隔开,而且模型开始知道在句子末尾加上句号。500次迭代:

代码语言:javascript
复制
we counter. He stutn co des. His stanted out one ofler that concossions and was 
to gearang reay Jotrets and with fre colt otf paitt thin wall. Which das stimn 

现在模型会拼写最短、最常见单词,比如“we”,“He”,“His”,“Which”,“and”等。700次迭代的时候,我们得到了更像英语的文本:

代码语言:javascript
复制
Aftair fall unsuch that the hall for Prince Velzonski's that me of
her hearly, and behs to so arwage fiving were to it beloge, pavu say falling misfort 
how, and Gogition is so overelical and ofter.

在经过1200次迭代后,我们发现模型开始使用引号和问号/感叹号了,与此同时也学会了更长的单词:

代码语言:javascript
复制
"Kite vouch!" he repeated by her
door. "But I would be done and quarts, feeling, then, son is people...."

经过2000次迭代,模型能够正确拼写的单词,引号,名字等:

代码语言:javascript
复制
"Why do what that day," replied Natasha, and wishing to himself the fact the
princess, Princess Mary was easier, fed in had oftened him.
Pierre aking his soul came to the packs and drove up his father-in-law women.

大体上我们可以这么认为,首先模型发现了单词-空格这样普遍的结构,然后迅速学会拼写单词;从学习拼写简单单词开始到最后学习拼写长单词。在单词中显现出主题内容(一般依赖于长期性)在很多次迭代后才出现。

RNN预测结果和神经元激活可视化

可视化有趣的另一个方面是可以按字符来观察预测分布。在下面的可视化图中,我们向Wikipedia RNN模型中输入了校验好的数据集(蓝色/绿色的行)中的字符,然后在每个字符下面,我们列出了(红色部分)模型预测会出现的前5个字符,颜色深浅根据它们概率大小决定(深红:预测准确,白色:不准确)。比如,注意到有一连串字符是模型非常有信心能够预测准确的(对http://www.序列模型置信度非常高)。

输入字符序列(蓝色/绿色)的颜色取决于RNN隐藏层中随机选择的神经元的激活情况。定义绿色=非常兴奋,蓝色=不是那么兴奋(对于那些熟悉LSTMs细节的人来说,这些就是隐藏向量中[-1,1]范围内的值,也就是经过门限操作和tanh函数的LSTM单元状态)。直观的,下图显示了在RNN“大脑”读取输入序列时一些神经元的激活情况。不同的神经元可能有不同的模式;下面我们将会看到我找到的4个不同的神经元,我认为这几个是有趣的,并且是可解释的(许多其他的并不容易解释):

此图中高亮的神经元似乎对URL极度兴奋,URL以外的地方就不那么兴奋。LSTM似乎会用这种神经元来记住它是否在URL之中。

在这张图中,当RNN在[[]]标记之中时,高亮的神经元表现极度兴奋,所以在这种标记之外就没那么兴奋,在神经元碰到字符“[”的时候不会表现得兴奋,它一定要等到出现第二个“[”才会激活。计算模型是否碰到了一个还是两个“[”的任务似乎可以用一个不同的神经元完成。

在这里,我们可以看出在[[]]环境中,神经元有着线性的变化。换句话说,它的激活函数给了RNN中[[]]范围的一种基于时间的坐标系统。RNN可以通过这些信息或多或少的依赖于字符在[[]]中出现的早/晚来生成不同的字符(有可能是这样)。

这是另外一个神经元,它有着更个性化的行为:它整体上比较平淡无常,但是碰到“www”中第一个“w”的时候突然就开始变得兴奋。RNN可能可以使用这种神经元来计算“www”序列的长度,这样它就知道是否应该再添加一个“w”还是开始添加URL。

当然,由于RNN隐藏状态的庞大性,高维度性和分布式特性,很多这样的结论都稍微要加上特别说明才能理解。

源代码

我希望通过我上面的讲述,你会觉得训练一个字符级语言模型是一次有趣的练习。你可以使用我在Github(拥有MIT许可)上发布的 char-rnn code 来训练你自己的模型。它将大量文本文件作为输入,训练出一个字符级模型,然后你就可以从中得到样本文件。同时,如果你有一个GPU的话会对你有所帮助,否在在CPU上训练的话会花大约10多倍的时间。不管怎样如果你完成了训练并且得到了有趣的结果,请告知我!如果你在使用Torch/Lua代码库的时候碰到困难,请记住,这只是 100-line gist 的一个版本。

一些题外话。代码是由 Torch7 编写的,它最近成了我最喜欢的深度学习框架。我是最近几个月才开始使用Torch/Lua的,它们并不简单(我花了大量时间来阅读Github上Torch源码,向它的发布者提问才掌握它),但是一旦你掌握了足够的知识,它就会给你带来很大的灵活性和速度提升。我以前同样使用过Caffe和Theano,我认为Torch并不完美,但是它的抽象层次和原理比其他的要优秀。在我看来,一个有效框架应该具有以下功能:

  1. 有许多功能(slicing,array/matrix等操作)的CPU / GPU透明的Tensor库。
  2. 一个完全独立的代码库,它基于脚本语言(最好是 Python),工作在Tensors上,实现了所有深度学习方面的东西(前馈/后馈,图形计算等)。
  3. 它应该可以轻松共享预训练模型(Caffe在这方面做的很好,其他几个则存在不足),这也是至关重要的。
  4. 没有编译过程(或者说不要像Theano目前那样做)。深度学习是朝着更大更复杂的网络发展,所以在复杂图算法中花费的时间会成倍增加。重要的是,长时间或者是在开发阶段不进行编译所带来的影响是非常巨大的。而且,进行编译的话就会丢失可解释性和有效进行日志记录/调试的能力。如果为提高效率在图算法开发好后立即编译,那么这样做是可取的。

延伸阅读

在结束这篇文章之前,我还想再介绍更多关于RNNs的东西,并大致提供目前的研究方向。最近在深度学习领域,RNNs颇受欢迎。和卷积网络一样,它们已经存在了几十年,但它们的潜力最近才开始得到广泛的认可,这在很大程度上是因为我们不断增长的计算资源。下面是一些最近事态发展的简要介绍(这绝对不是完整的列表,很多这样的工作让研究界好像回到了上世纪90那种研究热潮,来看看相关的工作部分):

在NLP/语音领域,RNNs将 语音转录成文本 ,使用 机器翻译 , 生成手写文本 ,当然,它们已经被用来当做强大的语言模型( Sutskever等人 )( Graves )( Mikolov等人 )(都是在字符和单词层面)。目前看来,单词级的模型比字符级的模型要更好,但这肯定是暂时的。

计算机视觉。在计算机视觉方面,RNNs也很快成为了无处不在的技术。比如,我们会见到RNNs在帧层面 分类视频 , 添加图片字幕 (同样包括我和其他人的工作), 添加视频字幕 ,最近又用来 视觉问答 。我个人最喜欢的RNNs计算机视觉方面的论文是 Recurrent Models of Visual Attention ,这是因为它有着高层次方向特性(glance顺序处理图像)和低层次建模(REINFORCE学习规定它是强化学习中一个特定的梯度方法,可以训练出进行不可微计算的模型(以图像周边glance处理为例))。我相信,这种混合模型类型——由CNN形成的原始感知器再加上RNN glance策略,将会在感知器中普遍存在,特别是对于比分类更复杂的任务。

归纳推理,存储和关注模块。另一个非常令人兴奋的研究方向是面向解决Vanilla递归网络的局限性。它的一个问题是RNNs不是数学归纳的:它们能够非常好的记住序列,但是并不一定总能够得到正确的结果(我会举几个例子来具体说明)。第二个问题是,它们不必每步都将代表大小和计算数量结合起来。具体来说,如果你把隐藏状态向量的大小增加一倍,由于矩阵乘法,每步中FLOPS的数量会变成原来的四倍。理想情况下,我们想保持庞大的代表性/存储(比如,包含维基百科所有的内容或者多个中间状态变量),而同时保持计算的每个时间步长固定的能力。

在这些方向上,第一个有说服力的例子在DeepMind上的 Neural Turing Machines 这篇论文中讲述了。这篇论文描述了在计算开始时,模型在大的、外部的存储阵列和更小寄存器之间执行读写操作的方法(把它想象成是你自己的工作存储器)。至关重要的是,这篇论文也同样介绍了有趣的内存寻址机制,这是用一个(平缓的,完全可微的)关注模块实现的。平缓关注模块的概念是一个强大的建模特征,同时也是 Neural Machine Translation by Jointly Learning to Align and Translate 这篇文章再机器翻译上的一大特色,网络存储则用来问答。事实上,我不得不说:

关注模块的概念在最近的神经网络架构创新中是最有趣的。

现在,我不想讲太多的细节,但是内存寻址的平缓关注模块机制是非常方便的,因为它让模型完全可微,但不幸的是,这会牺牲一些效率,因为所有可以被关注的都被关注了(平缓的)。你可以把它想象成C语言中的指针,它不指向具体的地址,而是定义了在整个内存中分布的所有地址,并将指针返回的所指向内容的加权总和值非关联化(这个操作代价会很大!)。这促使多位作者在给多块内存进行关注操作的时候使用平缓关注方式而不是猛烈关注方式(比如,对某些内存单元进行读取操作,而不是从内存单元中读出/写入到某些地方)。这种模型有着更显著的哲学吸引力,可扩展性和高效率性,但是不幸的是,它是不可微的。这就要使用强化学习文献(比如REINFORCE)中使用到的技术来解决,人们将它完美地用于不可微的模型之中。这是正在进行的工作,但是针对这些困难的关注模型进行了探讨,你可以在 Inferring Algorithmic Patterns with Stack-Augmented Recurrent Nets ,Reinforcement Learning Neural Turing Machines , Show Attend and Tell 这几篇论文中了解到。

人物。如果你愿意阅读我推荐的 Alex Graves , Ilya Sutskever 和 Tomas Mikolov 所写的文章。你可以从 David Silver 或 Pieter Abbeel 的公开课中了解到更多的关于REINFORCE,强化学习和策略梯度方法的知识。

代码。如果你想实践实践训练RNNs,我推荐你使用Theano的 keras 和 passage ,也可以使用连同这篇文章一同发布的Torch 代码 ,或者使用我先前写好的numpy源代码 要点 ,它实现了一个有效率的、批量处理的LSTM前馈和后馈处理。你也可以看看我基于numpy的 NeuralTalk ,它用了RNN/LSTM来给图片加字幕,或者你可以使用Jeff Donahue写的 Caffe 。

总结

我们已经学习了RNNs是如何工作的,它们为什么变得至关重要,我们在几个有趣的数据集上训练了一个字符级的RNN模型,并且我们看到了RNNs的执行情况。你完全可以毫无顾忌的用RNNs进行大量创新,并且我相信它们会在智能系统中成为一种普遍存在并且至关重要的组成部分。

最后,在这篇文章中加上一些元数据,我用这篇文章的源文件训练了一个RNN。不幸的是,我只有46K的字符,没有足够的字符给RNN,但是返回的样本(使用低温度以得到更典型的样本)如下所示:

代码语言:javascript
复制
I've the RNN with and works, but the computed with program of the 
RNN with and the computed of the RNN with with and the code

好了,这篇文章是讲述关于RNN和它工作状况的,很明显它工作良好 :)。我们下回见!

原文链接: http://karpathy.github.io/2015/05/21/rnn-effectiveness/(译者/刘翔宇 审校/刘帝伟、朱正贵、李子健 责编/周建丁)

关于译者: 刘翔宇,中通软开发工程师,关注机器学习、神经网络、模式识别。

本文为CSDN原创翻译,未经允许不得转载,如需转载请联系market#csdn.net(#换成@)


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 人工智能头条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代数几何(Latex)
  • Linux源代码
  • 了解到底发生了什么
  • 源代码
相关产品与服务
NLP 服务
NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档