具有一维时间序列的 Keras LSTM

数据挖掘 Python 深度学习 时间序列 lstm rnn
2021-09-29 05:26:08

我正在学习如何使用 Keras,并且使用 Chollet 的Python 深度学习中的示例,我在标记数据集方面取得了相当大的成功数据集是约 1000 个时间序列,长度为 3125,具有 3 个潜在类别。

我想超越基本的Dense层,这给了我大约 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()
1个回答

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 要求您交付一批 shape (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如果您要求它是一个固定数字,可以使用 eg 来完成。

我知道该input_shape参数不在文档中LSTM,但该类本身继承自RNN,而后者又继承自Layer- 因此它将能够使用您提供的信息。

最后一个提示:如果您计划添加多个 LSTM 层(“堆叠”它们),那么您需要向除最后一个 LSTM之外的所有层添加一个参数,即return_sequences=True.