Keras LSTM自编码器时间序列重构

16

我正在尝试使用LSTM自编码器(Keras)重构时间序列数据。 现在,我想在少量样本(5个样本,每个样本长500个时间步长,有1个维度)上训练自编码器。我希望确保模型能够重构这5个样本,之后再使用所有数据(6000个样本)。

window_size = 500
features = 1
data = data.reshape(5, window_size, features)

model = Sequential()

model.add(LSTM(256, input_shape=(window_size, features), 
return_sequences=True))
model.add(LSTM(128, input_shape=(window_size, features), 
return_sequences=False))
model.add(RepeatVector(window_size))

model.add(LSTM(128, input_shape=(window_size, features), 
return_sequences=True))
model.add(LSTM(256, input_shape=(window_size, features), 
return_sequences=True))
model.add(TimeDistributed(Dense(1)))

model.compile(optimizer='adam', loss='mse')
model.fit(data, data, epochs=100, verbose=1)

模型

训练:

Epoch 1/100
5/5 [==============================] - 2s 384ms/step - loss: 0.1603
...
Epoch 100/100
5/5 [==============================] - 2s 388ms/step - loss: 0.0018

训练后,我尝试重新构建其中的5个样本之一:

yhat = model.predict(np.expand_dims(data[1,:,:], axis=0), verbose=0)

重构:蓝色
输入:橙色

重构(蓝色)与输入(橙色)

当损失很小时,为什么重构效果如此糟糕?我该如何改进模型呢?谢谢。


2
你能展示从 data[0,:,:]data[4,:,:] 的所有图表吗? - Daniel Möller
3个回答

6

更新: 下面的答案是基于旧版本的,根据当前LSTM文档,输入应该被塑造为[批次、时间步长、特征]! 请参见:https://github.com/keras-team/keras/blob/b80dd12da9c0bc3f569eca3455e77762cf2ee8ef/keras/layers/rnn/lstm.py#L481


旧答案:

在我看来,时间序列应该以这种格式提供给LSTMs:

 (samples, features , window_size)

因此,如果您更改格式,例如交换变量并查看结果:

[![输入图像说明][1]][1]

用于重现结果的代码(我没有更改变量的名称,请不要感到困惑:)):

import numpy as np
import keras
from keras import Sequential
from keras.layers import Dense, RepeatVector,        TimeDistributed
from keras.layers import LSTM

N = 10000
data = np.random.uniform(-0.1, 0.1, size=(N, 500))
data = data.cumsum(axis=1)
print(data.shape)
window_size = 1
features = 500
data = data.reshape(N, window_size, features)

model = Sequential()

model.add(LSTM(32, input_shape=
(window_size,features), 
return_sequences=True))
model.add(LSTM(16, input_shape=(window_size,   
features), 
return_sequences=False))
model.add(RepeatVector(window_size))

model.add(LSTM(16, input_shape=(window_size, 
features), 
return_sequences=True))
model.add(LSTM(32, input_shape=(window_size,   
features), 
return_sequences=True))
model.add(TimeDistributed(Dense(500)))

model.compile(optimizer='adam', loss='mse')
model.fit(data, data, epochs=100, verbose=1)


yhat = model.predict(np.expand_dims(data[1,:,:],   axis=0), verbose=0)
plot(np.arange(500), yhat[0,0,:])
plot(np.arange(500), data[1,0,:])

Credit to sobe86: 我使用了他/她提供的数据。 [1]: https://istack.dev59.com/5JUDN.webp

1
这不正确。Keras明确指出应该将格式(samples, window_size, n_features)提供给lstm。在此处阅读更多信息https://blog.keras.io/building-autoencoders-in-keras.html和https://keras.io/api/layers/recurrent_layers/lstm/,因此您建议的格式根本没有实现lstm,它的行为更像是一个密集层,因为您只有1个特征。 - Zeinab Sobhani

2
我尝试在以下数据上运行您的代码。
data = np.random.uniform(-0.1, 0.1, size=(5, 500))
data = data.cumsum(axis=1)

因此,数据只是一些随机均匀噪声的累积和。我运行了1000个epoch,我的结果并不像你的那样糟糕,LSTM似乎会尽力跟随线路,尽管它似乎只是在围绕运行平均值徘徊(正如我们所期望的那样)。
请注意,这是在训练数据上运行模型(你似乎在问题中暗示了这一点)-如果我们试图查看模型在未经过训练的数据上的性能,我们可能会得到糟糕的结果。
这一点毫不奇怪,由于训练集太小,我们应该完全预计模型会过度拟合,并且不能推广到新数据。

0

从我尝试拟合自动编码器的经验中,我明白了一件事,那就是它们并不容易拟合。但是我建议检查以下几个因素:

  1. LSTM对非平稳数据效果不佳。它会试图学习数据的趋势而不是变异性。因此,在处理数据之前,去趋势化是一个很好的步骤。现在,做到这一点的一种简单方法是计算数据与其前一个时间戳的差异。然后,在每个时间步长上,你将得到x[i]-x[i-1]而不是x[i]。你可以根据数据及其趋势/季节性尝试不同的去趋势化顺序。例如,如果你预期数据具有每周季节性,另一个要检查的顺序可能是7天(如果每个时间步长是一天),那么你的数据将是x[i]-x[i-7]。
  2. 尝试调整自动编码器的架构。根据序列长度,32个隐藏单元可能不足以正确编码数据并保留足够的信息。
  3. 使用双向层。有时我也会使用Conv1D。
  4. 不需要对称。所以要有创造力。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接