Перевод модели LSTM из Keras в Pytorch - PullRequest
0 голосов
/ 12 октября 2019

Мне трудно перевести довольно простую модель LSTM с Keras на Pytorch. X (получите здесь ) соответствует 1152 выборкам по 90 временных шагов, каждый временной шаг имеет только 1 измерение. y ( здесь ) - это единственное предсказание при t = 91 для всех 1152 выборок.

В Керасе:

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

X = pd.read_csv('X.csv', header = None).values
X.shape

y = pd.read_csv('y.csv', header = None).values
y.shape

# From Keras documentation [https://keras.io/layers/recurrent/]: 
# Input shape 3D tensor with shape (batch_size, timesteps, input_dim).
X = np.reshape(X, (1152, 90, 1))

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 = 10, batch_size = 32)

... приводит меня к:

# Epoch 10/10
# 1152/1152 [==============================] - 33s 29ms/sample - loss: 0.0068 - mean_absolute_error: 0.0628

Затем в Pytorch:

import torch
from torch import nn, optim
from sklearn.metrics import mean_absolute_error

X = pd.read_csv('X.csv', header = None).values
y = pd.read_csv('y.csv', header = None).values

X = torch.tensor(X, dtype = torch.float32)
y = torch.tensor(y, dtype = torch.float32)

dataset = torch.utils.data.TensorDataset(X, y)
loader = torch.utils.data.DataLoader(dataset, batch_size = 32, shuffle = True)

class regressor_LSTM(nn.Module):
    def __init__(self):
        super().__init__()
        self.lstm1 = nn.LSTM(input_size = 1, 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):
        # From the Pytorch documentation [https://pytorch.org/docs/stable/_modules/torch/nn/modules/rnn.html]:
        # **input** of shape `(seq_len, batch, input_size)`
        X = X.view(90, 32, 1)
        # I am discarding hidden/cell states since in Keras I am using a stateless approach
        # [https://keras.io/examples/lstm_stateful/]
        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(10):
    running_loss = 0.
    running_mae = 0.

    for i, data in enumerate(loader):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = regressor(inputs)
        outputs = outputs[-1].view(*labels.shape)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        mae = mean_absolute_error(labels.detach().cpu().numpy().flatten(), outputs.detach().cpu().numpy().flatten())
        running_mae += mae

    print('EPOCH %3d: loss %.5f - MAE %.5f' % (epoch+1, running_loss/len(loader), running_mae/len(loader)))

... приводит меня к:

# EPOCH  10: loss 0.04220 - MAE 0.16762

Вы можете заметить, что как потери, так и MAE весьма различны (У питоров намного выше). Если я использую модель Pytorch для прогнозирования значений, они все возвращаются как константы.

Что я делаю не так?

1 Ответ

0 голосов
/ 14 октября 2019

О, я думаю, я добился значительного прогресса. Кажется, что способ представления y отличается в Keras и Pytorch. В Keras мы должны передать его как одно значение, представляющее один временной шаг в будущем (или, по крайней мере, для проблемы, которую я пытаюсь решить). Но в Pytorch y должно быть X сдвинуто на один шаг в будущее. Это выглядит так:

time_series = [0, 1, 2, 3, 4, 5]

X = [0, 1, 2, 3, 4]
# Keras:
y = [5]
# Pytorch:
y = [1, 2, 3, 4, 5]

Таким образом, Pytorch сравнивает все значения во временном интервале при расчете потерь. Я считаю, что Keras реорганизует данные под капотом, чтобы соответствовать этому подходу, так как код работает, когда переменные подаются точно так же. Но в Pytorch я оценивал потери, основываясь только на одном значении (то, которое я пытался предсказать), а не на целой серии, поэтому я считаю, что он не мог правильно отразить зависимость от времени.

При принятии этого вучитывая, я получил:

EPOCH 100: loss 0.00551 - MAE 0.058435

И, самое главное, сравнение истинных и предсказанных значений в отдельном наборе данных дало мне this plot

Шаблоны былиотчетливо запечатлен моделью.

Ура!

...