PyTorch LSTM回归:应选取最后输出值还是全部输出值?
LSTM回归模型两种输出方案的选择建议
我正基于1850年1月以来的月度全球平均气温数据,训练首个LSTM回归模型。我采用输入连续12个月数据预测下一个月的方式,训练数据为除最后30年外的所有序列。最初仅将LSTM的最后输出传入全连接层,模型收敛效果不佳;改为传入LSTM的全部输出(维度为12×hidden_size)后,效果明显提升。但第二种方案无法处理可变长度序列,不过我本就无需使用可变长度序列。请问哪种方案更优?
结论:选择使用LSTM全部输出的方案更优
核心原因:
- 任务适配性:你的任务是固定12个月序列预测下一个月气温,属于固定长度序列的单步回归任务。LSTM的每一步隐藏状态都包含了对应时刻的时序上下文信息,使用全部输出能让模型充分捕捉气温的月度周期性、长期趋势等细节,这也是你实验中效果提升的关键。而仅用最后一步输出,相当于丢弃了前11个月的有效信息,对于具有强周期性的气温数据来说,信息缺失直接导致收敛效果差。
- 可变长度限制无影响:你明确不需要处理可变长度序列,因此第二种方案的这个“局限性”对你的场景完全不构成问题。固定序列长度反而能让全连接层输入维度稳定,模型结构更简单,训练效率更高。
额外优化建议:
- 调整全连接层结构:在全连接层中加入
nn.Dropout(0.2)层,防止模型过拟合气温数据中的噪声。 - 降低学习率:当前Adam优化器的
lr=0.01偏大,建议尝试0.001或更小的学习率,避免训练过程中损失震荡。 - 增加训练轮次:代码中仅训练2轮远不足以让LSTM收敛,建议增加到50-100轮,并加入早停机制,当验证集损失不再下降时停止训练。
- 数据预处理:先填充气温数据中的缺失值(如滚动均值填充),再进行标准化(Z-score归一化),能显著提升模型收敛速度和预测精度。
原始实验代码
import torch import torch.nn as nn import numpy as np import pandas as pd import matplotlib.pyplot as plt from torch.utils.data import DataLoader, Dataset class LSTMDataset( Dataset ): def __init__( self, x, y ): self.x = x self.y = y def __len__(self): return len( self.y ) def __getitem__(self, idx): sample, label = self.x[ idx ], self.y[ idx ] return sample.reshape( ( -1, 1 ) ), label.reshape( ( 1 ) ) class LSTMNet( nn.Module ): def __init__( self ): super().__init__() self.hidden_size = 24 self.lstm = nn.LSTM( input_size=1, hidden_size=self.hidden_size, num_layers=1, batch_first=True ) self.net = nn.Sequential( nn.Flatten(), nn.Linear( self.hidden_size * 12, self.hidden_size * 12 ), nn.ReLU(), nn.Linear( self.hidden_size * 12, 1 ) # 12 is the fixed sequence length (12 months of temperature data) ) def forward(self, x): x, _ = self.lstm( x ) # or x[ :, -1, : ] - which one is preferred? x = self.net( x ) return x df = pd.read_csv( "globalTemperatures.csv" ) df = df[ [ "dt", "LandAverageTemperature" ] ] df[ "dt" ] = pd.to_datetime( df[ "dt" ], format="%Y-%m-%d" ) forecastMonths = 12 * 30 # forecast 30 years sequenceLength = 12 # 12 months are fed into LSTM one after another trainX = [] trainY = [] testX = [] testY = [] for i in range( len( df ) - sequenceLength ): x = np.array( df[ "LandAverageTemperature" ].iloc[ i : i + sequenceLength ] ).astype( np.float32 ) y = np.array( df[ "LandAverageTemperature" ].iloc[ i + sequenceLength ] ).astype( np.float32 ) if i + sequenceLength >= ( len( df ) - forecastMonths ): testX.append( x ) testY.append( y ) else: trainX.append( x ) trainY.append( y ) trainingSet = LSTMDataset( trainX, trainY ) testSet = LSTMDataset( testX, testY ) training_loader = DataLoader( trainingSet, batch_size=1, shuffle=True ) test_loader = DataLoader( testSet, batch_size=1, shuffle=False ) model = LSTMNet() optimizer = torch.optim.Adam( model.parameters(), lr=0.01 ) loss_fn = torch.nn.MSELoss() accuracies = [] epochs = 2 for epoch in range( epochs ): losses = [] for i, data in enumerate( training_loader ): inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = loss_fn(outputs, labels) loss.backward() optimizer.step() losses.append( loss.item() ) print( f"Epoch [{epoch + 1}/{epochs}] Loss: {np.mean( losses ):.2f}" ) predictedTemperatures = [] model.eval() for i, data in enumerate( test_loader ): inputs, labels = data output = model( inputs ) loss = loss_fn(outputs, labels) losses.append( loss.item() ) predictedTemperatures.append( output.item() ) print( f"Test Loss: {np.mean( losses ):.2f}" ) plt.figure( figsize=(18, 2) ) plt.plot( df[ "dt" ], df[ "LandAverageTemperature" ], label="True Temperatures" ) plt.plot( df[ "dt" ].iloc[ -forecastMonths : ], predictedTemperatures, label="Predicted Temperatures" ) plt.savefig( "temperatures.png" )
内容的提问来源于stack exchange,提问作者binaryBigInt
相关产品推荐
相关产品推荐

