Керас LSTM з 1D часовим рядом


10

Я вивчаю, як користуватися Керасом, і я мав розумний успіх у моєму маркованому наборі даних, використовуючи приклади на глибоке навчання Chollet для Python . Набір даних становить ~ 1000 часових рядів довжиною 3125 з 3 потенційними класами.

Я хотів би вийти за рамки базових щільних шарів, які дають мені приблизно 70% прогнозування, і книга продовжує обговорювати шари LSTM та RNN.

У всіх прикладах, здається, використовуються набори даних з різними можливостями для кожного часового видання, і я намагаюся розробити, як втілити мої дані в результаті.

Якщо, наприклад, у мене є часовий ряд 1000x3125, як я можу це вводити в щось на кшталт шару SimpleRNN або LSTM? Чи пропускаю я якісь фундаментальні знання про те, що роблять ці шари?

Поточний код:

import pandas as pd
import numpy as np
import os
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM, Dropout, SimpleRNN, Embedding, Reshape
from keras.utils import to_categorical
from keras import regularizers
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

def readData():
    # Get labels from the labels.txt file
    labels = pd.read_csv('labels.txt', header = None)
    labels = labels.values
    labels = labels-1
    print('One Hot Encoding Data...')
    labels = to_categorical(labels)

    data = pd.read_csv('ts.txt', header = None)

    return data, labels

print('Reading data...')
data, labels = readData()

print('Splitting Data')
data_train, data_test, labels_train, labels_test = train_test_split(data, labels)

print('Building Model...')
#Create model
model = Sequential()
## LSTM / RNN goes here ##
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

print('Training NN...')
history = model.fit(data_train, labels_train, epochs=1000, batch_size=50,
    validation_split=0.25,verbose=2)

results = model.evaluate(data_test, labels_test)

predictions = model.predict(data_test)

print(predictions[0].shape)
print(np.sum(predictions[0]))
print(np.argmax(predictions[0]))

print(results)

acc = history.history['acc']
val_acc = history.history['val_acc']
epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

Відповіді:


10

Шари LSTM потребують даних різної форми.

З вашого опису я розумію, що початковий набір даних має 3125 рядків і 1000 стовпців, де кожен рядок - один крок часу. Потім цільова змінна повинна мати 3125 рядків та 1 стовпець, де кожне значення може бути одним із трьох можливих значень. Отже, це здається, що ви робите проблему з класифікацією. Щоб перевірити це в коді, я б зробив:

>>> X.shape
(3125, 1000)

>>> y.shape
(1000,)

Клас LSTM вимагає, щоб кожен окремий зразок складався з "блоку" часу. Скажімо, ви хочете мати блок з 100 часових кроків. Це означає X[0:100]- єдиний вхідний зразок, який відповідає цільовій змінній у y[100]. це означає, що розмір вікна (він же кількість часових кроків або кількість затримок) дорівнює 100. Як зазначено вище, у вас є 3125 зразків N = 3125. Щоб сформувати перший блок, ми, на жаль, мусимо відкинути перші 100 зразків y, оскільки ми не можемо сформувати цілий блок із 100 з доступних даних (нам би потрібні точки даних раніше X[0]).

Враховуючи все це, LSTM вимагає від вас надати партії форми (N - window_size, window_size, num_features), що перекладається на (3125 - 100, 100, 1000)== (3025, 100, 1000).

Створення цих блоків часу - це клопот, але створити хорошу функцію один раз, а потім зберегти її :)

Потрібно ще попрацювати, можливо, подивіться детальніше приклади мого пояснення тут ... або прочитайте документацію LSTM (або ще краще - вихідний код! ).

Кінцева модель тоді буде досить простою (на основі вашого коду):

#Create model
model = Sequential()
model.add(LSTM(units=32, activation='relu',
               input_shape=(100, 1000))    # the batch size is neglected!
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam',
              metrics=['accuracy'])

Перегляньте документацію щодо форми вводу для Sequentialмоделі . В основному це говорить про те, що нам не потрібно вказувати кількість партій всередині input_shape. Це можна зробити, наприклад batch_size=50, якщо вам потрібна фіксована цифра.

Я знаю, що input_shapeаргумент не в документації для LSTM, але сам клас успадковує RNN, який, у свою чергу, успадковує Layer- так він зможе використовувати надану вами інформацію.

Остання остання порада: якщо ви плануєте додавати декілька шарів LSTM («укладаючи» їх), вам потрібно буде додати ще один аргумент до всіх, крім останнього LSTM , а саме до return_sequences=True.


Дякую за вичерпну відповідь Dexter (!). Що стосується ваших коментарів щодо розміру партії, чи вказаний batch_size в аргументі model.fit відрізняється гіперпараметром порівняно із створенням моєї власної спеціальної партії? Мені вдалося змусити свій код принаймні виконати, змінивши свої дані з матриці 1000x3125 в матрицю 3D за допомогою data = np.reshape (data, (1000,1,3125)). Це дозволило мені запустити LSTM з input_shape (1,3125), але знову ж таки, я не дуже впевнений, що роблю. Ще раз дякую за відповідь. Я ознайомлюсь із наданими вами посиланнями та ще трохи вивчу вашу відповідь.
користувач1147964

Ласкаво просимо! Так, ви отримали це, якщо ви не batch_sizeвизначитесь із моделлю, вона буде взята з того ж аргументу в межах model.fit(). Ви повинні переробити, щоб отримати (3025, 100, 1000), що означає 3025 партій, кожен із 100 (рядків) часових кроків та 1000 (стовпців) змінних. На np.reshapeжаль, для цього на жаль не вийде (ви отримаєте помилку) через те, що у вас будуть дані, що перекриваються ... остаточна форма має більше даних, ніж вхідні дані. 3025x100x1000> 3125x1000 - np.reshapeце не подобається, оскільки це неоднозначно. Я пропоную просто прокрутити набір даних, 1 цикл = 1 зразок.
n1k31t4

Я думаю, що тут я трохи заплутався, і це може бути, тому що я, можливо, ненароком вже здійснив процес дозування. Тут я буду використовувати конкретні значення. Я взяв вибірки 3 різних вимірювань на частоті 6,25 кГц приблизно 3 хвилини, в результаті чого було створено 3 часові серії довжиною 1093750. Це генерує матрицю 3x1093750. Потім я сегментував кожну ТС на 0,5 секунди, в результаті чого виходила матриця 1050x3125. Я міг би технічно переструктурувати це в 3D-матрицю розмірами 3x350x3125. Це дає мені 350, 0,5 сек довгих "партій". Здається, що ваша переформатування генерує ще багато значень. Дякую за відповідь ще раз. Вибачте
користувач1147964

Додаю лише, що прочитавши перше, що ви опублікували, ви посилаєтесь на те, що я переробити речі правильно. Вибачте, якщо я пропускаю щось очевидне, але тут вони починаються з довжини ТС 5000, і перетворює це на 3D-матрицю з розмірами [1 25 200].
користувач1147964

Порівняно з методом у вашому посиланні, мій спосіб створить ще багато зразків. Це тому, що я використовую своєрідне "прокатне" вікно. Погляньте на це зображення . Вони не використовують прокатне вікно. Зробити 3 хвилини на шматки 350x0,5s нормально (можливо, не потрібно - як часто ви прогнозуєте?), Кожен шматок повинен бути 3x3125. "Я міг би переструктурувати це в тривимірну матрицю розмірами 3x350x3125" - це звучить краще, але після створення розколів я очікував 350x3x3125 (350 фрагментів 3x3125). Кожен з цих фрагментів потім міг бути оброблений, як я описав.
n1k31t4
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.