Keras TimeseriesGenerator генерирует противоречивые фигуры - PullRequest
0 голосов
/ 17 марта 2020

Я использую tensorflow.keras.preprocessing.sequence.TimeseriesGenerator для предварительной обработки многовариантных временных рядов для модели LSTM. Однако формы выборок кажутся несовместимыми в зависимости от временных и пакетных размеров, что в конечном итоге приводит к ошибке при подгонке модели.

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

# Indices of data
# Sample 1: [1,2,...,n] -> [n+1]
# Sample 2: [2,3,...,n+1] -> [n+2]

Код:

import numpy as np
from tensorflow.keras.preprocessing.sequence import TimeseriesGenerator

def GenerateData(TIMESTEPS, BATCHSIZE, N_FEATURES, N_SAMPLES):
    """
    Generates batches of one-step forward samples (x_1,...,x_n), (y_n+1)
    Args: TIMESTEPS (int) Number of past observations
          BATCHSIZE (int) Number of samples in each batch
          N_FEATURES (int) Number of features in dataset
          N_SAMPLES (int) Length of dataset

    Each generated sample should be shape (BATCHSIZE, TIMESTEPS, N_FEATURES), (BATCHSIZE,)
    """
    # Dummy multivariate series
    dummy_x = np.random.rand(N_SAMPLES, N_FEATURES)
    dummy_y = np.array([x[0] for x in dummy_x]) # Predict future values of first column
    print(f'Data X Shape: {dummy_x.shape}, Data Y Shape: {dummy_y.shape}')

    generator = TimeseriesGenerator(data=dummy_x, targets=dummy_y,
                                    length=TIMESTEPS,
                                    batch_size=BATCHSIZE,
                                    sampling_rate=1,
                                    stride=1
                                   )

    # Check whether each sample is shaped correctly
    for n in range(len(generator)):
        x,y = generator[n]
        if x.shape != (BATCHSIZE, TIMESTEPS, N_FEATURES):
            print(f'Check index {n}.')

Тесты:

[In]
GenerateData(TIMESTEPS=5, BATCHSIZE=2, N_FEATURES=5, N_SAMPLES=1000)
[Out]
Data X Shape: (1000, 5), Data Y Shape: (1000,)
Check index 497.
Index 497 shapes: (1, 5, 5), (1,)

[In]
GenerateData(TIMESTEPS=5, BATCHSIZE=2, N_FEATURES=5, N_SAMPLES=1001)
[Out]
Data X Shape: (1001, 5), Data Y Shape: (1001,)

[In]
GenerateData(TIMESTEPS=6, BATCHSIZE=2, N_FEATURES=5, N_SAMPLES=1001)
[Out]
Data X Shape: (1001, 5), Data Y Shape: (1001,)
Check index 497.
Index 497 shapes: (1, 6, 5), (1,)

[In]
GenerateData(TIMESTEPS=6, BATCHSIZE=32, N_FEATURES=5, N_SAMPLES=1001)
[Out]
Data X Shape: (1001, 5), Data Y Shape: (1001,)
Check index 31.
Index 31 shapes: (3, 6, 5), (3,)

Есть мысли? В приведенных выше тестах успешно работает только второй.


Обновление: До сих пор не выяснено, что вызывает проблемы, и исходный код для TimeseriesGenerator является немного трудно следовать. На данный момент, это довольно не элегантный способ ручного поиска среди потенциальных кандидатов TIMESTEPS, BATCHSIZE параметров, которые будут генерировать выборки с постоянным размером.

from collections import defaultdict
candidates = defaultdict()

# df = your data

# Range of candidate values
TIMESTEPS_LOWER = 2
TIMESTEPS_UPPER = 15
BATCHSIZE_LOWER = 1
BATCHSIZE_UPPER = 128

for t in range(TIMESTEPS_LOWER,TIMESTEPS_UPPER):
    for b in range(BATCHSIZE_LOWER,BATCHSIZE_UPPER, 2):
        test = GenerateData(TIMESTEPS=t, BATCHSIZE=b, N_FEATURES=df.shape[1], N_SAMPLES=len(df))
        # Check if these parameters work
        if test:
            # Add to existing dict
            prev_cand = candidates.get(t, False)
            if prev_cand:
                prev_cand.append(b)
            else:
                candidates.update({t:[b]})
candidates
--
[OUT]
defaultdict(None,
            {2: [1],
             3: [1, 3, 17, 47, 51],
             4: [1, 5, 7, 35],
             5: [1, 13], ...

Выводы - это словарь TIMESTEPS: BATCH_SIZE, который будет работать для вашего набора данных.

...