如何在PyTorch中正确实现批量输入LSTM网络?

如何在PyTorch中正确实现批量输入LSTM网络?,pytorch,Pytorch,Pytork的这一特性似乎为递归神经网络的可变输入长度提供了PackedSequence。然而,我发现正确使用它有点困难 使用pad\u padded\u sequence恢复由pack\u padded\u sequence馈送的RNN层的输出,我们得到了T x B x N张量输出,其中T是最大时间步长,B是批量大小,N是隐藏大小。我发现,对于批处理中的短序列,后续输出将全部为零 以下是我的问题 对于需要所有序列的最后一个输出的单个输出任务,简单的输出[-1]将给出错误的结果,因为该张量包含许

Pytork的这一特性似乎为递归神经网络的可变输入长度提供了
PackedSequence
。然而,我发现正确使用它有点困难

使用
pad\u padded\u sequence
恢复由
pack\u padded\u sequence
馈送的RNN层的输出,我们得到了
T x B x N
张量
输出
,其中
T
是最大时间步长,
B
是批量大小,
N
是隐藏大小。我发现,对于批处理中的短序列,后续输出将全部为零

以下是我的问题

  • 对于需要所有序列的最后一个输出的单个输出任务,简单的
    输出[-1]
    将给出错误的结果,因为该张量包含许多短序列的零。我们需要根据序列长度构造索引,以获取所有序列的单个最后输出。有没有更简单的方法
  • 对于多输出任务(例如seq2seq),通常会添加一个线性层
    nxo
    ,并将批处理输出
    txbxo
    重塑为
    tbxo
    ,并使用真实目标
    TB
    (通常是语言模型中的整数)计算交叉熵损失。在这种情况下,批处理输出中的这些零是否重要

  • 问题1-最后一个时间步

    这是我用来获取上一个timestep的输出的代码。我不知道是否有更简单的解决办法。如果是,我想知道。我遵循这一点,抓取了我的
    last\u timestep
    方法的相关代码片段。这是我的前锋

    class BaselineRNN(nn.Module):
        def __init__(self, **kwargs):
            ...
    
        def last_timestep(self, unpacked, lengths):
            # Index of the last output for each sequence.
            idx = (lengths - 1).view(-1, 1).expand(unpacked.size(0),
                                                   unpacked.size(2)).unsqueeze(1)
            return unpacked.gather(1, idx).squeeze()
    
        def forward(self, x, lengths):
            embs = self.embedding(x)
    
            # pack the batch
            packed = pack_padded_sequence(embs, list(lengths.data),
                                          batch_first=True)
    
            out_packed, (h, c) = self.rnn(packed)
    
            out_unpacked, _ = pad_packed_sequence(out_packed, batch_first=True)
    
            # get the outputs from the last *non-masked* timestep for each sentence
            last_outputs = self.last_timestep(out_unpacked, lengths)
    
            # project to the classes using a linear layer
            logits = self.linear(last_outputs)
    
            return logits
    
    问题2-掩蔽交叉熵损失

    是的,默认情况下,零填充时间步(目标)很重要。然而,很容易掩盖它们。您有两个选项,具体取决于您使用的PyTorch版本

  • PyTorch:现在PyTorch支持直接在中使用
    ignore_index
    参数进行掩蔽。例如,在语言建模或seq2seq中,我添加了零填充,我屏蔽了零填充词(目标),如下所示:

    损失函数=nn.CrossEntropyLoss(忽略索引=0)

  • PyTorch和更老版本:在PyTorch的旧版本中,屏蔽不受支持,因此您必须实施自己的解决方案。我使用的解决方案是。你也可能对此感兴趣

  • 几天前,我发现使用索引的方法可以用一行完成相同的任务

    我首先拥有数据集批次(
    [批次大小、序列长度、功能]
    ),因此对我来说:

    unpacked_out = unpacked_out[np.arange(unpacked_out.shape[0]), lengths - 1, :]
    
    其中
    unpackaged\u out
    torch.nn.utils.rnn.pad\u packaged\u序列的输出


    我已经将其与方法进行了比较,该方法看起来类似于上面Christos Baziotis使用的
    last_timestep()
    方法(也是推荐的),结果与我的情况相同。

    我正在尝试您的解决方案,我得到了错误:文件“/root/PycharmProjects/skip thinks.torch/pytorch/tmpRNN.py”,第13行,在上一个\u timestep return unpackage.gather(1,idx).squese()文件“/usr/local/lib/python3.5/dist packages/torch/autograd/variable.py”中,第684行,在gather return gather.apply(self,dim,index)运行时错误:save\u for\u backwardward只能保存输入或输出张量,但参数0不满足此条件