Понимание LSTM с помощью простого набора данных - PullRequest
1 голос
/ 26 апреля 2020

Я хотел убедиться, что понимаю LSTM, поэтому я реализовал фиктивный пример с использованием фреймворка Pytorch. В качестве входных данных я использую последовательности последовательных чисел длиной 10, а прогнозируемое значение всегда является последним номером последовательности + 1. Например:
x = [6, 7, 8, 9, 10, 11, 12 , 13, 14, 15]
y = 16

Поскольку это очень простая задача прогнозирования, я ожидал, что модель будет работать хорошо, но наблюдаю очень плохие показатели. Модель предсказывает постоянное значение для партии, которое постоянно увеличивается в процессе обучения.

Мне интересно, что мне не хватает. Ниже приведен код, который я сделал - любая помощь будет принята с благодарностью.

from torch.utils.data import Dataset, TensorDataset, DataLoader, RandomSampler, SequentialSampler
import torch.nn as nn
import torch

class MyDataset(Dataset):

    def __init__(self):
        pass

    def __getitem__(self, index):
        x = torch.tensor([index-9,index-8,index-7,index-6,index-5,index-4,index-3,index-2,index-1,index])
        y = torch.tensor(index + 1)
        return x,y

    def __len__(self):
        return 1000
class LSTM(nn.Module):
    def __init__(self, hidden_layer_size=1, batch_size = 1):

        super().__init__()
        self.hidden_layer_size = hidden_layer_size
        self.batch_size = batch_size 
        self.lstm = nn.LSTM(1, hidden_layer_size)
        self.linear = nn.Linear(10, 1)
        self.hidden_cell = (torch.zeros(1,self.batch_size,self.hidden_layer_size),
                            torch.zeros(1,self.batch_size,self.hidden_layer_size))

    def forward(self, input_seq):

        lstm_out, self.hidden_cell = self.lstm(input_seq.view(10 ,self.batch_size, -1), self.hidden_cell)
        predictions = self.linear(lstm_out.squeeze().T)
        return predictions
batch_size = 32
epochs = 1000

train = MyDataset()
sampler = RandomSampler(train)
train_dataloader = DataLoader(train, sampler=sampler, batch_size= batch_size , drop_last = True)

model = LSTM(batch_size = batch_size)
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for e in range(epochs):
    for step, batch in enumerate(train_dataloader) :

        seq, labels = batch
        optimizer.zero_grad()

        model.hidden_cell = (torch.zeros(1, batch_size, model.hidden_layer_size),
                             torch.zeros(1, batch_size, model.hidden_layer_size))

        y_pred = model(seq.float())

        print(y_pred)

        single_loss = loss_function(y_pred, labels.float())
        single_loss.backward()
        optimizer.step()

1 Ответ

0 голосов
/ 26 апреля 2020

В вашей функции пересылки есть несколько проблем. Посмотрите на вход, который вы передаете в LSTM:

input_seq = input_seq.view(10 ,self.batch_size, -1)
print(input_seq[:, 0])

>>> tensor([[168.],
        [ 21.],
        [450.],
        [436.],
        [789.],
        [941.],
        [ -7.],
        [811.],
        [789.],
        [992.]])

Это серия случайных чисел. Вы должны либо транспонировать input_seq или, что еще лучше, передать batch_first=True в конструктор LSTM и просто unsqueeze input_seq перед передачей его в LSTM.

Вы также должны обновить lstm_out, единственная операция, которая требуется сейчас, - reshape до [batch_size x (10 * hidden_size)].

Наконец, вам нужно squeeze вывод линейного слоя.

Помимо этого, скрытый размер LSTM слишком мал, используйте 10 (или даже 100) вместо одного, только тогда модель сходится через 1000 эпох. Вот обновленный код:

class LSTM(nn.Module):
    def __init__(self, hidden_layer_size=100, batch_size = 1):

        super().__init__()
        self.hidden_layer_size = hidden_layer_size
        self.batch_size = batch_size 
        self.lstm = nn.LSTM(1, hidden_layer_size, batch_first=True)
        self.linear = nn.Linear(10 * hidden_layer_size, 1)
        self.hidden_cell = (torch.zeros(1,self.batch_size,self.hidden_layer_size),
                            torch.zeros(1,self.batch_size,self.hidden_layer_size))

    def forward(self, input_seq):
        batch_size = input_seq.size(0)
        input_seq = input_seq.unsqueeze(2)
        lstm_out, self.hidden_cell = self.lstm(input_seq, self.hidden_cell)
        lstm_out = lstm_out.reshape(batch_size, -1)
        predictions = self.linear(lstm_out).squeeze()
        return predictions
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...