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

Posted CSDN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归神经网络不可思议的有效性相关的知识,希望对你有一定的参考价值。

摘要:递归神经网络有一些不可思议的地方,有些时候,模型与你期望的相差甚远,许多人认为是RNNS非常难训练,那么RNNs究竟是什么呢?就有这篇文章来带给大家。


递归神经网络(RNNs)有一些不可思议的地方。我仍然记得我训练的第一个用于 图片字幕的递归网络。从花几十分钟训练我的第一个婴儿模型(相当随意挑选的超参数)开始,到训练出能够针对图像给出有意义描述的模型。有些时候,模型对于输出结果质量的简单程度的比例,会与你的期望相差甚远,而这还仅仅是其中一点。有如此令人震惊结果,许多人认为是因为RNNs非常难训练(事实上,通过多次试验,我得出了相反的结论)。一年前:我一直在训练RNNs,我多次见证了它们的强大的功能和鲁棒性,而且它们的输出结果同样让我感到有趣。这篇文章将会给你展现它不可思议的地方。


我们将训练一个RNNs让它一个字符一个字符地生成文本,然后我们思考“这怎么可能?”


顺便说句,在讲述这篇文章的同时,我同样会将代码上传到 Github 上,这样你就可以基于多层LSTMs来训练字符级语言模型。你向它输入大量的文本,它会学习并产生类似的文本。你也可以用它来重新运行我下面的代码。但是我们正在不断超越自己;那么RNNs究竟是什么呢?


递归神经网络


序列。你可能会问:是什么让递归神经网络如此特殊?Vanilla神经网络(卷积网络也一样)最大的局限之处就是它们API的局限性:它们将固定大小的向量作为输入(比如一张图片),然后输出一个固定大小的向量(比如不同分类的概率)。还不止这些:这些模型按照固定的计算步骤来(比如模型中层的数量)实现这样的输入输出。递归网络更令人兴奋的主要原因是,它允许我们对向量序列进行操作:输入序列、输出序列、或大部分的输入输出序列。通过几个例子可以具体理解这点:




每一个矩形是一个向量,箭头则表示函数(比如矩阵相乘)。输入向量用红色标出,输出向量用蓝色标出,绿色的矩形是RNN的状态(下面会详细介绍)。从做到右:(1)没有使用RNN的Vanilla模型,从固定大小的输入得到固定大小输出(比如图像分类)。(2)序列输出(比如图片字幕,输入一张图片输出一段文字序列)。(3)序列输入(比如情感分析,输入一段文字然后将它分类成积极或者消极情感)。(4)序列输入和序列输出(比如机器翻译:一个RNN读取一条英文语句然后将它以法语形式输出)。(5)同步序列输入输出(比如视频分类,对视频中每一帧打标签)。我们注意到在每一个案例中,都没有对序列长度进行预先特定约束,因为递归变换(绿色部分)是固定的,而且我们可以多次使用。


正如你预想的那样,与使用固定计算步骤的注定要失败的固定网络相比,使用序列进行操作要更加强大,因此,这激起了我们建立更智能系统更大的兴趣。而且,我们可以从一小方面看出,RNNs将输入向量与状态向量用一个固定(但可以学习)函数绑定起来,从而用来产生一个新的状态向量。在编程层面,在运行一个程序时,可以用特定的输入和一些内部变量对其进行解释。从这个角度来看,RNNs本质上可以描述程序。事实上,众所周知, RNNs是图灵完备的 ,即它们可以模拟任意程序(使用恰当的权值向量)。但是,类似于通用逼近定理神经网络,你还不应该深入阅读。就当我没说过这些吧。


如果训练Vanilla神经网络是优化功能,那么训练递归神经网络则是优化程序。


序列缺失情况下的序列处理。你可能会想,有序列作为输入或输出可能是相对少见的,但关键是,即使你的输入/输出是固定向量,仍然有可能使用这种强大的以序列的方式来处理它们。比如,下图显示了 DeepMind 中两篇非常棒的论文的结果。在左边,一个算法学习了一种递归网络策略,可以将它的注意力集中在图像周围;特别的,它学会了从左到右阅读门牌号码( Ba等人 )。在右边,一个递归网络通过学习在画布上序列化地添加颜色然后生成一张数字图像( Gregor等人 ):


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


左边:RNN学习阅读门牌号。右边:RNN学习学习绘制门牌号。


即使你的数据不是序列形式的,你仍然可以制定并训练出强大的模型来学习处理它。你可以学习有状态的程序来处理固定大小的数据。


RNN计算。那么这些是如何工作的呢?主要是,RNNs有一个非常简洁的API:它们将向量x作为输入,然后输出结果向量y.然而,关键的是这个输出向量的内容不仅受到前一次输入数据的影响,而且还会受整个历史输入数据的影响。这个API编写成了一个类,它由一个step方法构成:


rnn = RNN()
y = rnn.step(x) # x is an input vector, y is the RNN's output vector


RNN类有一些内部的状态,会在每一次调用 step方法的时候进行更新。最简单的情况是,这个状态由单个隐藏向量h构成。下面是Vanilla RNN中对step方法的一种实现:



class RNN:
  # ...
  def step(self, x):
    # update the hidden state
    self.h = np.tanh(np.dot(self.W_hh, self.h) + np.dot(self.W_xh, x))
    # compute the output vector
    y = np.dot(self.W_hy, self.h)
    return y


上面的代码指明了vanilla RNN的前馈操作。这个RNN的参数是以下三个矩阵:w_hh,w_xh,w_hy。隐藏状态self.h由两个零向量初始化。np.tanh函数实现了非线性的方法,将活化结果压缩到范围[-1,1]之内。简单介绍工作原理:tanh中有两种形式:一种是基于前面的隐藏状态,另一种是基于当前的输入。numpy中的np.dot是矩阵乘法。这两种中间体相加,然后由tanh函数将它压缩成一个新的状态向量。如果你适合看数学公式的话,我们同样可以将隐藏状态写成 ht+1 =tanh(Whh ht+ Wxhxt), tanh函数是元素智能的。


我们用随机数来初始化RNN矩阵,通过大量的训练找到一个令人满意的矩阵,并且用一些损失函数来度量,你可以在输入序列x上得到你希望的输出y。


更深层次说明。RNNs是一种神经网络,而且如果你开始学习深度学习并开始像堆煎饼一样积累模型,它们将会工作得更好(如果做得正确的话)。例如,我们可以通过以下方式建立一个2层的递归网络:


y1 = rnn1.step(x)
y = rnn2.step(y1)


换句话说,我们有两个独立的RNNs:一个RNN接收输入向量,另一个将前一个RNN的输出作为输入。这两个RNN没有本质区别——这不外乎就是向量的输入输出而已,而且在反向传播过程中每个模块都伴随着梯度操作。


来点更奇特的。我会简要说明,实际上我们大多数人使用一种与上面我所提及稍微不同的网络,它叫做长短期记忆(LSTM)网络。LSTM是一种特殊类型的递归网络,在实践中工作效果更佳,这归功于其强大的更新方程和一些吸引人的动态反向传播功能。我不会详细介绍,除了用于更新计算(self.h=···)的数学形式有点更复杂外,与其他RNNs没有多大区别。从现在开始,我将会交替使用术语“RNN/LSTM”,但是这篇文章中所有的实验都是用LSTM完成的。


字符级语言模型


好,我们现在已经初步了解了什么是RNNs,为什么它们如此令人兴奋,还有它们是如何工作的。我们现在就用它来实现一个有趣的应用:我们将要训练字符级的语言RNN模型。具体来说就是,我们将会向RNN输入大量的文本数据,然后在一个序列中给定一个前面的字符,用它来建立计算这个序列下一个字符概率的模型。这将会让我们在同一时间产生新文本字符。


作为一个案例,假设我们只有四种字母的词汇“helo”,然后我们想要用训练序列“hello”训练一个RNN。这个训练序列实际上是来自于4个独立的训练案例:1.字母e应该在字母h出现的情况下才可能出现,2.字母l应该出现在he出现的情况下,3.字母l同样可以出现在hel出现的情况下,最后4.字母o应该出现在hell出现的情况下。


具体来说,我们将用1-of-k编码(所有都是0,除了词汇中字符的索引)将每个字符编码成一个向量,然后用step函数每次向RNN中输入一个字符。然后我们会看到一个4维序列的输出向量(每个字符代表一个维度),我们将此作为RNN分配给序列下一个字符的置信度。下面是一张案例图:


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


一个有四维输入输出层和一个有着3个单元(神经元)的隐藏层的实例。这张图显示了当将“helo”作为RNN的输入时前馈操作的活化结果。输出层包含了RNN对下一个出现字符(这里词汇是“h,e,l,o”)的置信度。我们希望使得绿色的数字尽可能高而红色数字尽可能低。


比如,我们可以看出,在第一次执行step函数的时候,RNN读取到字符“h”然后将它之后可能出现字符“h”的置信度设置为1.0,可能出现字符“e”的置信度设置为2.2,可能出现字符“l”的置信度设置为-3.0,可能出现字符“o”的置信度设置为4.1。因为在我们的训练数据中,下一个出现的字符是“e”,我们将要提高这个字符的置信度(绿色数字)并且降低其他字符的置信度(红色数字)。通常的做法是使用一个交叉熵损失函数,这相当于在每个输出向量上使用Softmax分类器,将下一个出现的字符的索引作为一个正确的分类。一旦损失进行了反向传播并且RNN权值得到更新,在输入相同的情况下,下一个正确的字符将会有更高的分数。技术解释:该RNN是由小批量随机梯度下降训练的。我喜欢使用 RMSProp (每个参数的自适应学习率)来稳定更新。


同样可以注意到,字符“l”第一次输入时,得到的结果是“l”,但是第二得到的结果是“o”。因此,这个RNN不能单独依赖于输入数据,必须使用它的递归连接来跟踪内容以达到准确结果。


在测试的时候,我们向RNN输入一个字符,然后得到了下一个可能出现字符的分布。我们从这个分布中抽样,然后又将这些样本输入到RNN中得到下一个字符。重复这个过程,你就在做取样的工作了!现在让我们在不同数据集上训练RNN,看看会有什么发生。


为进一步说明,出于教育目的我还写了一篇文章 minimal character-level RNN language model in Python/numpy 。只有大约100行代码,如果你更擅长阅读代码而不是文字,你可以从中得到简明的、具体的、有用的结论。现在我们将深入到实例结果,使用更高效的Lua/Torch代码库来编程。


开心使用RNNs


下面的5个字符模型案例都是使用我发布在Github上的 代码 进行训练的。每个实例的输入都是单个文本文件,然后我们训练RNN预测序列中下一个可能出现的字符。


Paul Graham生成器


首先让我们尝试用一个小英语数据集作一个全面检查。我个人最喜欢的数据集是 Paul Graham散文串联集。其基本思路是,散文中有很多智慧,不幸的是Paul Graham是一个相对缓慢的生成器。如果我们能够按需生成智慧样本,那不是很强大?RNNs在这里就起到了作用。


连接过去5年所有的论文,我们得到了大约1MB的文本文件,或者说是大约100万个字符(这是一个非常小的数据集)。技术方面:我们用512个隐藏节点(大约350万个参数)来训练一个2层的LSTM,然后在每层之后设定参数为0.5的dropout层。我们将每批训练100个实例,然后每超过100个字符则停止反向传播。通过这些设置,每一批在TITAN Z GPU上处理完成大约需要0.46秒(这通过性能代价忽略不计的50个字符的BPTT算法将它分为两半)。事不宜迟,让我们看看RNN中的样本:


"The surprised in investors weren't going to raise money. I'm not the company with the time there are all interesting quickly, don't have to get off the same programmers. There's a super-angel round fundraising, why do you can do. If you have a different physical investment are become in people who reduced in a startup with the way to argument the acquirer could see them just that you're also the founders will part of users' affords that and an alternation to the idea. [2] Don't work at first member to see the way kids will seem in advance of a bad successful startup. And if you have to act the big company too."


好了,很明显上面的样本不会很快随时取代Paul Graham,但请记住, RNN不得不完全从一个小的数据集(包括逗号,顿号和空格的位置)开始学习英语。我同样喜欢让它来学习支持自己的论证(比如上面的[2])。有时,它会提供一些可洞察的东西,比如“ a company is a meeting to think to investors”。如果你想了解更多,点击这个 链接,它有5万个字符样本数据。


温度。我们同样可以在Softmax取样的时候对温度进行操作。将温度从1降至更低的数字(比如0.5)可以让RNN有更高的置信度,但是样本就会更保守。相反地,较高的温度将会得到更多元化的结果,但是失误就更多(比如拼写错误等)。特别地,将温度设置成与0接近的数字就会得到与Paul Graham相似的言论:


"is that they were all the same thing that was a startup is that they were all the same thing that was a startup is that they were all the same thing that was a startup is that they were all the same"


看起来我们陷入了startups的死循环了。


Shakespeare


看样子好像我们的模型可以学习拼写英语单词,但是数据更结构化更风格化又会怎样呢?为了检测这一点,我下载了莎士比亚所有的作品并将它们串起来组成一个单一的(4.4MB)文件。现在我们可以训练一个更大的网络了,在这个例子中,我们尝试使用每层上都拥有512个隐藏节点的3层RNN网络。在我们训练网络几小时后,我们得到了如下样本:


PANDARUS:
Alas, I think he shall be come approached and the day
When little srain would be attain'd into being never fed,
And who is but a chain and subjects of his death,
I should not sleep.

Second Senator:
They are away this miseries, produced upon my soul,
Breaking and strongly should be buried, when I perish
The earth and thoughts of many states.

DUKE VINCENTIO:
Well, your wit is in the care of side and that.

Second Lord:
They would be ruled after this chamber, and
my fair nues begun out of the fact, to be conveyed,
Whose noble souls I'll have the heart of the wars.

Clown:
Come, sir, I will make did behold your worship.

VIOLA:
I'll drink it.


切记,RNN只认识字符,所以它将说话者的名字和内容一起生成为样本。有时,我们还可以得到相对延伸的独白段落,比如:


VIOLA:
Why, Salisbury must find his flesh and thought
That which I am not aps, not a man and in fire,
To show the reining of the raven and the wars
To grace my hand reproach within, and not a fair are hand,
That Caesar and my goodly father's world;
When I was heaven of presence and our fleets,
We spare with hours, but cut thy council I am great,
Murdered and by thy master's ready there
My power to give thee but so much as hell:
Some service in the noble bondman here,
Would show him to her wine.

KING LEAR:
O, if you were a feeble sight, the courtesy of your law,
Your sight and several breath, will wear the gods
With his heads, and my hands are wonder'd at the deeds,
So drop upon your lordship's head, and your opinion
Shall be against your honour.


在这些样本中,我几乎认不出这是莎士比亚的作品:)如果你喜欢莎士比亚,你可能会重视这份100,000个字符的样本。当然,你也可以用我提供的代码,在不同温度下生成许多你自己的样本。


Wikipedia


我们看到,LSTM可以学习拼写单词和复制一般的句法结构。让我来加大难度,在结构化markdown语言上训练网络。特别的,让我们使用 Hutter Prize 的100MB的Wikipedia原始数据训练一个LSTM。在 Graves等人 之后,我使用前96MB数据来训练,剩下的则花一个晚上用来验证和运行几个模型。现在我们可以取样Wikipedia文章了!下面是几个有趣的节选。首先,一些基本的markdown输出:


Naturalism and decision for the majority of Arab countries' capitalide was grounded
by the Irish language by [[John Clair]], [[An Imperial Japanese Revolt]], associated 
with Guangzham's sovereignty. His generals were the powerful ruler of the Portugal 
in the [[Protestant Immineners]], which could be said to be directly in Cantonese 
Communication, which followed a ceremony and set inspired prison, training. The 
emperor travelled back to [[Antioch, Perth, October 25|21]] to note, the Kingdom 
of Costa Rica, unsuccessful fashioned the [[Thrales]], [[Cynth's Dajoard]], known 
in western [[Scotland]], near Italy to the conquest of India with the conflict. 
Copyright was the succession of independence in the slop of Syrian influence that 
was a famous German movement based on a more popular servicious, non-doctrinal 
and sexual power post. Many governments recognize the military housing of the 
[[Civil Liberalization and Infantry Resolution 265 National Party in Hungary]], 
that is sympathetic to be to the [[Punjab Resolution]]
(PJS)[http://www.humah.yahoo.com/guardian.
cfm/7754800786d17551963s89.htm Official economics Adjoint for the Nazism, Montgomery 
was swear to advance to the resources for those Socialism's rule, 
was starting to signing a major tripad of aid exile.]]


你可能会想,上面的雅虎url并不真实存在,该模型只是将它作为假想事物。同样,可以注意到模型学会正确打开和关闭插入语。模型同样学会了许多结构化markdown语言,比如,有时候它创建了头部信息和列表等:


{ { cite journal | id=Cerling Nonforest Department|format=Newlymeslated|none } }
''www.e-complete''.

'''See also''': [[List of ethical consent processing]]

== See also ==
*[[Iender dome of the ED]]
*[[Anti-autism]]

===[[Religion|Religion]]===
*[[French Writings]]
*[[Maria]]
*[[Revelation]]
*[[Mount Agamul]]

== External links==
* [http://www.biblegateway.nih.gov/entrepre/ Website of the World Festival. The labour of India-county defeats at the Ripper of California Road.]

==External links==
* [http://www.romanology.com/ Constitution of the Netherlands and Hispanic Competition for Bilabial and Commonwealth Industry (Republican Constitution of the Extent of the Netherlands)]


有时模型会生成随机但是有效的XML文件:


<page>
  <title>Antichrist</title>
  <id>865</id>
  <revision>
    <id>15900676</id>
    <timestamp>2002-08-03T18:14:12Z</timestamp>
    <contributor>
      <username>Paris</username>
      <id>23</id>
    </contributor>
    <minor />
    <comment>Automated conversion</comment>
    <text xml:space="preserve">#REDIRECT [[Christianity]]</text>
  </revision>
</page>


这个模型完全拼凑出了timestamp,id等等。同样,注意到它以正确的嵌套顺序适当的闭合了正确的标签。如果你有兴趣了解更多,这里有 100,000 characters of sampled wikipedia


代数几何(Latex)


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


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


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


这是另一份样本:


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

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


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


\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网络来说还是微不足道的。结果非常有趣:


/*
 * 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学习操作数组的情况:


/*
 * 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几个头文件,声明一些宏,然后就开始生成代码部分:


/*
 *  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次迭代后模型生成了随机、混乱的样本:


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次迭代后我们可以看到模型开始有了引号和句号的概念:


"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次迭代:


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次迭代的时候,我们得到了更像英语的文本:


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次迭代后,我们发现模型开始使用引号和问号/感叹号了,与此同时也学会了更长的单词:


"Kite vouch!" he repeated by her
door. "But I would be done and quarts, feeling, then, son is people...."


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


"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隐藏状态的庞大性,高维度性和分布式特性,很多这样的结论都稍微要加上特别说明才能理解。


完整内容和延伸阅读请点击“阅读原文”


本文为CSDN原创,点击“阅读原文”可查看专题并参与讨论。


以上是关于递归神经网络不可思议的有效性的主要内容,如果未能解决你的问题,请参考以下文章

递归神经网络的不可思议的有效性 [ 译 / 转 ]

拓展深度学习一种变相的马尔可夫链

Javacc 不可达语句

在graphql中嵌套片段

JavaScript - 代码片段,Snippets,Gist

需要一种有效的方法来避免使用 Laravel 5 重复代码片段