PyTorch基础数据训练损失过大预测异常问题求助
解决LSTM时间序列预测中损失值过大、预测偏差的问题
核心问题分析与解决步骤
1. 数据集逻辑错误:X与y完全一致
你的代码中X和y使用了完全相同的当前年份月度数据,相当于让模型"预测和输入一模一样的值",这和你"预测下一年数据"的目标完全背离。模型根本没有学习到"从历史到未来"的映射关系。
解决方法:
重新构建数据集:
- 每个样本的
X是历史年份的月度数据,y是对应下一年的月度数据 - 如果只有单年数据,可调整任务为"用前N个月数据预测后(12-N)个月数据",比如用前6个月预测后6个月
2. 数据未做归一化处理
你的数据中存在0、10000、120000这类跨度极大的数值,MSE损失会因大数值被放大到百万级别,同时LSTM对数据尺度极度敏感,未归一化会导致模型难以收敛。
解决方法:
使用sklearn的归一化工具将数据缩放到0-1区间,预测后再反归一化得到真实值:
from sklearn.preprocessing import MinMaxScaler # 初始化归一化器 scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(df.drop(['ProjectId', 'Year'], axis=1)) # 后续X、y均使用scaled_data构建,预测后反归一化: # forecast_values = scaler.inverse_transform(forecast.numpy())[0]
3. LSTM输入维度误用
LSTM的标准输入格式是[batch_size, sequence_length, input_size],其中:
sequence_length:时间序列的步数(比如历史12个月就是12步)input_size:每个时间步的特征数(单变量预测则为1)
你的代码将每个项目的12个月数据作为特征(input_size=12),而非时间序列步数,完全违背了LSTM处理序列数据的逻辑。
解决方法:
调整输入维度,将月度数据转换为时间序列格式。例如单变量预测场景:
# 假设scaled_data是形状为(n_samples, 12)的数组,每个样本是12个月的数据 # 转换为LSTM需要的序列格式:(n_samples, sequence_length=12, input_size=1) X = scaled_data.reshape(scaled_data.shape[0], 12, 1)
4. 训练数据量严重不足
你仅使用2个训练样本,模型无法学习到任何有效的时间序列规律,最终只能输出随机值。
解决方法:
- 收集更多项目的多年历史数据
- 若数据有限,考虑使用更简单的模型(如线性回归、MLP),或采用滑动窗口法生成更多样本(比如从长序列中截取多个子序列作为训练样本)
5. 模型结构与任务不匹配
当前模型取LSTM最后一个时间步的输出预测12个月,这种结构更适合单步预测。如果要预测未来12个月的序列,可调整为:
- 使用Seq2Seq结构(编码器-解码器)
- 让全连接层输出12个值对应12个月(需确保输入序列包含足够的历史信息)
修改后的示例代码片段
import torch import torch.nn as nn import torch.optim as optim import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler # 模拟多年份数据(示例) data = { 'ProjectId': ['P1', 'P1', 'P2', 'P2'], 'Year': ['2022/2023', '2023/2024', '2022/2023', '2023/2024'], 'July': [0, 0, 0, 0], 'August': [0, 0, 0, 0], 'September': [0, 0, 0, 0], 'October': [0, 0, 0, 0], 'November': [0, 0, 0, 0], 'December': [8000, 10000, 4000, 5000], 'January': [0, 0, 0, 0], 'February': [0, 0, 0, 0], 'March': [0, 0, 0, 0], 'April': [0, 0, 0, 0], 'May': [0, 0, 0, 0], 'June': [0, 120000, 0, 0] } df = pd.DataFrame(data) # 归一化数据 scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(df.drop(['ProjectId', 'Year'], axis=1)) # 构建数据集:用2022/2023的数据(X)预测2023/2024的数据(y) X = scaled_data[::2] # 取奇数行(2022/2023) y = scaled_data[1::2] # 取偶数行(2023/2024) # 转换为LSTM输入格式:[batch_size, seq_len=12, input_size=1] X_train = torch.tensor(X.reshape(X.shape[0], 12, 1), dtype=torch.float32) y_train = torch.tensor(y, dtype=torch.float32) # 定义适配的LSTM模型 class LSTMForecast(nn.Module): def __init__(self, input_size, hidden_size, output_size): super().__init__() self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): lstm_out, _ = self.lstm(x) # 用最后一个时间步的隐藏状态预测12个月 out = self.fc(lstm_out[:, -1, :]) return out # 初始化组件 input_size = 1 hidden_size = 32 output_size = 12 model = LSTMForecast(input_size, hidden_size, output_size) criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 训练 num_epochs = 500 for epoch in range(num_epochs): optimizer.zero_grad() outputs = model(X_train) loss = criterion(outputs, y_train) loss.backward() optimizer.step() if (epoch+1) % 50 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.6f}') # 预测示例 model.eval() with torch.no_grad(): # 用P2的2022/2023数据预测2023/2024 test_input = torch.tensor(scaled_data[2].reshape(1, 12, 1), dtype=torch.float32) forecast = model(test_input) # 反归一化得到真实值 forecast_values = scaler.inverse_transform(forecast.numpy())[0] print(f'Predicted values for each month of next year: {forecast_values.round(2).tolist()}')
内容的提问来源于stack exchange,提问作者user
相关产品推荐
相关产品推荐

