图:pixabay
原文来源:github
「机器人圈」编译:嗯~阿童木呀、多啦A亮
该存储库包含一篇用PyTorch实现的Salesforce Research发布的QRNN(Quasi-Recurrent Neural Networks)(
https://arxiv.org/abs/1611.01576)论文。
可以这样说,QRNN能够提供与LSTM相类似的精确度,但在基于用例的情况下,要比高度优化的NVIDIA cuDNN LSTM实施速度快2至17倍。
如果你想要安装,那么只需运行:
pip install cupy pynvrtc git+https://github.com/salesforce/pytorch-qrnn
如果你想要在你的相关研究中使用此代码或结果,请引用:
@article{bradbury2016quasi,
title={{Quasi-Recurrent Neural Networks}},
author={Bradbury, James and Merity, Stephen and Xiong, Caiming and Socher, Richard},
journal={International Conference on Learning Representations (ICLR 2017)},
year={2017}
}
软件要求
该代码库需要Python 3,PyTorch,pynvrtc(NVIDIA的绑定到NVRTC的Python)和CuPy。虽然代码库包含QRNN的CPU实现,但如果可能的话,默认使用GPU QRNN实现。在requirements.txt中将提供相关需求。
用法
QRNN API旨在在许多标准用例中与长短期记忆网络(LSTM)兼容。因此,最简单的做法是用QRNN替换任何GRU或LSTM模块。
注意:目前为止双向QRNN尚不支持,但在不久的将来一定会实现的。
import torch
from torchqrnn import QRNN
seq_len, batch_size, hidden_size = 7, 20, 256
size = (seq_len, batch_size, hidden_size)
X = torch.autograd.Variable(torch.rand(size), requires_grad=True).cuda()
qrnn = QRNN(hidden_size, hidden_size, num_layers=2, dropout=0.4)
qrnn.cuda()
output, hidden = qrnn(X)
print(output.size(), hidden.size())
QRNN的完整文档如下所示:
QRNN(input_size,hidden_size,num_layers,dropout = 0):
将多层准循环神经网络(QRNN)应用于输入序列。
参数:
input_size:输入x中的预期特征数。
hidden_size:隐藏状态下的特征数h。如果未指定,则使用输入大小。
num_layers:要生成的QRNN层数。
layers:用于QRNN模块的预构建QRNN图层列表(可选)。
save_prev_x:是否存储先前的输入以供将来的卷积窗口使用(即,用于连续的序列,如语言建模)。如果为True,则必须调用重置以删除缓存的先前x值。默认值:False。
window:定义卷积窗口的大小(计算QRNN值时要查看多少个标记字)。支持1和2. 默认值: 1。
zoneout:是否将zoneout(即未能更新隐藏状态的元素)应用到隐藏状态更新。默认值:0。
output_gate:如果为True,则执行QRNN-fo(在输出门输出)。如果为False,则执行QRNN-f。默认值:True。
use_cuda:如果为True,则使用快速定制的CUDA内核。如果为False,使用简单的循环。默认值:True。
输入:X,隐藏
- X(seq_len,batch,input_size):包含输入序列的特征的张量。
- hidden(layers,batch,hidden_size):包含QRNN的初始隐藏状态的张量。
输出:output,h_n
- output(seq_len,batch,hidden_size):包含每个时间步的QRNN输出的张量。
-h_n (layers, batch, hidden_size):包含t = seq_len的隐藏状态的张量
包含的QRNN层支持大小为1或2的卷积窗口,但将来会扩展,用以支持任意卷积。
如果你使用大小为2的卷积窗口(即查看前两个时间步的输入来计算输入),并且想要批量运行一个长序列,例如使用BPTT时,可以设置save_prev_x = True并调用reset 当你希望重置以前的输入缓存。
如果要在每个QRNN层的定义中具有灵活性,可以构建单独的QRNNLayer模块,并使用层参数将其传递给QRNN模块。
速度
速度比NVIDIA的cuDNN LSTM快2到17倍,差异是由于批量大小和序列长度的变化。最大的收益是针对小批量或长序列长度,都强调了由于强制顺序性导致的LSTM并行化难度。有关完整信息,请参阅准循环神经网络论文(
https://arxiv.org/abs/1611.01576)。
下图是QRNN论文的图4:
左图:在一批105时间步的20个例子中,二层640单位PTB LM的训练速度。“RNN”和“softmax”包括正向和反向时间,而“优化开销(optimization overhead)”包括梯度剪裁、L2正则化和SGD计算。右:对于具有给定批量大小和序列长度的数据,单独的320单位QRNN层的推理速度优于在相同大小的cuDNN LSTM层上。训练结果相似。
使用ForgetMult将QRNN速度优势扩展到其他循环结构
QRNN架构的速度优势有两个主要来源:将所有计算分批为几个大矩阵乘法的能力以及使用快速元素的递归函数。这个名为ForgetMult的递归函数是通用的,可以在其他场景下使用。 ForgetMult有两个参数——候选输入x和忘记门f——并计算h = f * x +(1-f)* hm1,其中hm1是先前的隐藏状态输出。
QRNN类是围绕深度学习的浅层包裹,它为候选x、忘记门f和输出门o执行大矩阵乘法。 任何需要循环并且可以具有候选x和忘记门f的预计算值的其他操作可以使用这种快速形式的循环。
ForgetMult模块的使用示例:output = ForgetMult()(f,x,hidden)。
ForgetMult computes a simple recurrent equation:
h_t = f_t * x_t + (1 - f_t) * h_{t-1}
This equation is equivalent to dynamic weighted averaging.
Inputs: X, hidden
- X (seq_len, batch, input_size): tensor containing the features of the input sequence.
- F (seq_len, batch, input_size): tensor containing the forget gate values, assumed in range [0, 1].
- hidden_init (batch, input_size): tensor containing the initial hidden state for the recurrence (h_{t-1}).
- cuda: If True, use the fast element-wise CUDA kernel for recurrence. If False, uses naive for loop. Default: True.
也许你需要一点点帮助
修改ForgetMult CUDA内核以生成BackwardForgetMult。这将启用双向QRNN。输入应该是相同的f 和 x ,但内核应该通过输入反向传入。
o双向QRNN支持(需要上述修改)。
o启用QRNN图层在多multi-GPU环境中工作。
o支持PyTorch的PackedSequence,使得可变长度序列被正确地掩码。
o显示如何以其他通用方式使用底层的快速重复运算符ForgetMult。
附《Quasi-Recurrent Neural Networks》论文摘要
循环神经网络是对序列数据进行建模的强大工具,但是每个时间步长的计算对前一个时间步长输出的依赖性限制了并行性,并使得RNN对于很长的序列的处理变得较为笨重。我们引入了QRNN,这是一种神经序列建模的方法,改变了卷积层,即可跨时间步长并行应用,并且是一个可以并行应用的极简循环池函数。尽管缺乏可训练的循环层,堆叠的QRNN具有比具有相同隐藏尺寸的堆叠LSTM有着更好的预测精度。由于它们的并行性增加,它们在训练和测试时间上快了16倍。而在语言建模,情绪分类和字符级神经机器翻译的实验也验证了这些优点,并强调了QRNN作为各种顺序任务的基本构件的可行性。
源代码:
https://github.com/salesforce/pytorch-qrnn。
论文:
https://arxiv.org/abs/1611.01576。