【问题标题】:Regressor with LSTM layer keeps returning same value具有 LSTM 层的回归器不断返回相同的值
【发布时间】:2021-10-07 22:32:36
【问题描述】:

如果我运行以下代码,我将获得相同值的数组(预测),如您在此处看到的:

基本上,我对回归器的输入是数字 0、1、2、... 99 的数组,我希望输出为 100。 正如您在代码中看到的那样,我按顺序(多次)执行此操作。 此代码应该是可运行的。我做错了什么,为什么预期的结果和结果不同?

代码:

import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt

from keras.layers import Dense
from keras.layers import LSTM
from keras.models import Sequential
from keras.layers import Dropout
from sklearn.preprocessing import MinMaxScaler
from datetime import datetime
from datetime import timedelta
from time import mktime


my_data = []
for i in range(0, 1000):
    my_data.append(i)

X_train = []
y_train = []

np_data = np.array(my_data)

for i in range(0, np_data.size - 100 ):
    X_train.append(np_data[i : i+100])
    y_train.append(np_data[i+100])

X_train, y_train = np.array(X_train), np.array(y_train)

X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1], 1])

regressor = Sequential()

regressor.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], 1)))

regressor.add(Dropout(0.2))


regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50))
regressor.add(Dropout(0.2))

regressor.add(Dense(units=1))

regressor.compile(optimizer='adam', loss='mean_squared_error')

regressor.fit(X_train, y_train, epochs=5, batch_size=32)


X_test = []
y_test = []

my_data = []
for i in range(1000, 1500):
    my_data.append(i)

np_data = np.array(my_data)

for i in range(0, np_data.size - 100 ):
    X_test.append(np_data[i : i+100])
    y_test.append(np_data[i+100])

X_test = np.array(X_test)

X_test = np.reshape(X_test, [X_test.shape[0], X_test.shape[1], 1])

predicted = regressor.predict(X_test)


plt.plot(y_test, color = '#ffd700', label = "Real Data")
plt.plot(predicted, color = '#1fb864', label = "Predicted Data")

plt.title(" Price Prediction")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.legend()
plt.show()

【问题讨论】:

  • 我认为这仅仅是因为模型太复杂而无法学习,这只是一个简单的线性预测任务,单个 Dense 层就足够了。
  • 嗨@seermer,你能推荐一个工作代码吗?
  • 看下面的答案,我修改为按预期工作的代码

标签: tensorflow machine-learning keras neural-network lstm


【解决方案1】:

正如我在评论中解释的那样,这是一个简单的线性问题,因此您可以使用线性回归。如果你想使用 keras/tf,你可以构建一个具有单个密集层的模型,下面是一个可以工作的代码:

import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
from keras import optimizers
from keras.layers import Dense
from keras.layers import LSTM
from keras.models import Sequential
from keras.layers import Dropout
from sklearn.preprocessing import MinMaxScaler
from datetime import datetime
from datetime import timedelta
from time import mktime

my_data = []
for i in range(0, 1000):
    my_data.append(i)

X_train = []
y_train = []

np_data = np.array(my_data)

for i in range(0, np_data.size - 100):
    X_train.append(np_data[i: i + 100])
    y_train.append(np_data[i + 100])

X_train, y_train = np.array(X_train), np.array(y_train)

X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1]])

regressor = Sequential()

regressor.add(Dense(units=1, input_shape=(len(X_train[1]),)))

regressor.compile(optimizer=optimizers.adam_v2.Adam(learning_rate=0.1), loss='mean_squared_error')

regressor.fit(X_train, y_train, epochs=1000, batch_size=len(X_train))

X_test = []
y_test = []

my_data = []
for i in range(1000, 1500):
    my_data.append(i)

np_data = np.array(my_data)

for i in range(0, np_data.size - 100):
    X_test.append(np_data[i: i + 100])
    y_test.append(np_data[i + 100])

X_test = np.array(X_test)

X_test = np.reshape(X_test, [X_test.shape[0], X_test.shape[1]])

predicted = regressor.predict(X_test)

plt.plot(y_test, color='#ffd700', label="Real Data")
plt.plot(predicted, color='#1fb864', label="Predicted Data")

plt.title(" Price Prediction")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.legend()
plt.show()

上面的代码会产生想要的预测,以下是我所做的更改:

  1. 将模型更改为单个密集层,正如我所解释的,它是线性关系
  2. 增加批量大小。这只是为了更快的训练,如果你愿意,你可以减少,但是你需要同时降低学习率和增加 epoch
  3. 将 epochs 增加到 1000。该数据包含大量无用信息,只有每个 X 的最后一个值是有用的,因此需要相对更多的 epoch 来学习。事实上,像这样使用线性回归时,通常会有数千甚至数万个 epoch,因为每个 epoch 无论如何都非常快
  4. 将数据重塑为 (num_samples, num_features),这是 Dense 层所期望的
  5. 提高学习率,只为更快学习

我只是修改了这个来证明我的观点,我没有进一步调整任何其他参数,我相信你可以添加正则化器,改变学习率等等,让它更快更容易。但老实说,我认为不值得花时间调整它们,因为预测线性关系真的不是深度学习的目的。
希望对您有所帮助,如果您有进一步的困惑,请随时发表评论:)

【讨论】:

    【解决方案2】:

    您的模型对于这个问题绝对是矫枉过正,但这不是问题! 我们想要预测一个线性函数,它只能存在 2 个参数(预测 = 模型(x)= 参数 1 + 参数 2 * x)。只有一个神经元(体重 + 偏差)的模型就足够了。 在这里,您的模型有 91,251 个参数! 使用 LSTM 的模型和使用 Dense 层的模型在拓扑上是全纯的,因此每个 LSTM 模型都能够获得与 Dense 模型相同的结果,反之亦然。 (LSTM 通常很容易训练以获得与 Dense 模型相同的结果。)

    您的代码中存在许多问题和最佳实践。

    这种类型的问题被称为“时间序列预测”,如果您想对此主题进行更多调查,它们是互联网上很多很棒的文章。

    首先始终扩展您的数据!
    未缩放的数据使训练更加困难。
    通常,对于回归问题,数据集在 0 和 1 之间缩放。因此,只需将数据除以 np_data 中的最大值即可。
    损失函数的极高值,例如“mean_square_error”,应该暗示模型接收到的数据没有缩放。

    对于使用 LSTM 层重塑 X_train y_train 的模型:

    • X_train 的形状应该是:(dataset_size, n_past, n_feature)
    • y_train 的形状应该是:(dataset_size, n_future, n_feature)

    地点:

    • n_feature :数据集中存在的不同数据的数量,模型应该进行预测。例如,如果你想根据最近 N 天的平均压力、平均温度和降水量来预测第二天的平均温度,n_feature 应该等于 3(“多变量时间序列预测”)
    • n_past : 给模型的过去条目数
    • n_future : 你要预测的未来预测次数(“时间序列多步预测”)

    (注意:X_train 和 y_train 中的 n_feature 不能相同)

    这里:

    • n_past : 100(为了加快训练速度,我在代码中将其减少到 4,这太过分了)
    • n_future : 1 因为您只预测一个数字,但您可以预测例如接下来的 10 个数字(您需要更改创建 y_train 的方式以匹配形状 (dataset_len, 10, 1))
    • n_feature : 1

    从更简单的模型开始:
    隐藏层数、神经元数和 LSTM n_past 是超参数,如优化器、学习率、批处理大小、权重和偏差初始化...... 因此,如果您的模型无法达到您的目标,请从简单开始并增加模型复杂性。

    增加训练epoch的数量。

    研究训练过程中损失函数的构成:目标是收敛到0。

    制作一个验证集以控制训练期间的过度拟合。

    my_data = []
    for i in range(0, 1000):
        my_data.append(i)
    
    X_train = []
    y_train = []
    
    np_data = np.array(my_data)
    
    # last 4 values to predict the next one
    n_past = 4
    n_future = 1
    n_feature = 1
    
    for i in range(0, np_data.size - n_past):
        X_train.append(np_data[i : i + n_past])
        y_train.append(np_data[i + n_past])
    
    X_train, y_train = np.array(X_train), np.array(y_train)
    
    # Reshape
    X_train = np.reshape(X_train, [X_train.shape[0], n_past, n_feature])
    y_train = np.reshape(y_train, [y_train.shape[0], n_future, n_feature])
    
    # Rescale dataset ]0,1]
    max_value = np.max(np_data)
    X_train = X_train / max_value
    y_train = y_train / max_value
    
    # More simple model (always overkill for linear function anyway)
    # No Droupout because I dont know if the model is doing overfitting
    regressor = Sequential()
    regressor.add(LSTM(units=16, return_sequences=True, input_shape=(n_past, n_feature)))
    regressor.add(LSTM(units=16, return_sequences=True))
    regressor.add(LSTM(units=16))
    regressor.add(Dense(units=1))
    
    regressor.compile(optimizer='Adam', loss='mse')
    
    # Summary the model to see if all layers are well combinated.
    regressor.summary()
    
    # validation_split = 0.2 : 20% of X_train and y_train are using to test your model
    history = regressor.fit(X_train, y_train, epochs=100, batch_size=32, validation_split=0.2)
    
    # Plot the training
    plt.plot(history.history["loss"], color = 'red', label = "Traning loss")
    plt.plot(history.history["val_loss"], color = 'green', label = "Validation loss")
    plt.title("Training")
    plt.xlabel("Epoch")
    plt.ylabel("mse")
    plt.legend()
    plt.show()
    
    
    # Make one test
    test_i = 12
    data = X_train[test_i].reshape(1, n_past, 1) # taking [test_i] result to the lost of the first dimension so : reshape to (batch_size=1, n_past, n_feature) for making prediction
    expected = y_train[test_i]
    predicted = regressor.predict(data)
    print(f"data: {data.reshape(-1,) * max_value}\nExpected: {expected * max_value}\nPredicted: {predicted[0] * max_value}")
    # multipled by max_value to rescale to the original data
    
    
    X_test = []
    y_test = []
    my_data = []
    for i in range(1000, 1500):
        my_data.append(i)
    
    np_data = np.array(my_data)
    
    for i in range(0, np_data.size - n_past ):
        X_test.append(np_data[i : i + n_past])
        y_test.append(np_data[i + n_past])
    
    X_test = np.array(X_test)
    X_test = np.reshape(X_test, [X_test.shape[0], n_past, n_feature])
    
    # scale the data with the max_value of the training
    X_test = X_test / max_value
    predicted = regressor.predict(X_test)
    
    # rescale the prediction
    predicted = predicted * max_value
    
    plt.plot(y_test, color = '#ffd700', label = "Real Data")
    plt.plot(predicted, color = '#1fb864', label = "Predicted Data")
    
    plt.title(" Price Prediction")
    plt.xlabel("X axis")
    plt.ylabel("Y axis")
    plt.legend()
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 2012-07-02
      • 2010-09-22
      • 2015-06-30
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      相关资源
      最近更新 更多