【问题标题】:Does a clean and extendable LSTM implementation exists in PyTorch? [closed]PyTorch 中是否存在干净且可扩展的 LSTM 实现? [关闭]
【发布时间】:2018-10-14 13:05:50
【问题描述】:

我想自己创建一个LSTM 类,但是我不想再次从头开始重写经典的LSTM 函数。

深入PyTorch的代码,我只发现一个肮脏的实现涉及至少3-4个具有继承性的类:

  1. https://github.com/pytorch/pytorch/blob/98c24fae6b6400a7d1e13610b20aa05f86f77070/torch/nn/modules/rnn.py#L323
  2. https://github.com/pytorch/pytorch/blob/98c24fae6b6400a7d1e13610b20aa05f86f77070/torch/nn/modules/rnn.py#L12
  3. https://github.com/pytorch/pytorch/blob/98c24fae6b6400a7d1e13610b20aa05f86f77070/torch/nn/_functions/rnn.py#L297

LSTMclean PyTorch 实现是否存在于某处?任何链接都会有所帮助。

例如,我知道 TensorFlow 中存在 LSTM 的干净实现,但我需要派生一个 PyTorch

举个明显的例子,我正在寻找的是一个像 this 一样干净的实现,但是在 PyTorch 中:

【问题讨论】:

    标签: coding-style open-source lstm implementation pytorch


    【解决方案1】:

    我找到的最佳实现在这里
    https://github.com/pytorch/benchmark/blob/master/rnns/benchmarks/lstm_variants/lstm.py

    它甚至实现了四种不同的循环 dropout 变体,非常有用!
    如果你把辍学部分拿走,你会得到

    import math
    import torch as th
    import torch.nn as nn
    
    class LSTM(nn.Module):
    
        def __init__(self, input_size, hidden_size, bias=True):
            super(LSTM, self).__init__()
            self.input_size = input_size
            self.hidden_size = hidden_size
            self.bias = bias
            self.i2h = nn.Linear(input_size, 4 * hidden_size, bias=bias)
            self.h2h = nn.Linear(hidden_size, 4 * hidden_size, bias=bias)
            self.reset_parameters()
    
        def reset_parameters(self):
            std = 1.0 / math.sqrt(self.hidden_size)
            for w in self.parameters():
                w.data.uniform_(-std, std)
    
        def forward(self, x, hidden):
            h, c = hidden
            h = h.view(h.size(1), -1)
            c = c.view(c.size(1), -1)
            x = x.view(x.size(1), -1)
    
            # Linear mappings
            preact = self.i2h(x) + self.h2h(h)
    
            # activations
            gates = preact[:, :3 * self.hidden_size].sigmoid()
            g_t = preact[:, 3 * self.hidden_size:].tanh()
            i_t = gates[:, :self.hidden_size]
            f_t = gates[:, self.hidden_size:2 * self.hidden_size]
            o_t = gates[:, -self.hidden_size:]
    
            c_t = th.mul(c, f_t) + th.mul(i_t, g_t)
    
            h_t = th.mul(o_t, c_t.tanh())
    
            h_t = h_t.view(1, h_t.size(0), -1)
            c_t = c_t.view(1, c_t.size(0), -1)
            return h_t, (h_t, c_t)
    

    PS:存储库包含更多 LSTM 和其他 RNN 的变体:
    https://github.com/pytorch/benchmark/tree/master/rnns/benchmarks.
    看看吧,也许你心目中的扩展已经存在了!

    编辑:
    如 cmets 中所述,您可以包装上面的 LSTM 单元来处理顺序输出:

    import math
    import torch as th
    import torch.nn as nn
    
    
    class LSTMCell(nn.Module):
    
        def __init__(self, input_size, hidden_size, bias=True):
            # As before
    
        def reset_parameters(self):
            # As before
    
        def forward(self, x, hidden):
    
            if hidden is None:
                hidden = self._init_hidden(x)
    
            # Rest as before
    
        @staticmethod
        def _init_hidden(input_):
            h = th.zeros_like(input_.view(1, input_.size(1), -1))
            c = th.zeros_like(input_.view(1, input_.size(1), -1))
            return h, c
    
    
    class LSTM(nn.Module):
    
        def __init__(self, input_size, hidden_size, bias=True):
            super().__init__()
            self.lstm_cell = LSTMCell(input_size, hidden_size, bias)
    
        def forward(self, input_, hidden=None):
            # input_ is of dimensionalty (1, time, input_size, ...)
    
            outputs = []
            for x in torch.unbind(input_, dim=1):
                hidden = self.lstm_cell(x, hidden)
                outputs.append(hidden[0].clone())
    
            return torch.stack(outputs, dim=1)
    

    我没有测试代码,因为我正在使用 convLSTM 实现。如果有问题请告诉我。

    更新:固定链接。

    【讨论】:

    • 经过一番测试,我意识到它说的是For now, they only support a sequence size of 1。所以这段代码可能需要大量重构才能使用。
    • 我上面给出的代码通常被称为 LSTM 单元。为了处理顺序输入,只需将其包装在一个设置初始隐藏状态的模块中,然后在输入的时间维度上进行迭代,在每个时间点调用 LSTM 单元(类似于这里的操作方式discuss.pytorch.org/t/implementation-of-multiplicative-lstm/…
    • 还可以看看它是如何在这里完成的 vor 卷积 LSTM github.com/automan000/Convolution_LSTM_PyTorch/blob/master/…。它与常规的 LSTM 非常相似。
    • 您能解释一下为什么在静态方法中使用view 为h 和c 添加一个额外的维度吗?
    • @AnIgnorantWanderer 这是因为此实现假定批量大小为 1,因此它适用于任何长度的输入序列。如果您想使用更大的批量大小,您需要一个固定的序列长度或sequence padding,并且您需要相应地修改代码。
    【解决方案2】:

    我制作了一个简单通用的框架来自定义 LSTM: https://github.com/daehwannam/pytorch-rnn-util

    您可以通过设计 LSTM 单元并将它们提供给LSTMFrame 来实现自定义 LSTM。 自定义 LSTM 的一个例子是包中的LayerNormLSTM

    # snippet from rnn_util/seq.py
    class LayerNormLSTM(LSTMFrame):
        def __init__(self, input_size, hidden_size, num_layers=1, dropout=0, r_dropout=0, bidirectional=False, layer_norm_enabled=True):
            r_dropout_layer = nn.Dropout(r_dropout)
            rnn_cells = tuple(
                tuple(
                    LayerNormLSTMCell(
                        input_size if layer_idx == 0 else hidden_size * (2 if bidirectional else 1),
                        hidden_size,
                        dropout=r_dropout_layer,
                        layer_norm_enabled=layer_norm_enabled)
                    for _ in range(2 if bidirectional else 1))
                for layer_idx in range(num_layers))
    
            super().__init__(rnn_cells, dropout, bidirectional)
    

    LayerNormLSTM 拥有 PyTorch 标准 LSTM 的关键选项和附加选项 r_dropoutlayer_norm_enabled

    # example.py
    import torch
    import rnn_util
    
    
    bidirectional = True
    num_directions = 2 if bidirectional else 1
    
    rnn = rnn_util.LayerNormLSTM(10, 20, 2, dropout=0.3, r_dropout=0.25,
                                 bidirectional=bidirectional, layer_norm_enabled=True)
    # rnn = torch.nn.LSTM(10, 20, 2, bidirectional=bidirectional)
    
    input = torch.randn(5, 3, 10)
    h0 = torch.randn(2 * num_directions, 3, 20)
    c0 = torch.randn(2 * num_directions, 3, 20)
    output, (hn, cn) = rnn(input, (h0, c0))
    
    print(output.size())
    

    【讨论】:

      猜你喜欢
      • 2019-11-18
      • 1970-01-01
      • 1970-01-01
      • 2022-07-17
      • 2020-09-18
      • 2017-01-08
      • 2011-12-25
      • 2014-01-15
      • 1970-01-01
      相关资源
      最近更新 更多