You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:20:54