【问题标题】:Why can model not even predict sine为什么模型甚至无法预测正弦
【发布时间】:2017-10-08 10:42:44
【问题描述】:

我正在尝试使用 Keras 生成具有 LSTM RNN 的学习时间序列,因此我想预测一个数据点,并将其作为输入反馈回来以预测下一个等等,这样我就可以实际生成时间序列(例如给定 2000 个数据点,预测下一个 2000) 我是这样试的,但是Test score RMSE是1.28,预测基本是一条直线

# LSTM for international airline passengers problem with regression framing
import numpy
import matplotlib.pyplot as plt
from pandas import read_csv
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
# convert an array of values into a dataset matrix
def create_dataset(dataset, look_back=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset[i:(i+look_back), 0]
        dataX.append(a)
        dataY.append(dataset[i + look_back, 0])
    return numpy.array(dataX), numpy.array(dataY)
# fix random seed for reproducibility
numpy.random.seed(7)

# load the dataset
dataset = np.sin(np.linspace(0,35,10000)).reshape(-1,1)
print(type(dataset))
print(dataset.shape)
dataset = dataset.astype('float32')

# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)

# split into train and test sets
train_size = int(len(dataset) * 0.5)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]

# reshape into X=t and Y=t+1
look_back = 1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = numpy.reshape(testX, (testX.shape[0], 1, testX.shape[1]))

# create and fit the LSTM network
model = Sequential()
model.add(LSTM(16, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=10, batch_size=1, verbose=2)

# make predictions
trainPredict = model.predict(trainX)
testPredict = list()
prediction = model.predict(testX[0].reshape(1,1,1))
for i in range(trainX.shape[0]):
    prediction = model.predict(prediction.reshape(1,1,1))
    testPredict.append(prediction)
testPredict = np.array(testPredict).reshape(-1,1)

# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])

# calculate root mean squared error
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))
# shift train predictions for plotting
trainPredictPlot = numpy.empty_like(dataset)
trainPredictPlot[:, :] = numpy.nan
trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
# shift test predictions for plotting
testPredictPlot = numpy.empty_like(dataset)
testPredictPlot[:, :] = numpy.nan
testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict

# plot baseline and predictions
plt.plot(scaler.inverse_transform(dataset))
plt.plot(trainPredictPlot)
plt.plot(testPredictPlot)
plt.show()

我做错了什么?

【问题讨论】:

    标签: python keras lstm recurrent-neural-network


    【解决方案1】:

    我发现您的代码存在多个问题。 look_back 的值为 1,这意味着 LSTM 一次只能看到一个 Sample,这显然不足以了解有关序列的任何信息。

    您可能这样做是为了在最后做出最终预测,方法是将上一步的预测作为新输入。正确的方法是使用更多时间步进行训练,然后将网络更改为具有单个时间步的有状态 LSTM。

    此外,当您进行最终预测时,您必须向网络展示多个真实样本。否则,正弦上的位置是不明确的。 (下一步是涨还是跌?)

    我打了一个快速的例子。以下是我生成数据的方式:

    import numpy as np
    
    numSamples = 1000
    numTimesteps = 50
    width = np.pi/2.0
    
    def getRandomSine(numSamples = 100, width = np.pi):
        return np.sin(np.linspace(0,width,numSamples) + (np.random.rand()*np.pi*2))
    
    trainX = np.stack([getRandomSine(numSamples = numTimesteps+1) for _ in range(numSamples)])
    valX = np.stack([getRandomSine(numSamples = numTimesteps+1) for _ in range(numSamples)])
    
    trainX = trainX.reshape((numSamples,numTimesteps+1,1))
    valX = valX.reshape((numSamples,numTimesteps+1,1))
    
    trainY = trainX[:,1:,:]
    trainX = trainX[:,:-1,:]
    
    valY = valX[:,1:,:]
    valX = valX[:,:-1,:]
    

    在这里我训练了模型:

    import keras
    from keras.models import Sequential
    from keras import layers
    
    
    model = Sequential()
    model.add(layers.recurrent.LSTM(32,return_sequences=True,input_shape=(numTimesteps, 1)))
    model.add(layers.recurrent.LSTM(32,return_sequences=True))
    model.add(layers.wrappers.TimeDistributed(layers.Dense(1,input_shape=(1,10))))
    model.compile(loss='mean_squared_error',
                  optimizer='adam')
    model.summary()
    
    model.fit(trainX, trainY, nb_epoch=50, validation_data=(valX, valY), batch_size=32)
    

    在这里我更改了训练模型以允许继续预测:

    # serialize the model and get its weights, for quick re-building
    config = model.get_config()
    weights = model.get_weights()
    
    config[0]['config']['batch_input_shape'] = (1, 1, 1)
    config[0]['config']['stateful'] = True
    config[1]['config']['stateful'] = True
    
    from keras.models import model_from_config
    new_model = Sequential().from_config(config)
    new_model.set_weights(weights)
    
    #create test sine
    testX = getRandomSine(numSamples = numTimesteps*10, width = width*10)
    
    new_model.reset_states()
    testPredictions = []
    # burn in
    for i in range(numTimesteps):
        prediction = new_model.predict(np.array([[[testX[i]]]]))
        testPredictions.append(prediction[0,0,0])
    
    # prediction
    for i in range(numTimesteps, len(testX)):
        prediction = new_model.predict(prediction)
        testPredictions.append(prediction[0,0,0])
    
    # plot result
    import matplotlib.pyplot as plt
    plt.plot(np.stack([testPredictions,testX]).T)
    plt.show()
    

    这是结果的样子。预测误差加起来很快就偏离了输入正弦。但它清楚地了解了正弦的一般形状。您现在可以尝试通过尝试不同的层、激活函数等来改进这一点。

    【讨论】:

    • 行得通!我只是想,look_back = 1 应该就足够了,因为关于前面步骤的信息应该存储在隐藏状态中,不是吗?显然有一些基本的东西我还没有理解
    • 如果在训练过程中使用无状态网络,LSTM 的状态会在每批后重置。如果您使用有状态网络进行训练,它可能会像这样工作。但我认为在计算和更新look_back 步骤的梯度时会产生一些积极影响,而不仅仅是最后一个步骤。
    【解决方案2】:

    我正在研究不同的架构and uploaded it on github.

    因此,对于所有正在研究逐点预测时间序列的人,我希望这会有所帮助。

    结果如下所示:

    【讨论】:

    • “它反馈自己的预测,以生成整个时间序列,而不仅仅是未来一个点。”我说得对吗,你已经离开了原始数据集?在您的演示中,您正在解决完全不同的任务?
    • 不同任务是什么意思?
    • 对不起卢卡,我想我读错了原始问题。我在尝试研究是否有任何 python 框架能够开箱即用地学习相对“简单”的映射 y=sin(x) where x=[1;20] 例如并成功预测 x= 的 y 时遇到了这个主题[20;40] 例如。因此,无需像您的示例中那样预测许多步骤。你的 LSTM RNN 模型能做到吗?我的概念验证代码是: x=np.linspace(1,40,1000) x=x.reshape(x.shape[0],1) y=(np.sin(x)).ravel() x_tr,x_tst,y_tr,y_tst=train_test_split(x,y,shuffle=False,test_size=0.5)
    猜你喜欢
    • 2020-09-29
    • 2021-03-17
    • 2016-08-04
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-26
    相关资源
    最近更新 更多