Модель LSTM Tensorflow 2 не обучается с помощью последовательности - PullRequest
1 голос
/ 17 июня 2020

В настоящее время я использую модель LSTM для создания прогнозов таймера ie с помощью Tensorflow 2.2.0

Я использовал большой набор данных, и все работает хорошо. Однако создание набора данных занимает много оперативной памяти, и я хотел использовать tensorflow.keras.utils.Sequence для решения проблемы, моя проблема заключается в следующем:

При использовании последовательности моя модель не обучается больше (он прогнозирует среднее значение реального сигнала по всему набору данных)

Мой набор данных создан из двух python списков x_train_flights и y_train_flights, каждый из которых содержит pandas DataFrame с. Для каждого (x_train_flight, y_train_flight) этого списка:

  • x_train_flight формы (-1, features), содержащих features сигналов
  • y_train_flight формы (-1, 1), содержащих один выравниваемый сигнал по времени с теми из x_train_flights

Система выглядит следующим образом (мне не разрешено делиться реальными данными, вместо этого я воссоздал график, используя псевдослучайные сигналы):

exemple of prediction

Здесь features=2 (синяя и оранжевая линии) и look_back=5. То есть 10 точек (из x_train_flights) в прямоугольнике используются для прогнозирования золотой точки (которая сравнивается с соответствующей точкой в ​​y_train_flights во время фазы обучения). Серые точки - это предыдущие прогнозы.

Для создания набора данных я использовал следующие функции:

def lstm_shapify(sequence, look_back, features):
    res = np.empty((look_back, len(sequence), features), dtype=np.float32)

    for i in range(look_back):
        res[i] = np.roll(sequence, -i * features)

    return np.transpose(res, axes=(1, 0, 2))[:-look_back + 1]


def make_dataset(x_flights, y_flights, look_back, features):
    x = np.empty((0, look_back, features), dtype=np.float32)
    y = np.empty((0, 1), dtype=np.float32)

    for i in range(len(x_flights)):
        x_sample = x_flights[i].values
        y_sample = y_flights[i].values[look_back - 1:]

        x = np.concatenate([x, lstm_shapify(x_sample, look_back, features)])
        y = np.concatenate([y, y_sample])

    return x, y

И я подобрал для своей сети следующее:

model.fit(
    x_train,
    y_train,
    epochs=7,
    batch_size=batch_size
)

Итак, я создал эту настраиваемую Последовательность:

class LSTMGenerator(Sequence):

    def __init__(
            self,
            x_flights: List[DataFrame],
            y_flights: List[DataFrame],
            look_back: int,
            batch_size: int,
            features: int
    ):
        self.x_flights = x_flights
        self.y_flights = []
        self.look_back = look_back
        self.batch_size = batch_size
        self.features = features
        self.length = 0

        for y_flight in y_flights:
            y = y_flight.iloc[look_back - 1:].to_numpy()
            self.y_flights.append(y)
            self.length += len(y) // batch_size

    def __getitem__(self, index):
        flight_index = 0

        while True:
            n = len(self.y_flights[flight_index]) // self.batch_size
            if index < n:
                break
            flight_index += 1
            index = index - n

        start_index = index * self.batch_size
        x_batch = lstm_shapify(
            self.x_flights[flight_index]
                .iloc[start_index:start_index + self.batch_size + self.look_back - 1]
                .to_numpy(),
            self.look_back,
            self.features
        )
        y_batch = self.y_flights[flight_index][start_index:start_index + self.batch_size]

        return x_batch, y_batch

    def __len__(self):
        return self.length

Каждый кортеж (x, y), который он возвращает, представляет собой два numpy массивов формы (batch_size, look_back, features) и (batch_size, 1) соответственно.

И теперь пытаюсь подогнать его под:

model.fit(
    LSTMGenerator(x_train_flights, y_train_flights, look_back, batch_size, features),
    epochs=epochs
)

Вот моя модель:

model = Sequential()    

model.add(LSTM(
    100,
    input_shape=(look_back, features),
    kernel_regularizer=regularizers.l2(1e-3),
    bias_regularizer=regularizers.l2(1e-4)
))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(1, activation='tanh'))

model.compile(optimizer='adam', loss='mse')

Надеюсь, вы мне поможете

РЕДАКТИРОВАТЬ: подробнее о наборах данных

Ответы [ 2 ]

0 голосов
/ 30 июня 2020

Я решил это, сделав перерыв и еще раз взглянув на код (и я понял, что это глупая ошибка): проблема моего Sequence возникает из-за того, что образцы в каждой партии являются последовательными образцами во времени, тогда как мои Пакеты compute-everything-dataset были красиво перемешаны.

My Sequence было проблемой c, потому что пакеты были выбраны по случайному индексу из случайного набора данных. Теперь я выбираю каждую выборку по случайному индексу из случайного набора данных, чтобы создать единый пакет.

0 голосов
/ 17 июня 2020

Вот рабочий пример:

from tensorflow.keras import *
from tensorflow.keras.layers import *
from tensorflow.keras.utils import *
import numpy as np
import tensorflow as tf

np.random.seed(1234)
tf.random.set_seed(1234)

features = 3
lookback = 7

model = Sequential()
model.add(LSTM(500, input_shape = (lookback, features)))
model.add(Dense(1, activation='tanh'))

XS = np.random.randn(200, features)
YS = np.random.randn(200)

class LookbackSeq(Sequence):
    def __init__(self, XS, YS, batch_size, lookback):
        self.XS = XS
        self.YS = YS
        self.batch_size = batch_size
        self.lookback = lookback

    def __len__(self):
        n_windows = self.XS.shape[0] - self.lookback
        return int(np.ceil(n_windows / self.batch_size))

    def __getitem__(self, i):
        base = i * self.batch_size

        n_windows = self.XS.shape[0] - self.lookback
        batch_size = min(n_windows - base, self.batch_size)

        X = np.zeros((batch_size, self.lookback, self.XS.shape[1]))
        Y = np.zeros((batch_size, 1))
        for i in range(batch_size):
            for j in range(self.lookback):
                X[i, j] = self.XS[base + i + j]
            Y[i] = self.YS[base + i + self.lookback]
        return X, Y

model.compile(optimizer='adam', loss='mse')

# ALL SAMPLES IN MEMORY
X, Y = [], []
for i in range(len(XS) - lookback):
    X.append(XS[i:i+lookback])
    Y.append(YS[i+lookback])
X, Y = np.array(X), np.array(Y)
model.fit(X, Y, epochs = 10, batch_size = 4, shuffle = False)

# GENERATED ON THE FLY
# gen = LookbackSeq(XS, YS, 4, lookback)
# model.fit(x = gen,
#           steps_per_epoch = len(gen),
#           shuffle = False,
#           epochs = 10)

Я предполагаю, что ваши входные данные имеют форму X = (n_points, n_features) и Y = (n_points,). LookbackSeq выполняет пакетирование и работу с окнами (ретроспективный анализ) за вас.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...