【问题标题】:How do I train an LSTM in Pytorch?如何在 Pytorch 中训练 LSTM?
【发布时间】:2020-02-03 16:39:21
【问题描述】:

我很难理解 Pytorch 中 LSTM 的内部工作原理。

让我给你看一个玩具例子。也许架构没有多大意义,但我试图了解 LSTM 在这种情况下是如何工作的。

数据可以从here获取。每行i(总计 = 1152)是一个片段,从t = it = i + 91,是一个较长时间序列的片段。我将提取每行的最后一列作为标签。

import torch
import numpy as np
import pandas as pd
from torch import nn, optim
from sklearn.metrics import mean_absolute_error

data = pd.read_csv('data.csv', header = None).values
X = torch.tensor(data[:, :90], dtype = torch.float).view(1152, 1, 90)
y = torch.tensor(data[:, 90], dtype = torch.float).view(1152, 1, 1)

dataset = torch.utils.data.TensorDataset(X, y)
loader = torch.utils.data.DataLoader(dataset, batch_size = 50)

然后我定义一个 LSTM 回归器,其中包含三个具有不同结构的 LSTM 层。

class regressor_LSTM(nn.Module):
    def __init__(self):
        super().__init__()
        self.lstm1 = nn.LSTM(input_size = 49, hidden_size = 100)
        self.lstm2 = nn.LSTM(100, 50)
        self.lstm3 = nn.LSTM(50, 50, dropout = 0.3, num_layers = 2)
        self.dropout = nn.Dropout(p = 0.3)
        self.linear = nn.Linear(in_features = 50, out_features = 1)

    def forward(self, X):
        X, _ = self.lstm1(X)
        X = self.dropout(X)
        X, _ = self.lstm2(X)
        X = self.dropout(X)
        X, _ = self.lstm3(X)
        X = self.dropout(X)
        X = self.linear(X)

        return X

初始化需要初始化的内容:

regressor = regressor_LSTM()
criterion = nn.MSELoss()
optimizer = optim.RMSprop(regressor.parameters())

然后训练:

for epoch in range(25):
    acc_loss = 0.
    acc_mae = 0.   
    for i, data in enumerate(loader):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = regressor(inputs)
        loss = criterion(outputs, labels)
        loss.backward(retain_graph = True)
        optimizer.step()
        acc_loss += loss.item()
        mae = mean_absolute_error(labels.detach().cpu().numpy().flatten(), outputs.detach().cpu().numpy().flatten())
        acc_mae += mae
#       print('\rEPOCH {:3d} - Loop {:3d} of {:3d}: loss {:03.2f} - MAE {:03.2f}'.format(epoch+1, i+1, len(loader), loss, mae), end = '\r')
    print('\nEPOCH %3d FINISHED: loss %.5f - MAE %.5f' % (epoch+1, acc_loss/len(loader), acc_mae/len(loader)))

问题是,在损失和 MAE(预期行为)最初有所下降之后,两者似乎都被卡住了(仅显示下面的前 10 个时期):


EPOCH   1 FINISHED: loss 0.38506 - MAE 0.27322          
EPOCH   2 FINISHED: loss 0.02825 - MAE 0.13601          
EPOCH   3 FINISHED: loss 0.02593 - MAE 0.13117          
EPOCH   4 FINISHED: loss 0.02568 - MAE 0.12705          
EPOCH   5 FINISHED: loss 0.02546 - MAE 0.12920          
EPOCH   6 FINISHED: loss 0.02502 - MAE 0.12763          
EPOCH   7 FINISHED: loss 0.02445 - MAE 0.12659          
EPOCH   8 FINISHED: loss 0.02310 - MAE 0.12328          
EPOCH   9 FINISHED: loss 0.02277 - MAE 0.12237          
EPOCH  10 FINISHED: loss 0.02352 - MAE 0.12476

使用 Keras 运行时,这两个指标在整个过程中都会持续下降。 (我还注意到 Keras 需要更长的时间。)

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM
import pandas as pd

data = pd.read_csv('data.csv', header = None).values
X = data[:, :90].reshape(1152, 90, 1)
y = data[:, 90]

regressor = Sequential()
regressor.add(LSTM(units = 100, return_sequences = True, input_shape = (90, 1)))
regressor.add(Dropout(0.3))
regressor.add(LSTM(units = 50, return_sequences = True))
regressor.add(Dropout(0.3))
regressor.add(LSTM(units = 50, return_sequences = True))
regressor.add(Dropout(0.3))
regressor.add(LSTM(units = 50))
regressor.add(Dropout(0.3))
regressor.add(Dense(units = 1, activation = 'linear'))
regressor.compile(optimizer = 'rmsprop', loss = 'mean_squared_error', metrics = ['mean_absolute_error'])
regressor.fit(X, y, epochs = 25, batch_size = 32)
[OUTPUT]
Epoch 1/25
1152/1152 - 35s 30ms/sample - loss: 0.0307 - mean_absolute_error: 0.1225
Epoch 2/25
1152/1152 - 32s 28ms/sample - loss: 0.0156 - mean_absolute_error: 0.0978
Epoch 3/25
1152/1152 - 32s 28ms/sample - loss: 0.0126 - mean_absolute_error: 0.0871
Epoch 4/25
1152/1152 - 34s 30ms/sample - loss: 0.0111 - mean_absolute_error: 0.0806
Epoch 5/25
1152/1152 - 29s 25ms/sample - loss: 0.0103 - mean_absolute_error: 0.0785
Epoch 6/25
1152/1152 - 29s 25ms/sample - loss: 0.0088 - mean_absolute_error: 0.0718
Epoch 7/25
1152/1152 - 32s 27ms/sample - loss: 0.0085 - mean_absolute_error: 0.0699
Epoch 8/25
1152/1152 - 30s 26ms/sample - loss: 0.0069 - mean_absolute_error: 0.0640
Epoch 9/25
1152/1152 - 30s 26ms/sample - loss: 0.0077 - mean_absolute_error: 0.0660
Epoch 10/25
1152/1152 - 30s 26ms/sample - loss: 0.0070 - mean_absolute_error: 0.0644

我一直在阅读有关隐藏状态初始化的文章,我尝试在 forward 方法的开头将它们设置为 0(不过,我理解这是标准行为),但没有任何帮助。我必须承认,我不明白 LSTM 的参数是什么,也不应该在每个批次或 epoch 之后重新初始化(如果有的话)。

感谢任何回报!

【问题讨论】:

  • 我认为这是一个关于如何在多个 LSTM 层之间移动隐藏状态的概念问题。我建议你看看my long answer on what is the proper way on retrieving hidden states in PyTorch
  • 惊人的解释安德鲁,我只是一直想知道如何构建整个事情。 1)当我调用 forward 方法并批量传递它时,这是否意味着所有时间步都通过模型,h 和 c 跨时间相应地更新? 2) 那么,我应该将 h 和 c 从我之前的 LSTM 层传递到下一层吗?但是如果我的 LSTM 层有不同的大小,我该怎么做呢? 3)当再次调用 forward 时,我应该重置 h 和 c 吗? (如果是这样,模块不会自动为我做这件事吗?)

标签: pytorch lstm


【解决方案1】:

几天后我会回来,因为我已经得出了结论。在阅读了一些关于隐藏/单元状态的材料后,(this one 非常有用)似乎重用它们是网络设计选择的问题。是否这样做以及何时这样做都可以算作一个超参数。我用我的玩具数据集尝试了很多选项,主要是在每批之后重置状态,在每个 epoch 之后重置,根本不重置,结果非常相似。另外,我的结果非常低,因为(我相信)我没有在加载程序中选择shuffle = True;这样做使它们变得更好(损失大约 0.003,MAE 大约 0.047)。

LSTM class 的原始代码第 510 行中,如果没有明确传递任何值,隐藏/单元格状态似乎也从零开始。

【讨论】:

    猜你喜欢
    • 2021-01-14
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2018-10-13
    • 2019-02-28
    • 2018-10-19
    • 2021-09-11
    相关资源
    最近更新 更多