Вопрос о настройке моего входного массива объектов для обучения классификатора LSTM для учета прошлых наблюдений - PullRequest
0 голосов
/ 19 апреля 2019

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

Ниже приведен мой автономный демонстрационный код.

Мой вопрос таков: чтобы LSTM мог выбрать шаблон из предыдущих наблюдений, мне нужно определить скользящее окно, чтобы каждое наблюдение фактически включалоданные предыдущих наблюдений, которые составляют период скользящего окна, или же керасы получают их сами из массива объектов?

import random
import pandas as pd
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from sklearn.model_selection import train_test_split
from keras.layers.recurrent import LSTM
from sklearn.preprocessing import LabelEncoder

# this section just generates some sample data
# the pattern we are trying to pick up on is that
# shift_value number of observations prior to a True
# label, the features are always [.5, .5, .5]

shift_value = 5
n_examples = 10000

features = []
labels = []
random.seed(1)

# create the labels
for i in range(n_examples + shift_value):
    labels.append(random.choice([True, False]))

# create the features
for label in labels:
    if label:
        features.append([.5, .5, .5]) 
    else:
        feature_1 = random.random()
        feature_2 = random.random()
        feature_3 = random.random()
        features.append([feature_1, feature_2, feature_3])

df = pd.DataFrame(features)
df['label'] = labels
df.columns = ['A', 'B', 'C', 'label']
df['label'] = df['label'].shift(5)
df = df.dropna()

features_array = df[['A', 'B', 'C']].values
labels_array = df[['label']].values

# reshape the data

X_train, X_test, Y_train, Y_test = train_test_split(features_array, labels_array, test_size = .1, shuffle=False)

X_train_reshaped = np.reshape(X_train, (len(X_train), 1, X_train.shape[1]))
X_test_reshaped = np.reshape(X_test, (len(X_test), 1, X_train.shape[1]))

encoder = LabelEncoder()
Y_train_encoded = encoder.fit_transform(Y_train)
Y_test_encoded  = encoder.fit_transform(Y_test)

# define and run the model

neurons = 10
batch_size = 100
model = Sequential()
model.add(LSTM(neurons, 
               batch_input_shape=(batch_size,
                                  X_train_reshaped.shape[1], 
                                  X_train_reshaped.shape[2] 
                                  ),
               activation = 'sigmoid',
               stateful = False)
               )

model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

model.fit(X_train_reshaped, 
          Y_train_encoded, 
          validation_data=(X_test_reshaped, Y_test_encoded), 
          epochs=10, 
          batch_size=batch_size)

Приведенный выше пример никогда не сходится, и я не думаю, что он принимает предыдущие наблюденияво внимание на всех.Он должен быть в состоянии найти базовую схему из 5 наблюдений до того, как Истина всегда будет [.5, .5, .5]

1 Ответ

1 голос
/ 19 апреля 2019

Это проблема последовательности. Подумайте об этой проблеме обучения, как показано ниже

При заданной последовательности длины seq_length, если вход на шаге по времени t равен [0.5,0.5,0.5], тогда вывод на t+shift_value == 1 остальное t+shift_value == 0

Чтобы смоделировать эту проблему обучения, вы будете использовать LSTM, который будет развернут seq_length раз, и каждый шаг по времени будет иметь размер 3. Также каждому временному шагу соответствует выходное значение размера 1 (соответствующее True of False). Это изображено ниже:

enter image description here

Код:

import random
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.layers.recurrent import LSTM

shift_value = 5
seq_length = 50

def generate_data(n, shift_value, seq_length):
    X = np.random.rand(n, seq_length, 3)
    Y = np.random.randint(0,2,size=(n, seq_length))
    for j in range(len(Y)):
        for i in range(shift_value,len(Y[j])):
            if Y[j][i] == 1:
                X[j][i-shift_value] = np.array([0.5,0.5,0.5])
    return X, Y.reshape(n,seq_length, 1)

# Generate Train and Test Data
X_train, Y_train = generate_data(9000,shift_value,seq_length)
X_test, Y_test = generate_data(100,shift_value,seq_length)

# Train the model
neurons = 32
batch_size = 100
model = Sequential()
model.add(LSTM(neurons, 
               batch_input_shape=(batch_size, seq_length, 3),
               activation = 'relu',
               stateful = False,
               return_sequences = True))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

model.fit(X_train, 
          Y_train,
          validation_data=(X_test, Y_test), 
          epochs=30, 
          batch_size=batch_size)

Выход (отфильтрованный):

...
Epoch 30/30
9000/9000 [=========] - loss: 0.1650 - acc: 0.9206 - val_loss: 0.1362 - val_acc: 0.9324

В 30 эпохах он достиг валидации в 93%. Несмотря на то, что это детерминированная функция, модель никогда не будет на 100% точной из-за неоднозначности в первых shift_value метках.

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