如何让神经网络开口说话

人类简史说,人类的进步大大依靠与人的语言,人在灵长类中具有最高级的语言能力,并且能够编故事,从而把越来越多的人组织在一起产生了文明,这才是人类社会进化的根本。 那幺,神经网络能否掌握人类的语言,听懂人类的故事呢? 相信朋友们都知道谷歌翻译,谷歌助手,机器写诗, 它们实现了令人惊艳的性能,并在某些具体任务里让人真假难辨。这里的技术核心,就是 RNN 。 – 我们常说的传说中的循环神经网络。 RNN 可以称得上是深度学习未来最有前景的工具之一。它在时间序列(比如语言文字,股票价格)的处理和预测上具有神功。

 

 

时间序列和 RNN 引入

 

让我们从基础学起, 首先 什幺是时间序列, 我们又 为什幺需要 RNN 。

 

 

 

时间序列, 是 一个随时间变化的过程, 我们 把它像一个数列一样排列下来, 序列 里的数字往往 看起来 在随机波动。 一定 程度, 我们 可以把它看做以一个一维的图像或向量, 这个 图像不停的向前滚动。 比如说文字,就是一个典型的时间序列。 处理和时间有关的信息,我们再次回到我们的大脑,看我们的大脑是怎幺处理这一类问题的。

 

实验发现,大脑越靠近感官的区域就越像CNN的结构,它的最本质特征是前馈,也就是每一次神经信息都是从感官向大脑的深层一步步推进的,而每层网络之间是没有联系的。而到了深层,这一切发生了变化,大脑内开始出现一些神经网络,这些网络在层间出现了很多的连接,这意味着什幺呢?

 

 

我们说,我们需要引入时间这个维度才能完全理解这件事,这些层内的链接意味着当下的神经信息会在下一个时刻被层内的其它神经元接受,而这个接受的结果呢? 当下的信息会传给这些层内的神经元, 从而使得这个信息在网络内回响一段时间,就好像社交网络里人们互相发送消息或分享朋友圈一样一个事件发生,就会引发一系列的社交网络动作使得信息的影响停留很久。

 

一个典型的例子是如果人和人彼此链接形成回路,我发出的信息可能会在若干时间又传递给我,从而让我自己直接看到我的过去历史,这个信息停留的效应是什幺?大脑处理时间相关信息的关键正是记忆。 最典型的在一个对话过程里,你要记住此时此刻所说的话, 还要关联前面很久的话,否则就会发生歧义。

 

引入了记忆,  这些问题就好解决了, 记忆分为不同的种类,  你在一个对话里可能回忆起很久以前的事情, 但是这和刚刚说的话的重要性显然不一样, 所以我们大脑就把这些记忆分成了长时的记忆和短时的记忆(工作记忆)。这个短时记忆, 正是通过互相高度连接成回路的网络之间的神经元互相喊话造成的。

 

一个神经网络里神经元之间彼此互相传递信号,形成循环往复的回路结构,就可以让过去的信息保持下来,把 这个 原理转化成人工神经网络就是 RNN , 翻译出来就是循环神经网络,这个循环,正是彼此链接形成回路的意思。我们看怎幺把模糊的想法一步步变成一个数学模型。

 

 

我们把这个网络内部神经元互相链接的方式用一个矩阵Wij表达, 也就是从 i 到 j 的连接强度表示。 Wij 就是神经元间彼此沟通的方法, 我们看rnn的方程,一方面网络要接受此刻从外部进来的输入,另一方面网络接受自己内部的神经元从上一个时间时刻通过 Wi 进来的输入,这一部分代表过去的历史 ,决定网络此刻的状态。

 

 

深度学习的核心就是特征提取。用一句话说, RNN 具备的素质就是把整个过去的时间信息转化成此刻的一组特征,然后让网络做预测或者决策。 比如,此刻股市的价格是所有之前和公司有关的信息一点一滴积累起来的。公司每个时间点的信息, 就是输入向量,  那幺神经元所干的事情是什幺呢? 它把所有过去的信息转化为当下的神经元活动, 而这些活动,就是一组由过去历史信息组成, 决定当下预测的特征。在股价的情况下,你可以想象成, 这些神经元就在描绘人们的信心指数, 而信心是所有过去点信息汇集的结果,RNN把每个时间步的信息通过神经元之间的互相喊话Wij,压缩成当下的一个状态向量hi,它包含了所有和我此刻决策有关的历史。 数学上你可以推到, 这个hi是所有过去输入的一个函数.

 

RNN 学说话

 

什幺叫预测说话,这是一个形式上开起来有点傻的例子, 就是给你一个序列的字母或单词让你猜下一个,我想你一定玩过报纸上的填词游戏。 那个每个时间步骤的输入就是一个字母,然后我要输出最后一个。

 

一个处理这个问题的经典模型叫N-gram , 它是说我可以把这个猜词的游戏看成一系列条件概率来处理, 用这个模拟过去的字母对当下字母的影响。因为我们知道语言本身存在非常清晰的规律, 这个规律就是字母都是成对出现的, 如果全面我给你的字母是 hell , 且还有一个字母,那幺你基本就知道是 o 了, 这个现象我们可以用字母共现概率表达,也就是说衡量一些字母在一起的概率 P ( w 1, w2,w3… ) , 那些经常在一起出现的字母概率会很大, 而其他很小, 我们可以用经典的条件概率公式来表达, 这个事情。

 

这个公式的意思非常清楚, 就是字母和字母之间不是互相独立的, 就是刚刚说的后面的字母极强的依赖于前面的字母, 这种关系通过条件概率体现。 这件事我们用一个图画出来,就是当下是所有过去的作用, 而一旦字母多了以后,这件事就特别复杂。我们用物理学家惯用的加入假设来简化降维,就是我当下的字母与过去相关,这种相关却是有限的, 比如只与前面n-1个相关。 这个模型就是n gram 。 比如说 只与前面一个相关,这就是2-gram, 而这个模型就是标准的马尔科夫链。

 

那幺,这里我们换一个模型来, 我们用 rnn 来做。具体怎幺干? 每个字母给他编个号码(独热编码),我一个一个的输入给这个网络,网络每一刻的状态取决于此刻的输入和上一刻的网络内部状态,而上一个网络内部状态又取决于过去的,输入,这样当我整个单词输出完毕,每个字母的信息可以看作都包含了在了神经元的状态里。我们要 把整个输入切分成小块, 用一个卷积核把 它们 卷入到一个隐层网络里, 只不过此处的 Wij 代替了 CNN 的卷积核,把历史卷入到一个隐层里。

 

我们用一段小巧的 python 代码让你重新理解下上述的原理:

 

 

这个结构, 非但 优雅, 而且 有效。 一个非常重要的点是, 我们不必在假定那个 n-gram 里的 n ,这时候,因为原则上 h 是所有历史输入 I1 …It 的函数, 这个过程, 也就是说我们具有一个 infinit – gram 。 你来思考一下这是真的吗? No , 当然不是, 你知道信息的传播是有损耗的, 如果把 RNN 展开,它事实上相当于一个和历史长度一样长的深度网络,信息随着每个时间步骤往深度传播,这个传播的信息是有损耗的,到一定程度我就记不住之前的信息了,当然如果你的学习学的足够好, Wij 还是可以学到应该学的记忆长度。

 

 

图:循环的本质

 

刚刚的词语预测模型,我们最终的目标是每次预测出现的下一个字母,我们的方法是在隐层之上加入一个读出权重,这个矩阵的作用如同我们之前讲的感知机,是在有效的特征基础上加一个线性分类器, 再加一个softmax函数得到一个向量每个数值代表出现某个字母的概率。然后我们希望我们的向量能够完全预测真实字母出现的概率,因此我们把真实数据作为输入不停的让他预测这个字母,直到这个概率和真实是最匹配的,我们就得到了训练好的模型, 然后我们就可以让他生成一段文本了!

 

 

上面介绍的过程是语言介绍的最基本的部分,这里所说的对字母进行独热编码这件事,如果进入到文本的世界,你要预测的不是字母而是单词, 这时候,我们通常不再采用独热编码,而你自己思考这件事显然是不合理的,因为词语之间相互关联,如果你把词语本身作为完全独立的东西来编码,你事实上就是丧失了这种本来的语义结构的信息,因而我们用更复杂的word2vec来替换,这个方案的核心依然是编码,只不过这套编码也是从神经网络里学过来的,具体来说,这套编码可以把语言内在的语法或语义信息包含在编码向量的空间结构里, 从而使用这部分语言有关的先验信息。

 

 

RNN 的物理与工程理解

 

我们说把对 RNN 的理解 在 抬升一个层次,RNN 在物理学家眼里是一个动力系统, 循环正对应动力学系统的反馈概念,可以刻画复杂的历史依赖 – 路径依赖 。另一个角度看也符合着名的图灵机原理。 即此刻的状态包含上一刻的历史,又是下一刻变化的依据。 工程上看, 这其实 就是 可编程神经网络的概念,即当你有一个未知的过程,但你可以测量到输入和输出, 你假设当这个过程通过 RNN 的时候, 你要设计一个程序来完成 这样的输入输出规律, 那幺这个程序可以被 RNN 学出来 。

 

 

总的来说 , 无论作为 一个非线性动力系统 还是程序生成器 的 RNN , 都需要依然数据背后本身是有规律可循的,也就是它背后真的有某种“ program ”而非完全随机 。 如果一旦 RNN 学习到了 真实 数据背后的 动力系统 的性质, 它也就 掌握了过程中复杂的路径依赖,从而能够对 过去 和 现在 进行建模。

 

RNN 生成诗歌

 

诗歌的生成,方法类似于句子,区别在于,诗歌是有主题的,我们都知道主题的重要性,同一个句话在不同主题下含义完全不同,如何把这个诗歌的主题输入给rnn呢?

 

事实上,我们可以把这种主题或者背景看作是一种上下文关系,比如说一首诗歌有四行,在生成第一行的时候,我可以输入开头一个关键词,然后让rnn自动生成一行,虽然这个过程还有一定随机性,但是这一行内容无疑确定了诗歌整体的基调,因此,我们需要把这种信息编码成一个包含上下文含义的内容向量,这个向量作为整个网络的输入。

 

 

我们采取的方法是逐行生成诗歌。已经生成的行就作为后面生成行的基调,每行诗歌的生成都使用和之前一样的RNN,但是,它的输入要加上一个主题向量。

 

如何提取主题向量呢?首先,它是一种由所有之前生成行构成的宏观信息,那幺,我们也可以用一个RNN来提取它,由于宏观, 这个RNN的输入是每行诗歌。而我们要用一个方法, 直接把行编码, 而不像刚刚是把字母或单词编码。 一行诗歌本身每个子都是一个向量,整行诗歌构成一个二维的图像(字数一定, 图像尺寸一定)。记得什幺东西最好处理图像吗?我们引入一个CNN网络,把这些同样尺存的“图片”,压缩一个特征向量,最后被这个被称为主题RNN的RCM卷成一个主题向量。

 

 

这个主题向量作为一个先验输入交给RGM, 这个普通的RNN, 作为这行诗词生成的关键。由此生成的诗歌不仅是押韵的,而且可以构成一个完整的意思。

 

 

引入长短记忆

 

RNN虽然看起来好用, 而且似乎 能够模拟任何一个 动力过程或程序 , 实际 中, 却 并没有那幺容易。 为什幺 ? RNN 的 强大 功能 , 体现在 能够学习 过去 时间点对现在的影响这件事, 但是,我们刚刚说了 RNN 相当于于一个无限深的深度网络, 而传播是有损失的, 假定每次这个损失是 0.99 , 经过 100 层后也是 0.36 , 这种信息传递的递减, 会导致 RNN 无法学到长时间的信息之间的关联性 。

 

我们的一个重要的解决这个问题的技巧是 : 引入一个能够学习多个时间尺度的改进版 RNN – LSTM( Long short term memory )。

 

 

首先,什幺是时间尺度,宇宙间最神秘的概念莫过于时间,但是绝对的时间毫无意义,一个时间的长短,一定是根据你所描述的过程, 比如你是描述一个人一生的变化过程,还是描述一次化学反应, 还是生物进化,各自的时间尺度可以有级数之差。我们对时间尺度最数学的理解来自原子的半衰期。

 

对于大脑神经尺度,处理动态过程最麻烦的东西就是时间尺度, 因为生活中的事情往往是多时间尺度的,比如你的一个决策今天晚上吃不吃饭,可能既受到刚刚是不是饿了的影响,又受到这个月你是不是有减肥计划的影响,还受到你长期养成的饮食习惯的影响,因此, 你的大脑需要有对复杂时间尺度的处理能力。也就是说,同时对各个不同的时间尺度变化的信息保持特异性和敏感度, 这和我们图像识别里需要对图像的局部和整体反应是类似的。一个有意思的电影inception描述要改变一个人的意念,我们需要一步步的走进他思想的最深层 ,逐层的改变它对某个东西的认知,而每个层里的时间尺度又有不同,就是对这件事最好的体现。事实上,类似于 inception 的描述,我们的确发现在我们的大脑里,有着不同时间尺度的处理, 越浅层,我们就对越近的东西敏感,而进入到大脑的深层,我们开始对慢过程敏感。

 

LSTM ,所谓的长短记忆机,这是对这个过程的模拟。我们来看它是怎幺对 RNN 进行改进的 , 这个道理非常简单,首先,我们加入一个叫做记忆细胞的概念,进入到记忆细胞的信息,可以永久不被改变, 但也可以根据一定触发条件修改,实现的方法是我们加入一些 控制 信息流动 的阀门 在这些记忆细胞之间 , 这个 阀门随着输入和隐层状态决定, 如果是 1 ,我们让过去的记忆完全进入到当下,信息丝毫不衰减,如果阀门的值是 0 ,就彻底的遗忘,如果是 0 和 1 就是在一个时间段里记住这个值就是一个时间尺度。只要 控制好这个 阀门 , 我们就得到了一个动态的可以学习的时间尺度。

 

 

刚刚讲的阀门被称为 遗忘门, 为了配合它,我们还加上输入门和输出们, 控制有多少新的信息流入,有多少输出, 这三层门 整体构成一套 信息的闸门,门的形式都是可微分的 sigmoid 函数,确保可以通过训练得到最佳参数。根据这一原理,我们可以抓住本质简化 lstm ,如 GRU 或极小 GRU 。其实我们只需要理解这个模型就够了,而且它们甚至比 lstm 更快更好。

 

我们看一下最小 GRU 的结构:

 

 

 

第一个方程 f 即遗忘门,第二方程如果你对比先前的 RNN 会发现它是一样的结构,只是让遗忘门 f 来控制每个神经元放多少之前信息出去(改变其它神经元的状态),第三个方程描述 “ 惯性 ” ,即最终每个神经元保持多少之前的值,更新多少。这个结构你理解了就理解了记忆体 RNN 的精髓。

 

Attention 版 LSTM 与宋词生成

 

当然,我还可以把这个多时间记忆的东西玩到极致,最终我们可以得到一个升级版本的诗词处理器, 我们要加入几个新的概念: 1 , 双向编码 lstm 2 , 多层 lstm , 3 , attention 。

 

为什幺双向,因为语言也可以倒过来念啊,甚至很多时候后面的内容越重要越能决定主题, 比如一句话一旦出现“但是”一定是但是后面的内容更中重要有决定性。

 

 

为什幺要多层, 记得我刚刚讲过的大脑结构吗? 如果每层的lstm学习的事件尺度敏感性不同, 会更好的处理多事件尺度新消息, 比如从词语到句子到段落。

 

最后,也是最关键的,看看我们如何引入 a ttention. 。 Google 这一次 2016 寄出的大法,是在其中加入了 attention 机制 , 首先大家理解人脑的注意力模型,人脑的注意力机制的特点是在认知资源有限的情况下,我们只给那些最重要的任务匹配较多的认知资源。 这个机制实现的方法正是 attention 。

 

首先,在引入 attention 之前,我们的想法是既然我们最终的决策想利用好所有的历史信息,而每个时间的隐层状态都是对那个时刻时间状态的总结,我们完全可以把所有时间点的 h 作为一个特征使用, 这一点, 而不只是最后的 h ,这点在文章分类这类任务里特别好理解,但是每个 h 动辄上百维度,所以当我们把所有的 h 合成在一起的时候 ,我们就会得到几十万个维度,我们再次抛出降维度找重点的思维, 加入一个 attention 来吸取和当下预测最重要的信息。 A ttention 又称为 content base addressing ,因为过去哪个东西比较重要,往往取决于我现在要预测的信息。

 

 

有了这个机制,我们可以抛出我们唐诗生成器的改进版,宋词生成器,宋词的生成,确实是比唐诗更复杂的一个东西,因为宋词更长, 更多变,句子长短不同,也更需要多时间尺度。

 

 

这一次,我们可以把宋词的结构看作是一种对话体, 我们用一个把问题编码, 然后直接从这个基础上预测对上一句的回答,这里,我们生成第一句词的技巧和之前是类似的, 从这个生成的第一句词开始,我们用编码器 LSTM 来把这一行编码作为下一句的 cue , 然后解码器把这个 cue 转化为下一行词。为什幺我们要用 attention 呢? 因为上一句的所有的 h 被叠加成一打,刚刚说到的,这时候会造成信息过大,所以我们引入 attention 的机制来注意相应的信息, 这样我们就可以找到上一行和下一行之间精细的相关性。

 

 

大家可以比较和唐诗生成的时候, 我们的结构不仅更简洁,而且能够处理更难的任务。

 

模拟人类对话

 

最终, 我们已经接近了让神经网络听懂故事的境界, 你是否认为类似的结构可以用作和我们对话呢?

 

 

当然不是, 因为你我在对话时候有大量的背景知识, 而机器人是没有的, 但是有没有补救的方法? 当然有, 谷歌的问答系统, 已经把很多重要的背景知识放入了神经网络, 这种加入很长的背景知识的结构, 被我们称为记忆网络, 事实上,它是对人类的长时间记忆的模拟。 这些长时间记忆, 包含知识,或者地图等。用它做的聊天机器人,可以成为你电话里的助手,但是, 你是否认为这样的结构已经具备了真正理解语言的能力呢?

 

参考文献 :

 

The unreasonable effective RNN

 

Google’s Neural Machine Translation System: Bridging the Gap between Human and Machine Translation

 

Minimal Gated Unit for Recurrent Neural Networks

发表评论

电子邮件地址不会被公开。 必填项已用*标注