[翻译]循环神经网络不可思议的性能
循环神经网络(RNN)具有神奇的功能。我还记得当我训练我的第一个关于图像字幕的循环网络。在训练了几十分钟后,模型的雏形(使用相当随意选择的超参数)开始产生对图像有意义的描述,这些描述处于合理的边缘。有时候,模型的简单程度与从中获得的结果的质量之比超出了您的期望,这就是其中之一。当时让这个结果很是令人惊讶,因为人们普遍认为RNN是很难训练的(根据更多的经验,我实际上得出了相反的结论)。快一年了:我一直在训练RNN,我已经多次目睹了它们的强大之处和鲁棒性,但它们神奇的输出仍然能吸引我。这篇文章即时和你们分享一些它的神奇之处。
我们将训练RNNs一个单词一个单词的生成文本,并思考“这怎么可能?"
顺便说一句,我将这篇文章和相关代码都放在了GitHub上,可以让你基于多层LSTMs来训练字符级别的语言模型。你给它大量的文本内容,它将学会一次生成像原字符一样的文本。你也可以使用它复制我的实验。 但我们正在超越自己; 什么是RNNs呢?
循环神经网络
序列:你可能会想:是什么让循环网络如此特别?普通神经网络(MLP, BP)以及卷积网络的一个明显限制是它们的API过于受限:它们接受固定大小的向量作为输入(如图像),并产生固定大小的向量作为输出(如不同类别的概率)。不仅如此:这些模型使用固定数量的计算步骤(例如模型中的层数)执行映射。递归网络更吸引人的地方是,它可以让我们对向量的序列进行操作:输入序列、输出序列,或者通常情况下,两者都可以。几个具体的例子如下:
每个矩形是一个向量,箭头表示函数(例如矩阵乘法)。输入向量为红色,输出向量为蓝色,绿色向量保持RNN的状态(稍后将介绍更多内容)。从左到右:(1)无RNN的普通处理模式,从固定大小的输入到固定大小的输出(如图像分类)。(2) 序列输出(例如,图像字幕获取图像并输出一个句子)。(3) 顺序输入(例如,情绪分析,其中一个句子被归类为表达积极或消极情绪)。(4) 序列输入和序列输出(例如机器翻译:RNN读取英语句子,然后输出法语句子)。(5) 同步序列输入和输出(例如,视频分类,我们希望在其中标记视频的每个帧)。请注意,所有的长度序列都没有预先指定的约束,因为递归变换(绿色)是固定的,可以应用任意次数。
正如你所想的那样,固定网络从一开始就注定要经过固定数量的计算步骤,相比之下,序列方法要更为强大,这对我们这些渴望建立更多智能系统的人来说也更有吸引力。此外,RNNs将输入向量和它们的状态向量与一个固定的(经过学习的)函数结合起来,生成一个新的状态向量。从程序的角度来看,这相当于运行了一个具有特定输入和一些内部变量的程序,该程序是固定的。由此看来,RNNs本质上描述的则是程序。事实上,RNN是图灵完备的(Turing-Complete),它们可以模拟任意程序(具有适当的权重)。不过类似神经网络的普遍逼近定理,你不用读得太多。忘记我说的话吧。
如果训练普通神经网络是对函数的优化,则训练递归网络是对程序的优化。
对缺失序列的处理:你可能觉得,将序列作为输入或输出比较少见。但重点是即便你输入/输出的是固定向量,仍然可以使用这种强大的框架,按顺序处理这些向量。例如,下图显示了来自 DeepMind的两篇优秀论文的结果。图左是一个循环网络算法,它将注意力放在图像上,学习从左到右读出门牌号(Ba et al.)。图右是一个循环网络通过学习按顺序为画布添加颜色,将原本模糊的数字图像变成生成清晰的数字图像 (Gregor et al.):
Left: RNN learns to read house numbers. Right: RNN learns to paint house numbers.
这样做的优点是,即便数据不是序列形式,你依然可以构建并训练按序列处理任务的模型。你正在学习一种有状态程序,该程序可以处理大小为固定的数据。
RNN的计算:那么上述这些东西如何实现呢?关键点,RNNs有一个看起来很简单的API,它接受一个输入向量x,并给你一个输出向量y。但是,这个输出向量的内容不仅受你刚刚输入的内容的影响,而且还受你过去输入的整个历史的影响。RNN的API作为一个类来编写,有一个阶跃函数构成:
rnn = RNN()
y = rnn.step(x) # x is an input vector, y is the RNN's output vector
该RNN类有一些内部状态,每次调用函数时都会更新这些状态。在最简单的情况下,该状态由单个隐藏向量h组成。下面是普通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
上面指定了一个简单RNN的前向传递。这个RNN的参数是三个矩阵:W_hh, W_xh, W_hy
。隐藏状态self.h
用零向量初始化。np.tanh
函数执行非线性处理,将激活后的数值压缩到[-1,1]
。请稍微留意一下这是如何工作的:tanh中有两个术语:一个是基于以前的隐藏状态,另一个是基于当前输入。在numpy中,np.dot
是矩阵相乘。这两个中间产物相加,然后被tanh压入新的状态向量。如果你更擅长数学符号,我们还可以将隐藏状态的更新写成
h
t
=
t
a
n
h
(
W
h
h
h
t
−
1
+
W
x
h
x
t
)
h_t=tanh(W_{hh}h_{t−1}+W_{xh}x_{t})
ht=tanh(Whhht−1+Wxhxt)
其中tanh是按元素应用的。我们用随机数初始化RNN的矩阵,训练过程中的大部分工作都是寻找期望的矩阵,通过用一些损失函数,以实现输入序列x
后对应输出期望的y
。
深入:RNN是神经网络,如果你像烙饼煎一样开始训练模型,一切工作都会单调向好(如果做法正确)。例如,我们可以形成一个2层递归网络,如下所示:
y1 = rnn1.step(x)
y = rnn2.step(y1)
换句话说,我们有两个独立的RNN:一个RNN接收输入向量,第二个RNN接收第一个RNN的输出作为其输入。这两个RNN互不认识-它们只是向量进出,以及在反向传播过程中流经每个模块的一些梯度。
变得有趣:我想简单地提一下,在实践中,我们一般使用的公式与我在上面提到的长-短期记忆(LSTM)网络稍有不同。LSTM是一种特殊的递归网络,由于其更强大的更新方程和引人注意的反向传播过程,在实际应用中效果更好。我不会详细介绍,但我所说的关于RNNs的所有内容都保持不变,除了计算更新的形式(self.h=…
)变得有点复杂。从这里开始,我将交替使用术语“RNN/LSTM”,但本文中的所有实验都使用LSTM。
字符级语言模型(Character-Level Language Models)
我们已经知道了什么是RNNs,为什么它们如此吸引人,以及它们是如何工作的。我们现在将在一个有趣的应用程序中实现这一点:我们将训练RNN字符级语言模型。也就是说,我们将给RNN一个巨大的文本块,并要求它在给定一个字符序列的序列中,模拟下一个字符的概率分布。这样我们就可以生成一个新文本。举一个例子,假设我们只有一个由’helo’四个字母组成的词汇表,并想根据训练序列“hello”训练一个RNN。实际上,该训练序列来自4个不同的训练例子:
1.在“ h”的上下文中,应该有合适的概率给出“ e”,
2.在“he”的上下文中,应该有合适的概率给出“ l”,
3.在“ hel”的上下文中,应该有合适的概率给出“ l”,
4.最后,在“hell”的上下文,应该有合适的概率给出“ o”。
具体来说,我们将使用1-of-k编码将每个字符编码成一个向量(即除了词汇表中字符索引处的那个字母外,所有字符都为零),并使用step函数将它们一次性输入RNN。然后我们观察一个四维输出向量序列(每个字符一维),我们将其表述为,RNN当前分配给序列中下一个字符的置信度。这里有一张图:
一个示例RNN,它有一个4维的输入和4维的输出,以及3个单位(神经元)的隐藏层。此图显示了当输入字符’hell’时,RNN的正向激活过程。输出层包含RNN为下一个字符分配的置信度(词汇表为“h,e,l,o”);我们希望绿色数字高,红色数字低。
例如,当RNN看到’h’字符时,它将下一个字母为“h”的置信度分配为1.0,将下一个字母为“e”的置信度分配为2.2,将下一个字母为“l”的置信度分配为-3.0,将下一个字母为“o”的置信度分配为4.1。在我们的训练数据中(字符串“hello”),正确的下一个字符是“e”,所以我们希望增加它的置信度(绿色)并降低所有其他字母的置信度(红色)。类似地,我们在4个时间步长中,每一步都有一个期望的目标字符,我们希望网络赋予它更高的置信度。由于RNN完全由可微分运算组成,因此我们可以运行反向传播算法(这是微积分链式规则的递归应用),以确定应该朝哪个方向调整权重以增加正确目标的得分 (绿色粗体数字)。然后,我们可以执行参数更新,在此梯度方向上将每个权重微调。 如果在参数更新后将相同的输入提供给RNN,我们会发现正确字符的分数(例如,第一步中的“ e”)会略高(例如2.3而不是2.2),并且 错误字符的得分会略低。 然后,我们反复重复此过程,直到网络收敛,并且其预测最终与训练数据一致为止,并始终都会预测正确的字符。
一个更专业的解释是,我们在每个输出向量上同时使用标准的Softmax分类器(也称为交叉熵损失)。RNN采用小批量随机梯度下降(mini-batch Stochastic Gradient Descent)训练,我喜欢使用 RMSProp或Adam(每参数自适应学习率的方法)来稳定更新。
还要注意,第一次输入字符“l”,目标是“l”,但第二次输入的目标是“o”。因此,RNN不能仅仅依赖于输入,还必须使用它的循环连接(recurrent connection)来跟踪上下文以实现此任务。
在测试时,我们将一个字符输入RNN,并获得关于接下来可能出现的字符的分布。 我们从该分布中采样,然后将其反馈回去以获得下一个字母。 重复此过程,你就得到了一个文本! 现在让我们在不同的数据集上训练RNN,看看会发生什么。
为了进一步澄清,出于教育目的,我还用Python/numpy编写了一个最小字符级的RNN语言模型(minimal character-level RNN language model in Python/numpy)。它只有大约100行长,如果你更擅长阅读代码而不是文本的话,希望它能给你一个简洁、具体和有用的总结。我们现在将深入到示例结果中,使用效率更高的Lua/Torch代码库生成。
RNN的有趣之处
下面的5个字符模型都是用我在Github上发布的代码( code)训练的。每种情况下的输入都是一个包含文本的文件,我们训练一个RNN来预测序列中的下一个字符。
Paul Graham 生成器
我们首先用一个小的英文数据集作一个健全的检查。我最喜欢的数据集是保罗·格雷厄姆的论文。基本的观点是,这些文章有很多精彩之处,但是,保罗·格雷厄姆是一个相对缓慢的生成器。如果我们可以按需创造精彩之处,那不是很好吗? 这就是RNN的作用。
把过去5年中Paul Graham 所用的文章加起来,我们得到了一个大约1MB的文本文件,或者说大约有100万个字符(顺便说一句,这通常被认为是一个非常小的数据集)。技术:训练一个2层的LSTM,每层有512个隐藏节点(约350万个参数),节点后的dropout为0.5。我们将分批训练100个示例,并在100个字符内使用时序反向传播算法(Back Propagation Through Time,常简称为 BPTT,可译为“时序反向传播算法”)。 通过这些设置,在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”(“公司是一个让投资者思考的会议)。这里(Here’s)有一个5万字符的示例。
温度(Temperature):我们还可以在采样过程中调整Softmax的温度。把温度从1降到一些较低的数值(例如. 0.5分)使RNN更加自信,但其样本也更加保守。相反,较高的温度会带来更多的多样性,但代价是会犯更多的错误(例如拼写错误等)。特别是,将温度设定在接近零度时,保罗·格雷厄姆可能会说:
“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”(他们都是创业公司…)
看来我们达到了一个关于创业的无限循环。
Shakespeare
看来我们可以学会拼写英语单词了。但如果数据中有更多的结构和样式呢?为了研究这个问题,我下载了莎士比亚的所有作品,并将它们整合到一个文件中(4.4MB)。我们现在可以训练一个更大的网络,在这种情况下,让我们尝试一个3层RNN,每层有512个隐藏节点。在我们对网络进行了几个小时的培训后,我们获得了如下样本:
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个字符的样本(100,000 character sample)。 当然,您还可以使用提供的代码在不同温度下生成自己的样本。
维基百科
我们看到LSTM可以学习拼写单词和复制一般的句法结构。 让我们进一步增加难度并进行训练markdown结构(train on structured markdown)。 让我们从原始Wikipedia的Hutter Prize 100MB数据集( Hutter Prize )中训练LSTM。 按照Graves等人的方法,我使用了最初的96MB进行训练,其余的用于验证,并用了一晚上训练出一些模型。我们现在可以体验一下维基百科的文章了! 以下是一些有趣的摘录。 首先,一些基本的markdown输出( basic markdown output):
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.]]
如果您想知道,上面的yahoo网址实际上不存在,则该模型只是将其幻化了。 另外,该模型学会了正确地打开和关闭括号。该模型还可以学习很多结构化的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>
模型完全由时间戳、id等组成。另外,它会以正确的嵌套顺序适当地关闭正确的标记,如果你有兴趣,这里有10万个字符的维基百科样本(100,000 characters of sampled wikipedia)。
Algebraic Geometry (Latex)
上述结果表明,该模型在学习复杂的句法结构方面具有很好的效果。这些结果给我留下了深刻的印象,我和我的同事(Justin Johnson)决定进一步深入到结构化领域,并得到了一本关于代数/几何的书。我们下载了原始的Latex文件(16MB文件)并训练了一个多层LSTM。令人惊讶的是,得到的样本Latex像是编译好的。在我们人工完善一些问题后,你会得到看似合理的数学,这相当令人吃惊:
Sampled (fake) algebraic geometry. Here’s the actual pdf.
这是另一个示例:
More hallucinated algebraic geometry. Nice try on the diagram (right).
正如你看到的,有时模型会尝试生成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}
结尾。这是我们必须手动修复的一个例子,可能是由于依赖性太长导致的:模型在证明时,它已经忘记了它是在做证明还是引理(a proof or a lemma)。类似地,它会打开一个\ begin {enumerate}
,但忘记将其关闭。我们发现,这些问题在更大/更好的模型中变得不太常见,但是,这些都是出现的错误类型。
Linux Source Code
我想将结构化数据发展到极限,所以在最后一个挑战中,我决定使用代码。我获取了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;
}
The code looks really quite great overall. Of course, I don’t think it compiles but when you scroll through the generate code it feels very much like a giant C code base. 注意,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 %02x/%02x, "
"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!在最后一个函数中,注意代码没有返回任何内容,这恰好是正确的,因为函数签名是无效的(the function signature is void)。但是,前两个函数也被声明为void并返回值。由于长期的相互作用,这又是一种常见的错误。
有时,模型会决定采样新文件。 这通常是一个非常有趣的部分:模型首先逐个字符地列举GNU许可证,对其中的一些样本进行采样,生成一些宏,然后深入代码(The model first recites the GNU license character by character, samples a few includes, generates some macros and then dives into the code):
/*
* 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的示例Linux代码( 1MB of sampled Linux code)供您欣赏。
Generating Baby Names
为了好玩,我们再试一次吧。我们为RNN提供一个大型文本文件,其中包含列出的8000个婴儿名字,每个名字是一行(从 这里获得名字)。我们可以把这个输入到RNN,然后生成新的名称!以下是一些示例名称,仅显示训练数据中没有出现的名称(90%没有):
Rudi Levette Berice Lussa Hany Mareanne Chrestina Carissy Marylen Hammine Janye Marlise Jacacrie Hendred Romand Charienna Nenotto Ette Dorane Wallen Marly Darine Salina Elvyn Ersia Maralena Minoria Ellia Charmin Antley Nerille Chelon Walmor Evena Jeryly Stachon Charisa Allisa Anatha Cathanie Geetra Alexie Jerin Cassen Herbett Cossie Velen Daurenge Robester Shermond Terisa Licia Roselen Ferine Jayn Lusine Charyanne Sales Sanny Resa Wallon Martine Merus Jelen Candica Wallin Tel Rachene Tarine Ozila Ketia Shanne Arnande Karella Roselina Alessia Chasty Deland Berther Geamar Jackein Mellisand Sagdy Nenc Lessie Rasemy Guen Gavi Milea Anneda Margoris Janin Rodelin Zeanna Elyne Janah Ferzina Susta Pey Castina
你可以在 这里看到更多内容。Some of my favorites include “Baby” (haha), “Killie”, “Char”, “R”, “More”, “Mars”, “Hi”, “Saddie”, “With” and “Ahbort”. 很有趣不是吗。当然,在你写一本小说,或命名一个新的创业公司时,你作为一个非常有用的灵感:)
理解发生了什么
我们看到训练结束时的结果令人印象深刻,但是这些工作如何进行? 让我们运行两个简单的实验简要了解一下。
训练时样本的演变
首先,当模型训练时,看看样本文本是如何演变的。例如,我训练了一个关于托尔斯泰的《战争与和平》的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.
模型首先发现一般的单词加空格的结构,然后快速地开始学习;首先从短词开始,最后从长词开始。跨多个词的话题和主题(topics and themes)(通常是长期依赖项)在迭代很多次才开始出现。
RNN的预测和“神经元”激活的可视化
另一个有趣的可视化方法是查看各个字符的预测分布。在下面的可视化中,我们从验证集(沿蓝/绿行显示)中提供一个Wikipedia RNN模型字符数据,模型猜测5个最有可能是下一个的字符,并将其可视化(用红色标记)。猜测用概率来表示(所以深红色=被判断为很有可能,白色=不太可能)。 例如,在某些字符段中,模型对下一个字母是什么非常有信心(例如,模型对http:// www。序列中的字符非常有信心)。随机选择RNN隐藏层的神经元并激活,以此对输入字符序列(蓝色/绿色)进行染色,可以把它想象成绿色=非常兴奋,蓝色=不太兴奋(对于熟悉LSTMs细节的人来说,这些是位于隐藏状态向量中,介于[-1,1]之间的值。该值是接受门控和tanh处理的LSTM细胞单元。)直观地说,这是在RNN读取输入序列时,观察RNN“大脑”中某些神经元的激活频率(firing rate)。不同的神经元可能在寻找不同的模式;下面我们将看到4个不同的模式,我认为有趣并可以解释(也有很多不是):
图片中突出显示的神经元似乎对url非常兴奋,并在url之外关闭。LSTM可能使用这个神经元来记住它是否处于url中。
当RNN位于[[]]的markdown环境中,该被标记的神经元变得非常兴奋,并会在神经元之外关闭。有趣的是,神经元在看到字符“[”后不能马上启动,它必须等待第二个“[”然后激活。计算模型中是否有一个或两个“[”的任务很可能是用不同的神经元完成的。
这里我们看到一个似乎可以在[[]]环境中线性变化的神经元。换句话说,该神经炎的激活给RNN一个穿越[[]]范围的时间坐标系。RNN可以依靠位于[[]]范围的早/晚程度(可能是),使不同字符更有可能/不可能出现。
这是另一个行为非常局部的神经元:它相对安静,在“ www”序列中的第一个“ w”之后立即关闭。 RNN可能使用该神经元来计算它在“ www”序列中的距离,以便它可以知道是应该发出另一个“ w”,还是否应该启动URL神经元。
当然,由于RNN的隐藏状态是一个巨大的、高维的、大量分布的表示,所以许多结论都有点像空中楼阁(hand-wavy)。这些可视化是用自定义的HTML/CSS/Javascript生成的,如果您想创建类似的东西,可以在这里( here)看到所涉及内容的草图。我们还可以通过排除最可能的预测来压缩这种可视化,并且只看文本,通过激活单元格来着色。可以看到,除了很大一部分细胞不做任何可解释的事情外,约有5%的细胞学会了有趣和可解释性的算法:
我们还可以通过排除最可能的预测来压缩这种可视化,并且只可视化文本,通过激活单元格来着色。我们可以看到,除了很大一部分细胞不做任何可解释的事情外,大约5%的细胞已经学会了非常有趣和可解释的算法:
同样,这个样做的好处是,所有地方(例如,如果你想预测下一个字符 )都不需要硬编码(hardcode),这有助于知道当前是否正在处理一个引用。
(Again, what is beautiful about this is that we didn’t have to hardcode at any point that if you’re trying to predict the next character it might, for example, be useful to keep track of whether or not you are currently inside or outside of quote. )
我们只是对原始数据进行了LSTM培训,它确定这是一个有用的跟踪数据。 换句话说,它的一个单元在训练过程中逐渐进行自我调整,成为报价检测单元,因为这有助于其更好地执行最终任务。这是一个最直接、最引人注目的例子,说明了深度学习模式(通常是端到端的训练)的强大之处来自何方。
源代码
希望我已经让你相信,训练字符级语言模型是一个非常有趣的练习。 你可以使用我在Github上发布的char-rnn代码(char-rnn code )(获得MIT许可)来训练自己的模型。它接受一个大的文本文件并训练一个字符级模型,然后你可以从中进行采样。 此外,如果你有GPU,则也有帮助,否则在CPU上的训练速度会慢10倍左右。 无论如何,如果你最终对一些数据进行了培训并获得了有趣的结果,请告诉我! 另外,如果你在Torch / Lua代码库中迷路了,请记住,它只是这个100行代码(100-line gist.)的一个更奇特的版本。
简短的题外话。 该代码用 Torch 7编写,最近已成为我最喜欢的深度学习框架。 在过去的几个月中,我刚刚开始使用Torch / LUA,但并非一帆风顺(我花了大量时间在Github上浏览原始的Torch代码,并询问他们的想法以完成工作), 但是一旦掌握了很多东西,它就会提供很大的灵活性和速度。 我过去也曾与Caffe和Theano合作,我相信Torch虽然并不完美,但其抽象和哲学水平却比其他人更好。 我认为有效框架的理想功能是:
-
具有很多功能(切片,数组/矩阵操作等)的CPU / GPU透明Tensor库
-
脚本语言(理想情况下为Python)中的一个完全独立的代码库,可在Tensor上运行并实现所有深度学习功能(前进/后退,计算图等)
-
应该可以轻松共享预先训练的模型(Caffe做得很好,其他人做不到),并且至关重要的是
-
没有编译步骤(或至少没有当前在Theano中完成的步骤)。 深度学习的趋势是朝着更大,更复杂的网络发展,这些网络会在复杂的图中随时间展开。 至关重要的是,这些文件不能长时间编译,否则将大大缩短开发时间。 其次,通过编译可以放弃解释性和有效记录/调试的能力。 如果为了提高生产效率而开发了图表,则可以选择对其进行编译。
进一步阅读
在文章结束之前,我还想将RNN定位在更广阔的背景下,并提供当前研究方向的概述。 RNN最近在深度学习领域引起了极大的轰动和兴奋。 与卷积网络类似,它们已经存在了几十年,但是它们的全部潜力直到最近才开始得到广泛认可,这在很大程度上是由于我们不断增长的计算资源。 以下是一些近期发展的简要概述(肯定不是完整的清单,其中很多工作都来自1990年代的研究,请参见相关工作部分):
在NLP/Speech领域,RNNs将语音转换成文本( transcribe speech to text,),执行机器翻译,生成手写文本( machine translation, generate handwritten text),当然,它们已经被用作强大的语言模型( (Sutskever et al.) (Graves)(Mikolov et al.)(都是在字符和单词的层次上)。目前看来,单词级模型比字符级模型工作得更好,但这肯定是暂时的。
计算机视觉。RNN也在计算机视觉中迅速普及。例如,我们在帧级视频分类、图像字幕( video classification, image captioning )(也包括我自己的工作和许多其他工作)、视频字幕( video captioning)和最近的视觉问答( visual question answering)中看到了RNNs。在计算机视觉论文中,我个人最喜欢的RNNs是视觉注意的递归模型(Recurrent Models of Visual Attention),这是由于它的高层次方向(用扫视图像的顺序处理)和低层次建模(强化学习规则,这是强化学习中策略梯度方法的一个特例,它允许训练执行不可微计算的模型(在本例中是浏览图像)。我相信,这种混合模型由CNN的原始感知和RNN的浏览策略混合而成,将在感知中变得非常普遍,尤其是对于更复杂的任务,这些任务超出了在普通视图中对某些对象进行分类的范围。
归纳推理,记忆和注意力。 另一个极为激动人心的研究方向是着眼于解决普通循环网络的局限性。 一个问题是RNN不能归纳:它们可以很好地记忆序列,但是不一定总是以正确的方式显示出令人信服的泛化迹象(我将提供一些更具体的指针)。 第二个问题是它们不必要地将其表示大小与每个步骤的计算量相结合。 例如,如果你将隐藏状态向量的大小加倍,则由于矩阵乘法,每一步的触发器数量将增加四倍。 理想情况下,我们希望保持庞大的表示形式/内存(例如,包含所有Wikipedia或许多中间状态变量),同时保持每时间步长的计算保持不变的能力。
朝着这些方向发展的第一个令人信服的例子是在DeepMind的《神经图灵机》( Neural Turing Machines)中提出的。这篇文章叙述了一种构建模型的方法,该模型可以在大型外部存储阵列(memory arrays)与较小的一组存储寄存器(将其视为我们的工作存储器)之间执行读取/写入操作。最重要的是,NTM论文还展示了非常有趣的记忆寻址机制(memory addressing mechanisms),这些机制是通过一个(软的,完全可微的(soft, and fully-differentiable))注意模型(attention model)实现的。软注意力( soft attention)的概念已被证明是强大的建模功能,并且在神经机器翻译(Neural Machine Translation)中也得到了特别的关注,这是通过共同学习对齐和翻译的神经机器翻译,以进行(玩具)问题解答的机器翻译和存储网络。事实上,我可以这么说
注意力的概念是近年来神经网络最有趣的结构性创新。
现在,我不想深入讨论太多细节,但是内存寻址(memory addressing)中使用软注意力体系(soft attention scheme)会很方便,因为它可以使模型完全可微分(fully-differentiable)。但不幸的是,它牺牲了效率,因为所有可能被注意的事物都被注意了。可以把它认为是一个C语言中声明的指针,在整个记忆中,它不指向特定地址,而是定义所有地址的整个分布。(Think of this as declaring a pointer in C that doesn’t point to a specific address but instead defines an entire distribution over all addresses in the entire memory),取消引用指针将返回所指向内容的加权总和(那将是一个昂贵的操作!)。这激发了多位作者将软注意力模型交换为硬注意力,其中一个人采样了一块特定的内存来参与(例如,对某个存储单元执行读/写操作,而不是对所有存储单元进行某种程度的读/写操作)。该模型在更富有哲理性,可伸缩性和效率更高,但不幸的是,它也是不可微分的(non-differentiable)。这就需要使用强化学习文献中的技术(例如REINFORCE),在该技术中人们完全习惯了不可微分的交互的概念。这是一项正在进行的工作,但是已经研究了这些注意力模型,例如, Inferring Algorithmic Patterns with Stack-Augmented Recurrent Nets, Reinforcement Learning Neural Turing Machines, 和 Show Attend and Tell.
人。如果你想阅读RNN,我推荐Alex Graves,Ilya Sutskever和Tomas Mikolov的论文。更多关于 REINFORCE和更一般的强化学习和政策梯度方法(REINFORCE是一个特例)大卫西尔弗的班,或彼得阿比勒的班之一。(最后这段英文实在看不懂啥意思…)
代码。如果你想体验训练RNN,可以用Theano和keras。本文用的代码基于Torch。或者我刚才编写的原始numpy代码的要点,它实现了一个高效的、成批的LSTM向前和向后传递。你也可以看看我基于numpy的NeuralTalk,它使用RNN / LSTM来为图像添加字幕,或者也许是Jeff Donahue的Caffe实现。
结论
我们已经了解了RNN,它们的工作原理,为什么会变得很重要,我们已经在几个有趣的数据集上训练了RNN字符级语言模型,并且了解了RNN的发展方向。我相信它们将成为智能系统的无处不在的关键组成部分。
最后,为了向本文添加一些元数据,我在此博客文章的源文件上训练了RNN。 不幸的是,在大约46K字符处,我没有编写足够的数据来正确地输入RNN,但是返回的样本(在低温( low temperature )下生成以获得更典型的样本)是:
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及其运作方式的,所以很显然这是可行的:)。 下次见!