经常看到说rnn的训练速度比较慢,事实上我在训练过程中也发现了这个问题,但是不清楚是什么原因。

我看到说cnn在每一层的卷积计算中并行使用gpu的core进行了计算,所以速度比较快。那rnn为什么会比较慢呢?

求解答,谢谢!


因为需要一个时序一个时序按顺序计算


为什么训练RNN速度很慢?

训练Recurrent Neural Network的速度很慢,是因为每个time step的计算,都依赖于对前一time step的计算和输出结果。

Recurrent Neural Network训练速度慢的问题,在处理很长的sequence的training example会更加的明显。这个问题,也限制了deep RNN model的能够stack的RNN的数量。VGG16可训练weights的layer有16层。deep RNN能够到达4层已经很少见了。

RNN训练的速度有多慢? 用一个language model任务的例子说明。

Language Modeling Task[1]

Quasi-RNN [1] 在结构设计上不是Recurrent neural network。 它的pseudo-recurrence模似了time step的记忆,inputs layers的也很好的利用了CNN的并行性的优势。Quasi-RNN是为NLP定制的一种CNN,可以一次读入和处理整个sequence。

以下是Quasi-RNN训练速度与基于LSTM的RNN的训练速度的比较,batch size = 8

[公式] [1]

在256序列长度输入中,Quasi-RNN是基于LSTM的RNN的12.6倍。

Forward Propagation

用一个例子说明Recurrent neural network的forward computation的dependency

"They took a vacation in Hawaii and visited the islands by bike"

在bi-gram language model中,当计算单词「Hawaii」时,它以两个单词作为输入,「vacation」,在GRU block里,计算memory cell,和计算update gate/forget gate.

当计算到「and」之后的下一个单词时,正确的答案是什么?

visit

visitedvisiting

正确答案是「visited」。 如果它取决于前两个单词「Hawaii and」,但它没有「They took...」的context,它可能会出现语法错误,象是「visit」,如果是只有3个选择的话(visit, visited, visiting)。

所以这种time step based的dependency保证了后面predict新的word的时候,有前面的context words。这个context是基于time step的hidden state,或者是output word传递的。

这些是具有上下文的特性,能够在之前time steps的contextual words的情况下,在语法和语义上更准确地预测下一个单词。但是,这种time steps dependent的sequential计算,在计算效率上有明显的缺陷。上面的例子,在GRU block的RNN是这样计算的

在GRU中的forward propagation将input分成一个order set的一级单词序列

"They took a vacation in Hawaii and visited..." =&> Order set {"They", "took", ...}

  1. 取第一个word,计算memory cell and update/reset gates
  2. 取下一个word,根据先前的输出hidden state/output, 计算hidden state, output
  3. 重复以上步骤10次,因为|sequence length| = 12

Recurrent neural network的forward propagation的计算复杂度为O(| Sequence Length |)。 Sequence越长,所需的计算量就越多。 并且长Sequence中的每个time step都包括一个memory I/O操作。这非常慢并且受GPU的最大线程和最大内存带宽的约束。

[1] James Bradbury, Stephen Merity, Caiming Xiong, Richard Socher, ICLR 2017, QUASI-RECURRENT NEURAL NETWORKS


首先,说我的观点,GPU计算RNN的过程不慢,而是RNN的特性不利于GPU加速。

慢的概念需要一个参照物,我们知道CNN里面模型空间结构越小,前向计算越快,而RNN这个看起来空间结构很小的模型,计算时间却不和其空间结构成比例,这里模型空间结构就是参照物。

RNN除了有空间结构外,还有时序结构。由于,所有的时序网路都共享了同一套参数,就使得空间结构显得特别小。

终于来了,为什么会慢呢?有两点,

  1. 计算量大。即便共享了参数,计算量却没有显著减少,RNN都是用全联接的结构。
  2. 计算依赖。后一帧的计算依赖前一帧的输出。

因此,这意味RNN的每个Time Step都要在CPU和GPU来回调度一次,而CNN每一层才需要调度一次(假设GPU存储充足)。

所以,综上。

若有错误,还望指出。


  1. Xt代表输入序列中的第t步元素,例如语句中的一个汉字。一般使用一个one-hot向量来表示,向量的长度是训练所用的汉字的总数(或称之为字典大小),而唯一为1的向量元素代表当前的汉字。
  2. St代表第t步的隐藏状态,其计算公式为St=tanh(U*Xt+W*St-1)。也就是说,当前的隐藏状态由前一个状态和当前输入计算得到。考虑每一步隐藏状态的定义,可以把St视为一块内存,它保存了之前所有步骤的输入和隐藏状态信息。S-1是初始状态,被设置为全0。
  3. Ot是第t步的输出。可以把它看作是对第t+1步的输入的预测,计算公式为:Ot=softmax(V*St)。可以通过比较Ot和Xt+1之间的误差来训练模型。
  4. U,V,W是RNN的参数,并且在展开之后的每一步中依然保持不变。这就大大减少了RNN中参数的数量。

假设真实的输出应该是

,那么误差可以定义为

,

是训练样本的index。整个网路的误差

我们将RNN再放大一些,看看细节

矩阵向量化表示

所以梯度为:

其中

是点乘符号,即对应元素乘。

简单点来说,RNN的训练过程:假设一个输入文本长度为20,然后对loss求导(W,U,V),由于是前后相互影响的,整个求导是一个叠加的过程,即可得到求导后的变化量,整个UVW是共享的。

如何有效训练RNN是一个活跃的研究领域,有很多方法,但还没有哪种表现出了明显的优势,因此也让今天要介绍的这项工作值得注意。来自ASAPP公司和MIT的两位研究人员提出了一种名为「简单循环单元」(Simple Recurrent Unit,SRU)的结构,对现有门控单元做了调整,简化了状态计算的过程,从而展现出了与CNN、注意力和前馈网路相同的并行性。实验结果表明,SRU训练速度与CNN一样,并在图像分类、机器翻译、问答、语音识别等各种不同任务中证明了有效性。

先看论文摘要,有个大概的了解:

标题非常直接,也是很多人都想实现的——《像训练CNN一样快速训练RNN》:

摘要

RNN因其状态计算固有的特性难以并行化因而很难扩展。例如,的前向计算要到的计算完成后才能开始,这构成了并行计算的主要瓶颈。在这项工作中,我们提出了一种RNN的替代实现,简化了状态计算过程,展现更多的并行性。我们所提出的循环单元,运行速度与卷积层一样快,比cuDNN优化的LSTM快5-10倍。我们展示了这种循环单元在广泛应用中的有效性,包括分类、问答、语言建模、翻译和语音识别。我们开源了在PyTorch和CNTK中的实现。

简单循环单元SRU,简化状态计算,速度与CNN一样快

近来深度学习取得的许多进展都源于模型容量的增加和计算力的相应提升。模型容量增大,通常会涉及使用更大、更深的网路,而这些网路又需要复杂的超参数设置和调整。因此,不断增大的模型和超参数数量也大大增加了训练时间。

显然,计算力已经成为深度学习研究的一大主要瓶颈。作为应对,研究人员开始深入挖掘并行计算的潜力,很多人使用GPU加速训练来扩展深度学习。不过,虽然诸如卷积和注意力的运算非常适合于多线程/GPU计算,但是循环神经网路(RNN)仍然不太适合并行化。在典型的RNN实现中,输出状态的计算需要等到计算完成后才能开始。这阻碍了独立计算,并大大减慢了序列处理的速度。

图1展示了cuDNN优化后的LSTM和使用conv2d的字级卷积的处理时间。可以看出,两者区别非常明显,即使是优化后的LSTM,运行速度也可能慢10倍多。

图1:cuDNN优化后的LSTM和使用conv2d的字级卷积的处理时间:即使是优化后的LSTM,运行速度也可能慢10倍多

于是,作者提出了「简单循环单元」(Simple Recurrent Unit,SRU),并在论文中表示其计算速度明显快于现有的循环实现。SRU简化了状态计算的过程,从而展现出了与CNN、注意力和前馈网路相同的并行性。

具体说,虽然SRU的内部状态ct的更新仍然与前一个状态ct-1有关,但是在循环步骤中不再依赖于。因此,SRU中的所有矩阵乘法(即gemm)和元素方面的操作可以在不同的维度和步骤中实现并行化。

SRU实现:增加highway连接和变分dropout

那么,SRU是怎么实现的呢?

作者指出,当前性能最佳的RNN,比如LSTM和GRU,都使用神经门(neural gate)控制信息流,缓解梯度消失(或爆炸)的问题。

因此,他们在此基础上,对门控单元进行了调整。具体说,作者新增加了两个特征:首先,他们在循环层之间增加了highway连接,因为此前的研究已经证明,像highway连接这样的skip connections,在训练深度网路时非常有效;其次,在将RNN正则化时,他们在标准的dropout外,增加了变分dropout,变分dropout在时间步长t与dropout使用相同的mask。

然后,作者将和步骤t的神经门之间的连接全部丢弃,以这种方法来加速循环计算。相比之下,现有的RNN在实现时是要使用先前的输出状态的。

经过这样的改善后,对于现有的深度学习库,SRU已经可以实现超过5倍的加速。接下来,作者还进行了CUDA级的优化,并在一系列不同的基准上进行测试,评估SRU的效果。

实验评估结果:图像分类、语音识别、机器翻译等任务,实现更好性能的同时,训练速度更快

作者还在分类、问答、语言建模、翻译和语音识别等一系列不同任务中评估了SRU。

实验结果证实了SRU的有效性——与这些任务的循环(或卷积)基准模型相比,SRU在实现更好性能的同时,训练速度也更快。

  • 图像分类

  • 斯坦福SQuAD文本处理

  • 语言建模

  • 语音识别

  • 机器翻译

  • 论文地址:https://arxiv.org/pdf/1709.02755.pdf
  • Github地址:https://github.com/taolei87/sru

对于有使用GPU需求的朋友,可以再智星云租用GPU,性价比很高

发布于 2020-11-21继续浏览内容知乎发现更大的世界打开Chrome继续xingxingxingxing深度学习专业调参师,从不相信「人工智慧」

建议编写一个只有一层一个节点的神经网路,其实就是线性拟合,看看速度。

然后你看看一个RNN里面有多少个参数 (知名CNN网路都是M级别参数)。结合上面拟合的速度和RNN的参数就知道为什么慢了。


建议编写一个只有一层一个节点的神经网路,其实就是线性拟合,看看速度。

然后你看看一个RNN里面有多少个参数 (知名CNN网路都是M级别参数)。结合上面拟合的速度和RNN的参数就知道为什么慢了。


肯定相当慢啊。cnn是一个batch做一次前向运算和反向传播;rnn,lstm之类是一个batch的每一个元素都要依次做一次前向和反向运算;以NLP为例,cnn是以一个句子为样本,一次前向和反向运算就计算完这个样本了;rnn是逐个字词的挨个前向运算,最后挨个反向传播之后,才算是计算完这个样本。

因为反向传播的路径长....


attention+mask替代rnn,可并行计算


很大程度上 我同意崔向阳的观点!在此 我想重述一下:

1、RNN/seq2seq的模型,此类模型中的变数是按照时间戳一步步向前(反向传播时,为向后)进行的,如Encoder为例, [公式] ,其中 [公式] 代表隐状态, [公式] 代表输入。这也就决定了循环网路中的计算是按照时间戳(输入、输出位置)来分解计算的,加之 输入往往是可变长序列,且我们想捕获的就是这种时序上的依赖,这种固有的序列化本质阻碍了并行化处理RNN网路的加速。

2、在CNN网路中比较方便利用批处理技术,即 batch by batch的处理数据,而且在per batch内部可以有效地利用向量化技术来加速。RNN网路中就很难做到这一点儿。当然也有一些计算分解技术,但是实现起来就不是那么直观。


因为序列化,不能并行


推荐阅读:
相关文章