Seq-to-seq LSTM 无法正确学习

问题描述 投票:0回答:1

我正在尝试使用 Pytorch 中的 LSTM 解决 seq-to-seq 问题。具体来说,我采用 5 个元素的序列来预测接下来的 5 个元素。我关心的是数据转换。我有大小为 [bs, seq_length, features] 的张量,其中

seq_length = 10
features = 1
。每个特征都是 0 到 3 之间的整数(两者都包含在内)。

我认为输入数据必须使用 MinMaxScaler 转换为浮点范围 [0, 1],以便使 LSTM 学习过程更容易。之后,我应用一个线性层,它将隐藏状态转换为相应的输出,大小为

features
。我在 Pytorch 中对 LSTM 网络的定义:

class LSTM(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, num_layers, dropout_prob):
        super(LSTM, self).__init__()
        self.lstm_layer = nn.LSTM(input_dim, hidden_dim, num_layers, dropout=dropout_prob)
        self.output_layer = nn.Linear(hidden_dim, output_dim)

    ...

    def forward(self, X):
        out, (hidden, cell) = self.lstm_layer(X)
        out = self.output_layer(out)
        return out

我用来进行训练循环的代码如下:

def train_loop(t, checkpoint_epoch, dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    for batch, X in enumerate(dataloader):
        X = X[0].type(torch.float).to(device)

        # X = torch.Size([batch_size, 10, input_dim])
        # Split sequences into input and target
        inputs = transform(X[:, :5, :]) # inputs = [batch_size, 5, input_dim]
        targets = transform(X[:, 5:, :]) # targets = [batch_size, 5, input_dim]

        # predictions (forward pass)
        with autocast():
            pred = model(inputs)  # pred = [batch_size, 5, input_dim]
            loss = loss_fn(pred, targets)

        # backprop
        optimizer.zero_grad()
        scaler.scale(loss).backward()
        scaler.step(optimizer)
        scaler.update()

        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            #print(f"Current loss: {loss:>7f}, [{current:>5d}/{size:>5d}]")

        # Delete variables and empty cache
        del X, inputs, targets, pred
        torch.cuda.empty_cache()

    return loss

我用于预处理数据的代码:

def main():
    num_agents = 2
    # Open the HDF5 file
    with h5py.File('dataset_' + str(num_agents) + 'UAV.hdf5', 'r') as f:
        # Access the dataset
        data = f['data'][:]
        # Convert to PyTorch tensor
        data_tensor = torch.tensor(data)

        size = data_tensor.size()
        seq_length = 10
        reshaped = data_tensor.view(-1, size[2], size[3])

        r_size = reshaped.size()
        reshaped = reshaped[:, :, 1:]
        reshaped_v2 = reshaped.view(r_size[0], -1)

        dataset = create_dataset(reshaped_v2.numpy(), seq_length)

        f.close()

    dataset = TensorDataset(dataset)

    # Split the dataset into training and validation sets
    train_size = int(0.8 * len(dataset))  # 80% for training
    val_size = len(dataset) - train_size  # 20% for validation
    train_dataset, val_dataset = random_split(dataset, [train_size, val_size])

    train_dataloader = DataLoader(train_dataset, batch_size=params['batch_size'], shuffle=True, pin_memory=True)
    val_dataloader = DataLoader(val_dataset, batch_size=params['batch_size'], shuffle=False, pin_memory=True)

尝试这个,模型没有正确学习,所以我想也许可以直接计算

targets
(范围 [0, 1] 内的浮点值)和
pred
(我认为是范围 [ 内的浮点值)之间的损失-1, 1] 因为来自 LSTM 层的 tanh 激活函数),不同的尺度可能是错误的。然后,我尝试在前向传递中的线性层之后应用 sigmoid 激活函数,但也没有正确学习。我尝试了许多超参数组合的执行,但没有一个产生“正常”的训练曲线。我还附上了 5000 epoch 的屏幕截图来说明训练过程:

我的问题是:

  • 我的训练过程中似乎有什么问题?
  • 我说的话有什么想法是错误的吗?
python machine-learning deep-learning pytorch lstm
1个回答
0
投票

代码的最大问题是如何定义 LSTM 层。

默认情况下,

nn.LSTM
需要形状为
(sl, bs, features)
的输入,而您的输入的形状为
(bs, sl, features)
。因此,您当前的代码正在沿着错误的维度进行处理。您需要将
batch_first=True
传递给
nn.LSTM
才能使用批量首次输入(lstm docs)。

此外,您的数据设置有缺陷。您的 LSTM 一次处理一个序列,这意味着序列元素

i
只看到序列元素
0, 1, ... i-1
。但您希望该序列元素能够预测输出序列中的
i+5

一个更具体的示例,输入中的第二项预计会预测输出中的第二项(总共第七项),而不会看到任何中间序列项。您尝试仅使用输入序列的一小部分来预测输出序列的元素。

最好的方法是使用下一步预测。这是有效的,因为每个步骤都已经看到了它之前的所有步骤,并且与所预测的步骤没有信息差距。这是一个简单的改变:

# old
inputs = transform(X[:, :5, :])
targets = transform(X[:, 5:, :])

# new
inputs = transform(X[:, :-1, :]) # all but the last step
targets = transform(X[:, 1:, :]) # all but the first step

如果您确实想坚持使用前 5 个步骤来预测接下来的 5 个步骤,则需要一个序列到序列模型。这涉及添加一个解码器 LSTM,该解码器使用从编码器 LSTM 生成的隐藏状态(从而拥有来自所有时间步的信息)。 Seq2seq 还需要解码器的 for 循环,这非常烦人。

© www.soinside.com 2019 - 2024. All rights reserved.