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

sta*_*low 14 pytorch

这个版本的PyTorch似乎PackedSequence为递归神经网络提供了可变长度的输入.但是,我发现正确使用它有点困难.

使用pad_packed_sequence以恢复其通过喂食RNN层的输出pack_padded_sequence,我们得到了一个T x B x N张量outputs,其中T为最大的时间步长,B是批量大小和N是隐藏的尺寸.我发现对于批处理中的短序列,后续输出将全为零.

这是我的问题.

  1. 对于单个输出任务,其中一个将需要所有序列的最后一个输出,simple outputs[-1]将给出错误的结果,因为该张量包含许多短序列的零.需要按序列长度构建索引以获取所有序列的单个最后输出.有更简单的方法吗?
  2. 对于多输出任务(例如seq2seq),通常会添加一个线性层N x O并将批量输出重新整形T x B x OTB x O并使用真实目标TB(通常是语言模型中的整数)计算交叉熵损失.在这种情况下,批量输出中的这些零值是否重要?

Chr*_*tis 8

问题1 - 最后一个时间步

这是我用来获取最后一个时间步的输出的代码.我不知道是否有更简单的解决方案.如果是的话,我想知道.我按照这个讨论,抓住了我的last_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
Run Code Online (Sandbox Code Playgroud)

问题2 - 蒙面交叉熵损失

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

  1. PyTorch 0.2.0:现在pytorch支持直接在屏蔽CrossEntropyLoss,与ignore_index说法.例如,在语言建模或seq2seq中,我添加零填充,我掩盖零填充的单词(目标),就像这样:

    loss_function = nn.CrossEntropyLoss(ignore_index = 0)

  2. PyTorch 0.1.12及更早版本:在较旧版本的PyTorch中,不支持屏蔽,因此您必须实现自己的解决方法.我使用的解决方案是jihunchoimasked_cross_entropy.py.您可能也对此讨论感兴趣.