具有 LSTM 层的回归器不断返回相同的值
Regressor with LSTM layer keeps returning same value
如果我 运行 下面的代码,我将得到相同值的数组(预测),如您在此处所见:
基本上我对 regressor 的输入是数字 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()
正如我在评论中解释的那样,这是一个简单的线性问题,因此您可以使用线性回归。如果你想使用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()
上面的代码将产生所需的预测,以下是我所做的更改:
- 将模型改为单dense layer,正如我解释的,是线性关系
- 增加批量大小。这只是为了更快的训练,如果你愿意,你可以减少,但是你需要同时降低学习率和增加 epochs
- 将epochs增加到1000。这个数据包含大量无用信息,只有每个X的最后一个值有用,所以需要相对更多的epochs来学习。事实上,像这样使用线性回归时,通常有数千甚至数万个 epoch,因为每个 epoch 都非常快
- 将数据重塑为 (num_samples, num_features),这是 Dense 层所期望的
- 提高学习率,只为学得更快
我只是修改这个来证明我的观点,我没有进一步调整任何其他参数,我相信你可以添加正则化器、改变学习率等等,以使其更快更容易。但老实说,我认为不值得花时间调整它们,因为预测线性关系并不是深度学习的目的。
希望这对您有所帮助,如果您有进一步的困惑,请随时发表评论:)
你的模型对于这个问题绝对是矫枉过正,但这不是问题!
我们想要预测一个只有 2 个参数的线性函数 (predicted = model(x) = param1 + param2 * x)。只有一个神经元(wheight + bias)的模型应该足够了。
这里你的模型有 91,251 个参数!
使用 LSTM 的模型和使用 Dense 层的模型是拓扑全纯的,因此每个 LSTM 模型都能够达到与 Dense 模型相同的结果,反之亦然。 (LSTM 通常很容易训练以达到与密集模型相同的结果。)
您的代码中存在许多问题和最佳实践。
这种类型的问题称为“时间序列预测”,如果您想对此主题进行更多研究,它们在互联网上有很多很棒的文章。
首先总是缩放你的数据!
未缩放的数据使训练更加困难。
通常,对于回归问题,数据集在 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 是超参数,如优化器、learning_rate、batch_size、权重和偏置初始化...
因此,如果您的模型无法达到您的目标,请从简单开始并增加模型复杂性。
增加训练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()
如果我 运行 下面的代码,我将得到相同值的数组(预测),如您在此处所见:
基本上我对 regressor 的输入是数字 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()
正如我在评论中解释的那样,这是一个简单的线性问题,因此您可以使用线性回归。如果你想使用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()
上面的代码将产生所需的预测,以下是我所做的更改:
- 将模型改为单dense layer,正如我解释的,是线性关系
- 增加批量大小。这只是为了更快的训练,如果你愿意,你可以减少,但是你需要同时降低学习率和增加 epochs
- 将epochs增加到1000。这个数据包含大量无用信息,只有每个X的最后一个值有用,所以需要相对更多的epochs来学习。事实上,像这样使用线性回归时,通常有数千甚至数万个 epoch,因为每个 epoch 都非常快
- 将数据重塑为 (num_samples, num_features),这是 Dense 层所期望的
- 提高学习率,只为学得更快
我只是修改这个来证明我的观点,我没有进一步调整任何其他参数,我相信你可以添加正则化器、改变学习率等等,以使其更快更容易。但老实说,我认为不值得花时间调整它们,因为预测线性关系并不是深度学习的目的。
希望这对您有所帮助,如果您有进一步的困惑,请随时发表评论:)
你的模型对于这个问题绝对是矫枉过正,但这不是问题! 我们想要预测一个只有 2 个参数的线性函数 (predicted = model(x) = param1 + param2 * x)。只有一个神经元(wheight + bias)的模型应该足够了。 这里你的模型有 91,251 个参数! 使用 LSTM 的模型和使用 Dense 层的模型是拓扑全纯的,因此每个 LSTM 模型都能够达到与 Dense 模型相同的结果,反之亦然。 (LSTM 通常很容易训练以达到与密集模型相同的结果。)
您的代码中存在许多问题和最佳实践。
这种类型的问题称为“时间序列预测”,如果您想对此主题进行更多研究,它们在互联网上有很多很棒的文章。
首先总是缩放你的数据!
未缩放的数据使训练更加困难。
通常,对于回归问题,数据集在 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 是超参数,如优化器、learning_rate、batch_size、权重和偏置初始化...
因此,如果您的模型无法达到您的目标,请从简单开始并增加模型复杂性。
增加训练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()