【问题标题】:How to deal with dropout in between LSTM layers when using PackedSequence in PyTorch?在 PyTorch 中使用 PackedSequence 时如何处理 LSTM 层之间的丢失?
【发布时间】:2021-12-20 04:42:42
【问题描述】:

我正在为我的硕士论文创建一个用于特征提取的 LSTM 自动编码器。但是,我在将 dropout 与 LSTM 层相结合时遇到了很多麻烦。

由于它是一个自动编码器,我遇到了一个瓶颈,这是通过两个独立的 LSTM 层实现的,每个层的 num_layers=1,中间有一个 dropout。我有长度非常不同的时间序列,因此我发现打包序列是一个好主意。

但是,根据我的实验,我必须在第一个 LSTM 之前打包数据,在 dropout 之前解包,然后在第二个 LSTM 之前再次打包。这似乎非常低效。有没有更好的办法?我在下面提供了一些示例代码和另一种实现方式。

当前可行但可能不是最佳的解决方案:

class Encoder(nn.Module):

    def __init__(self, seq_len, n_features, embedding_dim, hidden_dim, dropout):
        super(Encoder, self).__init__()

        self.seq_len = seq_len
        self.n_features = n_features
        self.embedding_dim = embedding_dim
        self.hidden_dim = hidden_dim

        self.lstm1 = nn.LSTM(
            input_size=n_features,
            hidden_size=self.hidden_dim,
            num_layers=1,
            batch_first=True,
        )

        self.lstm2 = nn.LSTM(
            input_size=self.hidden_dim,
            hidden_size=embedding_dim,
            num_layers=1,
            batch_first=True,
        )

        self.drop1 = nn.Dropout(p=dropout, inplace=False)

    def forward(self, x):
        x, (_, _) = self.lstm1(x)
        x, lens = pad_packed_sequence(x, batch_first=True, total_length=self.seq_len)
        x = self.drop1(x)
        x = pack_padded_sequence(x, lens, batch_first=True, enforce_sorted=False)
        x, (hidden_n, _) = self.lstm2(x)

        return hidden_n.reshape((-1, self.n_features, self.embedding_dim)), lens

替代方案,可能更好,但目前无法解决;

class Encoder2(nn.Module):

    def __init__(self, seq_len, n_features, embedding_dim, hidden_dim, dropout):
        super(Encoder2, self).__init__()

        self.seq_len = seq_len
        self.n_features = n_features
        self.embedding_dim = embedding_dim
        self.hidden_dim = hidden_dim

        self.lstm1 = nn.LSTM(
            input_size=n_features,
            hidden_size=self.hidden_dim,
            num_layers=2,
            batch_first=True,
            dropout=dropout,
            proj_size=self.embedding_dim,
        )

    def forward(self, x):
        _, (h_n, _) = self.lstm1(x)
        return h_n[-1].unsqueeze(1), lens

非常感谢有关使用时间序列、打包序列、lstm 单元和 dropout 的任何帮助和提示,因为我在 Internet 上的其他地方没有找到太多文档/指导。谢谢!

最好的,拉斯安基尔

【问题讨论】:

  • 您的“替代”解决方案是正确的方法。你的意思是“不工作的解决方案”?什么不工作?
  • 感谢@ayandas 的评论!好的,所以根据您的理解,这些实现将是等效的,但第二个更好?无法正常工作,因为它仍然会引发有关某些尺寸等的错误。正在调试硬 atm。

标签: pytorch time-series lstm autoencoder dropout


【解决方案1】:

对于以后,经过大量的试验和错误,自动编码器的以下完整代码似乎工作得很好。使包装和拆包正常工作是主要障碍。我认为,线索是通过使用 proj_size、num_layers 和 dropout 参数来尝试利用 LSTM 模块的价值。

class EncoderV4(nn.Module):
    def __init__(
        self, seq_len, n_features, embedding_dim, hidden_dim, dropout, num_layers
    ):
        super().__init__()

        self.seq_len = seq_len
        self.n_features = n_features
        self.embedding_dim = embedding_dim
        self.hidden_dim = hidden_dim
        self.num_layers = num_layers

        self.lstm1 = nn.LSTM(
            input_size=n_features,
            hidden_size=self.hidden_dim,
            num_layers=num_layers,
            batch_first=True,
            dropout=dropout,
            proj_size=self.embedding_dim,
        )

    def forward(self, x):
        _, (h_n, _) = self.lstm1(x)
        return h_n[-1].unsqueeze(1)


class DecoderV4(nn.Module):
    def __init__(self, seq_len, input_dim, hidden_dim, n_features, num_layers):
        super().__init__()

        self.seq_len = seq_len
        self.input_dim = input_dim
        self.hidden_dim = hidden_dim
        self.n_features = n_features
        self.num_layers = num_layers

        self.lstm1 = nn.LSTM(
            input_size=input_dim,
            hidden_size=hidden_dim,
            num_layers=num_layers,
            proj_size=n_features,
            batch_first=True,
        )

    def forward(self, x, lens):
        x = x.repeat(1, self.seq_len, 1)
        x = pack_padded_sequence(x, lens, batch_first=True, enforce_sorted=False)
        x, _ = self.lstm1(x)

        return x


class RecurrentAutoencoderV4(nn.Module):
    def __init__(
        self, seq_len, n_features, embedding_dim, hidden_dim, dropout, num_layers
    ):
        super().__init__()

        self.encoder = EncoderV4(
            seq_len, n_features, embedding_dim, hidden_dim, dropout, num_layers
        )
        self.decoder = DecoderV4(
            seq_len, embedding_dim, hidden_dim, n_features, num_layers
        )

    def forward(self, x, lens):

        x = self.encoder(x)
        x = self.decoder(x, lens)

        return x

使用此自动编码器的完整代码和论文可以分别在 GitHub 和 arXiv 找到。

【讨论】:

    猜你喜欢
    • 2017-11-22
    • 1970-01-01
    • 2017-09-26
    • 2017-09-13
    • 1970-01-01
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    相关资源
    最近更新 更多