我正在尝试使用Keras对时间序列数据训练一个ANN。我有三个数据向量,这些向量被分成滚动窗口序列(例如,对于向量l)。
np.array([l[i:i+window_size] for i in range( len(l) - window_size)])
目标向量同样被分成窗口,因此神经网络的输出是对接下来window_size个时间步长的目标向量的预测。所有数据都使用最小-最大缩放器进行归一化。数据以shape=(nb_samples, window_size, 3)的形式输入到神经网络中。这是3个输入向量的图表。
我从ANN中勉强得到的唯一输出是下面的图表。目标向量为蓝色,预测为红色(图表放大以使预测模式可读)。预测向量以window_size的间隔绘制,因此每个重复的模式都是网络的一个预测。
我尝试了许多不同的模型架构、训练轮数、激活函数,以及短而宽的网络、瘦长的网络。这是我的当前模型(有点另类)。
Conv1D(64,4, input_shape=(None,3)) ->Conv1d(32,4) -> Dropout(24) -> LSTM(32) ->Dense(window_size)
但无论我尝试什么,都无法改变神经网络输出这种重复模式。我一定是误解了关于时间序列或Keras中LSTM的一些东西。但我现在非常迷茫,所以任何帮助都将不胜感激。我已在该仓库中附上完整代码。
https://github.com/jaybutera/dat-toy
回答:
我对你的代码做了一些调整,我认为我有一些建议可以帮助你走上正轨。代码似乎与你的图表不完全匹配,但我假设你自那以后已经做了一些调整。无论如何,主要有两个问题:
-
最大的问题在于你的数据准备步骤。你基本上把数据形状弄反了,你对X使用了一个时间步长的输入,而对Y使用了一个时间序列。你的输入形状是(18830, 1, 8),而你真正想要的是(18830, 30, 8),这样可以将完整的30个时间步长输入到LSTM中。否则,LSTM只在一个时间步长上操作,并不真正有用。为了解决这个问题,我在
common.py
中将代码从X = X.reshape(X.shape[0], 1, X.shape[1])
改为
X = windowfy(X, winsize)
同样,输出数据可能只需要一个值,根据我在绘图函数中对你的目标的理解。确实有些情况下你想预测整个时间序列,但我不知道这是否是你想要的。在这种情况下,我将
Y_train
改为使用fuels
而不是fuels_w
,这样它只需要预测时间序列的一个步骤。 -
对于这个简单的网络架构来说,训练100个轮次可能太多了。在我运行的一些情况下,看起来似乎有一些过拟合。在观察网络损失的减少情况时,似乎只需要3-4个轮次即可。
这是经过我提到的调整后,训练3个轮次后的预测图表。这不是一个很好的预测,但至少看起来现在走上了正轨。祝你好运!
编辑:预测多个输出时间步长的示例:
from sklearn import datasets, preprocessingimport numpy as npfrom scipy import statsfrom keras import models, layersINPUT_WINDOW = 10OUTPUT_WINDOW = 5 # 预测输出变量的5个步骤。# 随机生成一些回归数据(不是真正的顺序数据;样本是独立的)。np.random.seed(11798)X, y = datasets.make_regression(n_samples=1000, n_features=4, noise=.1)# 重新缩放到0-1并转换为窗口序列。X = preprocessing.MinMaxScaler().fit_transform(X)y = preprocessing.MinMaxScaler().fit_transform(y.reshape(-1, 1))X = np.array([X[i:i + INPUT_WINDOW] for i in range(len(X) - INPUT_WINDOW)])y = np.array([y[i:i + OUTPUT_WINDOW] for i in range(INPUT_WINDOW - OUTPUT_WINDOW, len(y) - OUTPUT_WINDOW)])print(np.shape(X)) # (990, 10, 4) - 十个时间步长的四个特征print(np.shape(y)) # (990, 5, 1) - 五个时间步长的单个特征# 构建一个简单的模型,预测输出序列。m = models.Sequential()m.add(layers.LSTM(20, activation='relu', return_sequences=True, input_shape=(INPUT_WINDOW, 4)))m.add(layers.LSTM(20, activation='relu'))m.add(layers.RepeatVector(OUTPUT_WINDOW))m.add(layers.LSTM(20, activation='relu', return_sequences=True))m.add(layers.wrappers.TimeDistributed(layers.Dense(1, activation='sigmoid')))print(m.summary())m.compile(optimizer='adam', loss='mse')m.fit(X[:800], y[:800], batch_size=10, epochs=60) # 在前800个序列上训练。preds = m.predict(X[800:], batch_size=10) # 预测剩余的序列。print('预测:\n' + str(preds[0]))print('实际:\n' + str(y[800]))# 相关系数应该大约为r = .98,基本完美。print('相关系数: ' + str(stats.pearsonr(y[800:].flatten(), preds.flatten())[0]))