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

LSTM时序预测模型准确率低、RMSE高 增加Epoch无效如何优化

LSTM时序预测模型准确率低、训练停滞问题修复方案

你的模型存在多个逻辑错误和结构设计问题,按优先级调整如下:

核心问题排查与修复

1. 修正基础逻辑错误

  • 首先删除metrics=['accuracy']:这是分类任务专属指标,回归任务用MSE/RMSE/MAE评估即可,该指标对你的任务完全无参考价值,是你误以为“准确率极低”的核心原因之一。
  • 修复归一化数据泄露:你当前对全量数据集做归一化后再切分训练/测试集,会把测试集的数值分布信息泄露到训练过程,导致测试结果失真。正确做法是仅用训练集拟合归一化器,再分别转换训练集、测试集。
  • 删除冗余代码:你在生成trainX/trainY后又重复生成了一遍Xdata_train/Ydata_train,属于无意义冗余,直接用前面生成的训练集即可。

2. 调整模型结构与激活函数

当前模型结构存在梯度消失、正则化位置错误问题:

  • 去掉最后一层LSTM的sigmoid激活,换成relu即可:sigmoid输出范围狭窄,多层网络叠加后很容易出现梯度饱和,导致模型学不动,这也是你增加epoch效果无变化的核心原因之一。
  • Dropout层不要放在全连接层之后,在两层LSTM之间插入Dropout做正则化,防止过拟合,Dropout率设0.1-0.2即可,不要太高。
  • 删除冗余全连接层:两层50单元的全连接层对于单变量时序预测容量过剩,容易过拟合且收敛慢,LSTM输出后接1层小维度全连接即可。
  • 削减LSTM层数:三层50单元LSTM对于单特征时序预测来说参数过多,很容易卡在局部最优,保留2层LSTM足够。

3. 修正训练超参数

  • 把batch_size=1改成32或者64:单样本在线学习梯度波动极大,模型会在局部最优点反复震荡,根本没法持续收敛。
  • 学习率不要一开始就设1e-4这么小,先用Adam默认的1e-3训练,观察loss下降情况,如果后期震荡再调低学习率,配合学习率衰减策略效果更好。
  • epochs不用手动设固定值,加早停回调EarlyStopping,监控验证集loss,连续5轮不下降就停止训练,避免无效训练。
  • 时序任务必须保持shuffle=False,这点你写的是对的,不用修改。

4. 优化数据与窗口设置

  • 从你提供的序列可视化结果看,数据存在明显的趋势性/周期性,属于非平稳序列,直接喂原始值LSTM很难学到规律:可以先做一阶差分去掉趋势,或者加入时间特征(比如周期位置编码、滑动平均统计特征)作为多特征输入,不要只用单变量原始值。
  • look_back=15的窗口需要匹配数据周期:如果你的数据是按天采样,周期为7天/30天,15的窗口覆盖不了完整周期,模型学不到周期规律,可以做窗口大小的网格搜索,选验证集loss最低的窗口值。

修正后的参考代码

import numpy as np
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

# 1. 先切分数据集再做归一化,避免数据泄露
train_size = int(len(df) * 0.8)
train_df = df.iloc[:train_size, :]
test_df = df.iloc[train_size:, :]

scaler = MinMaxScaler(feature_range=(0, 1))
# 仅用训练集拟合scaler
train_scaled = scaler.fit_transform(train_df)
test_scaled = scaler.transform(test_df)

def create_dataset(dataset, look_back=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset[i:(i+look_back), 0]
        dataX.append(a)
        dataY.append(dataset[i + look_back, 0])
    return np.array(dataX), np.array(dataY)

look_back = 15 # 可根据数据周期调整,比如尝试7/14/30
trainX, trainY = create_dataset(train_scaled, look_back)
testX, testY = create_dataset(test_scaled, look_back)

#  reshape输入为[样本数, 时间步, 特征数]
trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
testX = np.reshape(testX, (testX.shape[0], testX.shape[1], 1))

# 2. 重构模型
model = Sequential()
model.add(LSTM(32, activation='relu', return_sequences=True, input_shape=(look_back, 1)))
model.add(Dropout(0.1))
model.add(LSTM(32, activation='relu', return_sequences=False))
model.add(Dropout(0.1))
model.add(Dense(16, activation='relu'))
model.add(Dense(1)) # 回归输出层用默认线性激活,无需额外加激活函数

# 3. 编译模型,回归任务不要加accuracy指标
model.compile(optimizer='adam', loss='mean_squared_error')

# 加训练回调:早停+学习率自动衰减
callbacks = [
    EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True),
    ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-5)
]

# 4. 训练,从训练集拆分10%作为时序验证集
history = model.fit(
    trainX, trainY,
    batch_size=32,
    epochs=100,
    validation_split=0.1, # shuffle=False时自动取训练集最后10%做验证,符合时序要求
    shuffle=False,
    callbacks=callbacks
)

# 预测后必须做逆归一化还原到原始尺度,再计算RMSE才有意义
train_pred = scaler.inverse_transform(model.predict(trainX))
test_pred = scaler.inverse_transform(model.predict(testX))
trainY_real = scaler.inverse_transform(trainY.reshape(-1,1))
testY_real = scaler.inverse_transform(testY.reshape(-1,1))

额外注意点

  • 计算RMSE的时候必须把预测值和真实值做逆归一化还原到原始尺度,你之前算的RMSE=35如果是归一化后的值完全没有参考意义。
  • 如果调整后模型效果还是不好,可以尝试把LSTM换成双向LSTM,或者加入注意力机制,优先把前面的基础逻辑错误改完再调试复杂结构。

内容的提问来源于stack exchange,提问作者user17091916

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:03:50