我试图解决一个非常简单的问题(虽然简单,但它让我头疼)。
我的数据是这样的
0.64900194, 2.32144675, 4.36117903, 6.8795263 , 8.70335759, 10.52469321, 12.50494439, 14.92118469, 16.31657096, 18.69954666, 20.653336 , 22.08447934, 24.29878371, 26.01567801, 28.3626067 , 30.75065028, 32.81166691, 34.52029737, 36.90956918, 38.55743122
上述数据序列对应的目标值为40.24253
如您所见,这是一个简单的LSTM序列预测问题,输入数据是过去20个2的乘积序列值,目标是序列中的下一个数字加上某个随机的均匀数(为了增加一些噪声)。
样本输入和目标的大小分别为:(batch_size, 20, 1) 和 (batch_size, )
这是我用于预测的代码:
def univariate_data(dataset, start_index, end_index, history_size, target_size): data = [] labels = [] start_index = start_index + history_size if end_index is None: end_index = len(dataset) - target_size for i in range(start_index, end_index): indices = range(i-history_size, i) # Reshape data from (history_size,) to (history_size, 1) data.append(np.reshape(dataset[indices], (history_size, 1))) labels.append(dataset[i+target_size]) return np.array(data), np.array(labels)uni_data = np.array([(i*2)+random.random() for i in range(0,400000)])TRAIN_SPLIT = 300000uni_train_mean = uni_data[:TRAIN_SPLIT].mean()uni_train_std = uni_data[:TRAIN_SPLIT].std()uni_data = (uni_data-uni_train_mean)/uni_train_stdunivariate_past_history = 20univariate_future_target = 0x_train_uni, y_train_uni = univariate_data(uni_data, 0, TRAIN_SPLIT, univariate_past_history, univariate_future_target)x_val_uni, y_val_uni = univariate_data(uni_data, TRAIN_SPLIT, None, univariate_past_history, univariate_future_target)print ('Single window of past history')print (x_train_uni.shape)print ('\n Target temperature to predict')print (y_train_uni.shape)BATCH_SIZE = 256BUFFER_SIZE = 10000train_univariate = tf.data.Dataset.from_tensor_slices((x_train_uni, y_train_uni))train_univariate = train_univariate.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()val_univariate = tf.data.Dataset.from_tensor_slices((x_val_uni, y_val_uni))val_univariate = val_univariate.batch(BATCH_SIZE).repeat()simple_lstm_model = tf.keras.models.Sequential([ tf.keras.layers.LSTM(8, input_shape=x_train_uni.shape[-2:]), tf.keras.layers.Dense(1)])simple_lstm_model.compile(optimizer='adam', loss='mae')for x, y in val_univariate.take(1): print(simple_lstm_model.predict(x).shape)EVALUATION_INTERVAL = 200EPOCHS = 10simple_lstm_model.fit(train_univariate, epochs=EPOCHS, steps_per_epoch=EVALUATION_INTERVAL, validation_data=val_univariate, validation_steps=50)
对于任何给定的序列,预测值与实际值相差甚远,任何建议都会有所帮助。
之前的一些搜索建议了归一化和标准化,我都尝试过了。我还尝试了不同层的LSTM,并尝试了SimpleRNN和GRU。尝试了不同的激活函数,如’tanh’和’relu’。还尝试了使用过去的10、30和50个值,而不是过去的20个值。这些都没有帮助。我认为我犯了一个非常简单的错误,任何指导都会非常有帮助。谢谢,保重!!
回答:
所以我终于找到了解决方案。
上述方法的问题在于我的训练数据和测试数据的均值和标准差非常不同。换句话说,我用范围(0,400000)的数据训练模型,而我的测试集是范围(400000, 500000)的数据。现在,从训练数据中获得的均值和标准差与测试数据大不相同,而且在上述情况下,标准差(训练数据的)大约是173,250。任何模型在训练数据具有如此高标准差的情况下预测准确度都非常困难。
解决方案是,不要直接将数据输入模型,而是输入连续元素的差异。例如,不要输入数据p = [0, 1, 2, 3, 4, 5, 6]
,而是输入数据q = [2, 2, 2, 2, 2, 2, 2]
,其中q是通过q[i] = p[i] - p[i-1]
获得的。所以现在如果我们用数据q喂养模型,模型当然会预测出2,因为模型只看到输入值为2,我们只需将这个值加到最后一个实际值上即可得出结果。
因此,模型的基本问题是训练数据的高标准差和测试中未见过的值,而解决方案是输入值的差异。
但另一个问题是,如果我们想预测2的幂,即2的指数,在这种情况下,模型可能会从类型q的数据中学习趋势,但模型仍然不会非常准确,因为在某个点上,它又会遇到具有非常高均值和标准差的值。
最后,我在某处读到LSTM并不适合从模型未接触过的嵌入空间中外推数据,有其他模型用于外推数据,但LSTM不是其中之一。