为什么非常简单的 PyTorch LSTM 模型无法学习?

Sha*_*oon 4 python lstm pytorch tensor

我正在尝试进行非常简单的学习,以便更好地理解 PyTorch 和 LSTM 的工作原理。为此,我试图学习从输入张量到两倍值的输出张量(相同形状)的映射。因此[1 2 3],作为输入应该学习[2 4 6]作为输出。为此,我有一个dataloader:

class AudioDataset(Dataset):
    def __init__(self, corrupted_path, train_set=False, test_set=False):
        torch.manual_seed(0)
        numpy.random.seed(0)

    def __len__(self):
        return len(self.file_paths)

    def __getitem__(self, index):
        random_tensor = torch.rand(1, 5) * 2
        random_tensor = random_tensor - 1

        return random_tensor, random_tensor * 2
Run Code Online (Sandbox Code Playgroud)

我的 LSTM 本身非常简单:

class MyLSTM(nn.Module):
    def __init__(self, input_size=4000):
        super(MyLSTM, self).__init__()

        self.lstm = nn.LSTM(input_size=input_size, hidden_size=input_size,
                            num_layers=2)

    def forward(self, x):
        y = self.lstm(x)
        return y
Run Code Online (Sandbox Code Playgroud)

我的训练看起来像:

    train_loader = torch.utils.data.DataLoader(
        train_set, batch_size=1, shuffle=True, **kwargs)

    model = MyLSTM(input_size=5)
    optimizer = optim.Adam(model.parameters(), lr=0.01, weight_decay=0.0001)
    loss_fn = torch.nn.MSELoss(reduction='sum')

    for epoch in range(300):
        for i, data in enumerate(train_loader):
            inputs = data[0]
            outputs = data[1]

            print('inputs', inputs, inputs.size())
            print('outputs', outputs, outputs.size())
            optimizer.zero_grad()

            pred = model(inputs)
            print('pred', pred[0], pred[0].size())

            loss = loss_fn(pred[0], outputs)

            model.zero_grad()

            loss.backward()
            optimizer.step()
Run Code Online (Sandbox Code Playgroud)

300 个纪元后,我的loss看起来像tensor(1.4892, grad_fn=<MseLossBackward>). 这看起来不太好。

随机查看一些输入/输出和预测:

inputs tensor([[[0.5050, 0.4669, 0.8310,  ..., 0.0659, 0.5043, 0.8885]]]) torch.Size([1, 1, 4000])
outputs tensor([[[1.0100, 0.9338, 1.6620,  ..., 0.1319, 1.0085, 1.7770]]]) torch.Size([1, 1, 4000])
pred tensor([[[ 0.6930,  0.0231, -0.6874,  ..., -0.5225,  0.1096,  0.5796]]],
       grad_fn=<StackBackward>) torch.Size([1, 1, 4000])
Run Code Online (Sandbox Code Playgroud)

我们发现它根本没有学到很多东西。我不明白我做错了什么;如果有人可以指导我,我将不胜感激。

Rea*_*lar 6

LSTM 由生成内部神经元的神经元组成根据先前训练数据的反馈循环每个神经元都有四个内门,它们接受多个输入并生成多个输出。它是更复杂的神经元之一,需要使用和理解,而我的技术还不够熟练,无法给出深入的答案。

\n\n

我在您的示例代码中看到的是缺乏对它们如何工作的理解,而且您似乎假设它们像线性层一样工作。我这么说是因为你的前向方法不处理内部状态,并且你没有重塑输出。

\n\n

您可以这样定义 LSTM:

\n\n
     self.lstm = nn.LSTM(input_size=input_size, hidden_size=input_size, num_layers=2)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这hidden_size与内存和功能如何与门配合使用有关。

\n\n

PyTorch 文档说明如下:

\n\n
\n

隐藏大小 \xe2\x80\x93 隐藏状态 h 的特征数量

\n
\n\n

它指的是用于训练长期和短期记忆内门的隐藏状态的大小。门是跨存储先前门输出的隐藏特征的函数。每次训练神经元时,隐藏状态都会更新并在下一次训练中再次使用数据。

\n\n

那么为什么这如此重要呢?

\n\n

您在训练期间丢弃了隐藏状态数据,并且我不知道如果您不定义隐藏状态会发生什么。我认为 LSTM 的工作方式就好像从来没有任何历史一样。

\n\n

前向函数应该如下所示:

\n\n
    def forward(self, x, hidden):\n        lstm_output, hidden = self.lstm(x, hidden)\n        return lstm_output, hidden\n
Run Code Online (Sandbox Code Playgroud)\n\n

在训练期间,您必须自己跟踪隐藏状态。

\n\n
for i in range(epochs):\n   hidden = (torch.zeros(num_layers, batch_size, num_hidden),\n             torch.zeros(num_layers, batch_size, num_hidden))\n\n   for x, y in generate_batches(...):\n        # missing code....\n        lstm_output, hidden = model.forward(x, hidden)\n
Run Code Online (Sandbox Code Playgroud)\n\n

记下隐藏状态的形状。它与您通常使用线性图层所做的不同。

\n\n

上面缺少一些与重置隐藏状态相关的步骤,但我不记得该部分是如何工作的。

\n\n

LSTM 本身仅描述与卷积层非常相似的特征。LSTM 的输出不太可能是您感兴趣的。

\n\n

大多数使用 LSTM 或卷积的模型都具有全连接层的底部部分(例如:nn.Linear())。这些层将训练特征来预测您感兴趣的输出。

\n\n

这里的问题是 LSTM 的输出形状错误,您必须重新调整张量的形状,以便线性层可以使用它们。

\n\n

这是我使用过的 LSTM 前向函数示例:

\n\n
    def forward(self, x, hidden):\n        lstm_output, hidden = self.lstm(x, hidden)\n        drop_output = self.dropout(lstm_output)\n        drop_output = drop_output.contiguous().view(-1, self.num_hidden)\n        final_out = self.fc_linear(drop_output)\n        return final_out, hidden\n
Run Code Online (Sandbox Code Playgroud)\n\n

LSTM 绝对是机器学习中的一个高级主题,而 PyTorch 并不是一个容易学习的库。我建议使用 TensorFlow 文档和在线博客阅读 LSTM,以更好地掌握它们的工作原理。

\n