使用GRU模型进行多变量预测,训练过程损失几乎为0,但预测效果非常差,是什么原因呢?
数据样式:
损失图像:
预测效果:
下面附上主体代码:
# 本代码参考:https://blog.csdn.net/m0_47256162/article/details/128595011?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167599212716800188597284%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167599212716800188597284&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-3-128595011-null-null.142^v73^control_1,201^v4^add_ask,239^v1^insert_chatgpt&utm_term=gru&spm=1018.2226.3001.4187
class Config():
data_path = 'AMZN_2006-01-01_to_2018-01-01.csv'
timestep = 30 # 时间步长,就是利用多少时间窗口
batch_size = 32 # 批次大小
feature_size = 5 # 每个步长对应的特征数量
hidden_size = 124 # 隐层大小
output_size = 1 # 由于是单输出任务
num_layers = 2 # gru的层数
epochs = 10 # 迭代轮数
learning_rate = 0.001 # 学习率
model_name = 'GRU' # 模型名称
save_path = './model_GRU_{}.pth' # 最优模型保存路径
config = Config()
# 1.加载时间序列数据
df = pd.read_csv(config.data_path, index_col=0)
# 2.将数据进行标准化
scaler_model = MinMaxScaler()
data = scaler_model.fit_transform(np.array(df[['Open','High','Low','Close','Volume']]))
# scaler_model.fit_transform(np.array(df['Open']).reshape(-1, 1))
# print(data, data.shape) # (3019, 5)
# 形成训练数据
def split_data(data, timestep, feature_size):
dataX = [] # 保存X
dataY = [] # 保存Y
# 将整个窗口的数据保存到X中,将未来一天保存到Y中
for index in range(len(data) - timestep):
dataX.append(data[index: index + timestep, :])
dataY.append(data[index + timestep, 0])
dataX = np.array(dataX)
dataY = np.array(dataY)
# print('\ndataX', dataX.shape, '\ndataY', dataY.shape) # dataX (2989, 30, 5) ; dataY (2989,)
# 获取训练集大小
train_size = int(np.round(0.8 * dataX.shape[0]))
# 划分训练集、测试集
x_train = dataX[: train_size, :]
y_train = dataY[: train_size].reshape(-1, 1)
x_test = dataX[train_size:, :]
y_test = dataY[train_size:].reshape(-1, 1)
return [x_train, y_train, x_test, y_test]
# 3.获取训练数据
x_train, y_train, x_test, y_test = split_data(data, config.timestep, config.feature_size)
# print(x_train.shape, y_train.shape, x_test.shape, y_test.shape) # (2391, 30, 5) (2391, 1) (598, 30, 5) (598, 1)
# 4.将数据转为tensor
x_train_tensor = torch.from_numpy(x_train).to(torch.float32)
y_train_tensor = torch.from_numpy(y_train).to(torch.float32)
x_test_tensor = torch.from_numpy(x_test).to(torch.float32)
y_test_tensor = torch.from_numpy(y_test).to(torch.float32)
# 5.形成训练数据集(封装)
train_data = TensorDataset(x_train_tensor, y_train_tensor)
test_data = TensorDataset(x_test_tensor, y_test_tensor)
# 6.将数据加载成迭代器
train_loader = torch.utils.data.DataLoader(train_data,
batch_size=config.batch_size,
shuffle=False)
test_loader = torch.utils.data.DataLoader(test_data,
config.batch_size,
False)
# 7.定义GRU网络
class GRU(nn.Module):
def __init__(self, feature_size, hidden_size, num_layers, output_size):
super(GRU, self).__init__()
self.hidden_size = hidden_size # 隐层大小
self.num_layers = num_layers # gru层数
# feature_size为特征维度,就是每个时间点对应的特征数量,这里为1
self.gru = nn.GRU(feature_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x, hidden=None):
batch_size = x.shape[0] # 获取批次大小 batch_size == config.batch_size
# 初始化隐层状态
if hidden is None:
h_0 = x.data.new(self.num_layers, batch_size, self.hidden_size).fill_(0).float()
else:
h_0 = hidden
# GRU运算
output, h_0 = self.gru(x, h_0)
# 获取GRU输出的维度信息
batch_size, timestep, hidden_size = output.shape
# 将output变成 batch_size * timestep, hidden_dim
output = output.reshape(-1, hidden_size)
# 全连接层
output = self.fc(output) # 形状为batch_size * timestep, 1
# 转换维度,用于输出
output = output.reshape(timestep, batch_size, -1)
# 只需要返回最后一个时间片的数据即可
return output[-1]
model = GRU(config.feature_size, config.hidden_size, config.num_layers, config.output_size) # 定义GRU网络
loss_function = nn.MSELoss(reduction='mean') # 定义损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate) # 定义优化器
# 8.模型训练
train_loss = []
test_loss = []
for epoch in range(config.epochs):
model.train()
train_bar = tqdm(train_loader) # 形成进度条
train_loss_per_epoch = []
test_loss_per_epoch = []
for data in train_bar:
x_train, y_train = data # 解包迭代器中的X和Y
y_train_pred = model(x_train)
loss = loss_function(y_train_pred, y_train)
train_loss_per_epoch.append( loss.item() )
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_bar.desc = "train epoch[{}/{}], MSEloss:{:.3f} ".format(epoch + 1,
config.epochs,
loss)
# 模型验证
model.eval()
with torch.no_grad():
test_bar = tqdm(test_loader)
for data in test_bar:
x_test, y_test = data
y_test_pred = model(x_test)
loss = loss_function(y_test_pred, y_test)
test_loss_per_epoch.append(loss.item())
train_loss.append( sum(train_loss_per_epoch) / len(train_loss_per_epoch) )
test_loss.append( sum(test_loss_per_epoch) / len(test_loss_per_epoch) )
# if (epoch+1) % 10 == 0 :
# torch.save(model.state_dict(), config.save_path.format(epoch+1))
print('\n-------------Finished Training-------------')
model.eval()
# 反归一化
def inverse_transform(x):
prediction_copies = np.repeat(x.detach().numpy(), 5, axis=-1)
pred = scaler_model.inverse_transform(np.reshape(prediction_copies, (len(x), 5) ))[:, 0]
return pred
# 训练集
# pred_train = inverse_transform( model(x_train_tensor) )
# true_train = inverse_transform( y_train_tensor )
prediction_copies1 = np.repeat(model(x_train_tensor).detach().numpy(), 5, axis=-1)
pred_train = scaler_model.inverse_transform(np.reshape(prediction_copies1, (len(model(x_train_tensor)), 5) ))[:, 0]
prediction_copies2 = np.repeat(y_train_tensor.detach().numpy(), 5, axis=-1)
true_train = scaler_model.inverse_transform(np.reshape(prediction_copies2, (len(y_train_tensor), 5) ))[:, 0]
# 验证集
pred_test = inverse_transform( model(x_test_tensor) )
true_test = inverse_transform( y_test_tensor )
plt.figure(figsize=(12, 8))
plt.plot(train_loss, "b")
plt.plot(test_loss, "r")
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Change of MSELoss')
plt.legend()
plt.show()
# 9.绘制结果
plt.figure(figsize=(12, 8))
plt.subplot(1,2,1)
plt.plot(pred_train, "b")
plt.plot(true_train, "r")
plt.xlabel('Time')
plt.ylabel('Open Value')
plt.title('Pred and True data of Train')
plt.legend()
plt.subplot(1,2,2)
plt.plot(pred_test, "b")
plt.plot(true_test, "r")
plt.xlabel('Time')
plt.ylabel('Open Value')
plt.title('Pred and True data of Test')
plt.legend()
plt.show()
可能是由于模型过拟合导致的。过拟合是指模型在训练数据上表现良好,但在新数据上表现不佳的情况。可能是由于训练数据中的噪声或偏差导致的,也可能是由于模型复杂度过高导致的。为了解决这个问题,可以尝试减少模型复杂度,添加正则化项,或者使用更多的训练数据。
过拟合:当模型的训练损失几乎为0时,可能出现了过拟合的情况,导致模型对训练集过于拟合,而对测试集或实际数据的预测效果较差。
数据质量问题:数据可能存在一些异常值或缺失值,或者存在一些噪声或不可靠的数据,这可能会对模型的预测效果造成不良影响。
模型复杂度不够:如果模型复杂度不够,可能无法捕捉到数据的复杂性和潜在关系,从而导致预测效果较差。
参数设置不当:模型参数的设置可能会影响模型的预测效果,如学习率、时间步长等参数设置不当,可能会导致模型的预测效果较差。
针对以上问题,可以采取一些解决方案来优化模型:
对模型进行正则化,如加入L1/L2正则化、Dropout等,以避免过拟合。
对数据进行清洗和处理,去除异常值、缺失值、噪声等。
调整模型的复杂度,如增加隐藏层、调整神经元数量等,以提高模型的学习能力。
调整参数,如调整学习率、时间步长等,以提高模型的预测效果。
通过对以上方面的优化,可以提高GRU模型的预测效果,从而更好地解决多变量预测问题。
过拟合太严重,你将预测数据分一部分去训练集中,重新训练,你观察下是否loss就没这么好了
这种大概率就是过拟合了,模型一旦过拟合,泛化能力不行,也就是在新的测试集上的表现就不够好,也就是你所说的预测效果很差。解决方法是丰富你训练的数据集,可以直接丰富采集的数据集也可以采用数据增强的方式来扩充数据集。
如果您的上述程序在训练过程中损失几乎为0,但预测效果非常差,那么有以下几种可能的原因:
1.Overfitting:模型可能过于复杂,在训练数据上表现良好,但在新数据上表现不佳。您可以尝试减少模型的复杂度,例如通过减少隐藏单元的数量或使用正则化技巧。
2.不够的训练数据:如果您的数据量较小,模型可能无法捕捉训练数据中的趋势和关系。您可以尝试增加训练数据的数量。
3.数据不平衡:如果您的数据存在不平衡,例如正样本和负样本数量不均衡,模型可能偏向于预测更多的样本。您可以尝试采用技巧,如重采样或欠采样,以消除数据不平衡的影响。
4.不适当的激活函数:不适当的激活函数可能导致模型存在梯度消失或梯度爆炸问题。您可以尝试使用更适当的激活函数,例如ReLU或Leaky ReLU。
5.不合适的优化器:您可以尝试更换优化器,例如Adam或SGD,以提高模型的
从训练损失接近于0的情况看,你的模型可能过拟合了,因此在测试集上的表现就很差。
出现这种情况的原因可能是模型过于复杂,训练数据不足,或者是训练过程中出现了一些问题。
以下是可能的解决方案:
1、模型结构简单化:GRU 是一种相对复杂的 RNN 模型,可以尝试使用 LSTM 模型代替,或者是一些简单的模型,比如 MLP。
2、提供更多的训练数据:可以增加训练数据的量,或者是通过数据增强等方式增加数据的多样性。
3、增加正则化:可以尝试在模型中加入正则化项,比如 L1 或 L2 正则化,或者是使用 dropout 等方式减少过拟合的风险。
4、调整超参数:可以尝试调整学习率、batch_size 等超参数的值,或者是增加训练轮数等,以寻找更好的模型表现。
5、检查数据是否存在问题:可以检查数据是否存在异常值、缺失值等问题,以及是否有正确的标签和特征。此外,还可以尝试使用其他的数据预处理方法,比如 PCA 或 LDA。
6、检查代码是否存在问题:可以检查代码是否存在错误或逻辑错误,比如数据处理的问题或者是模型的实现问题。也可以使用其他的库或者框架来实现模型,比如 Keras 或 PyTorch。
可以根据具体情况逐一排查以上问题。同时,可以利用可视化工具来分析模型的训练过程和结果,以更好地理解模型的表现。
可能是模型欠拟合的原因,即模型没有足够的参数来拟合数据,导致训练过程损失几乎为0,但预测效果却很差。可以尝试增加模型的参数,比如增加隐层大小、增加GRU层数等,以提高模型的拟合能力。
这是一个使用 PyTorch 库的 Python 脚本,用于在股价数据上训练 GRU 模型。该脚本执行以下步骤:
1.使用 Pandas 库从.csv文件加载股票价格数据
2.使用 MinMaxScaler 规范化数据
3.将数据拆分为训练数据集和测试数据集
4.将数据转换为 PyTorch 张量
5.将训练和测试数据包装到 TensorDataset 对象中,以便在训练中使用
6.为训练和测试数据创建数据加载器对象,以便在训练中使用
7.在 PyTorch 中定义 GRU 模型
8.在训练数据上训练 GRU 模型
9.根据测试数据评估 GRU 模型
10.根据评估指标保存最佳模型
11.该脚本设置了多个超参数,例如时间步长、批量大小、特征大小、隐藏大小、输出大小、层数、周期数和学习率。可以调整这些超参数以提高模型的性能。
原因:
一个模型的损失值为0并不一定代表该模型预测效果良好。有很多因素会影响模型的预测效果,以下是一些常见原因:
1.过拟合:模型在训练集上的表现很好,但在测试集上的表现却很差,这说明模型在训练集上学习了噪声,而没有学习到真实模式。
2.数据不平衡:如果样本数量不平衡,比如说正样本比较少,那么模型很难学习到正样本的特征,从而导致预测效果差。
3.样本不足:如果样本数量过少,模型可能无法学习到足够的信息,从而导致预测效果差。
4.不合适的损失函数:如果使用了不适合当前问题的损失函数,模型可能无法得到期望的结果。
5.不合适的超参数:如果超参数设置不当,比如学习率过大或过小,模型可能无法收敛。
这些原因中的任何一个都可能导致模型损失值为0,但预测效果很差。因此,如果模型的预测效果很差,应该对模型进行诊断;
优化模型方法:
不知道你这个问题是否已经解决, 如果还没有解决的话:1.你可以把数据集划分为训练集,验证集和测试集,用不仅要在训练集上查看模型的损失值,也要看验证集上模型的损失值,验证集上模型的损失值低了,模型的泛化性才好。
2.向模型的成本函数添加正则项,以防止过拟合