LSTM多对一架构时间序列预测结果严重偏离问题求助
问题:LSTM多对一预测结果严重偏离实际值
用12个月的序列预测12个月的数据,采用many-to-one LSTM架构,输出12维向量。但预测结果与预期偏差极大:时间序列实际值约为0.96,预测值却仅在0.08-0.12区间内;即使将epochs增加到1000,预测最大值仍仅约为0.2。
生成72个随机值后,使用subsequences函数创建长度为12的重叠序列,X维度为[12时间步序列数量, 12, 1],代码实现如下:
from keras.models import Sequential from keras.layers import LSTM from keras.layers import Dense import numpy as np import pandas as pd def subsequences(ts, window): shape = (ts.size - window + 1, window) strides = ts.strides * 2 return np.lib.stride_tricks.as_strided(ts, shape=shape, strides=strides) test_arr = np.random.normal(0.975, 0.008, size=72) ts = 12 temp = subsequences(test_arr, ts) X = temp.reshape(temp.shape[0], temp.shape[1], 1) y = subsequences(pd.Series(test_arr).shift(-ts).to_numpy(), ts) X_predict = X[-ts, :, :] # Lop off the timestamps that have missing values X = X[:(X.shape[0] - ts - 1), :, :] y = y[:(y.shape[0] - ts - 1), :] output = 12 model = Sequential() model.add(LSTM(12, return_sequences=True, input_shape=(ts, 1))) model.add(LSTM(12)) model.add(Dense(output)) model.compile(loss='mae', optimizer='adam') model.summary() model.fit(X, y, batch_size = 24, epochs = 50) yhat = model.predict(X_predict, verbose=0)
部分预测结果如下:
array([[0.11727975, 0.08559777, 0.09116013, 0.09350648, 0.13221847, 0.08328149, 0.12618074, 0.12006135, 0.11579201, 0.10330589, 0.11863852, 0.13914064], [0.1172842 , 0.08561642, 0.091188 , 0.0935307 , 0.1322322 , 0.08330169, 0.12619175, 0.12007872, 0.11579723, 0.10331573, 0.11865252, 0.13916571], [0.11731011, 0.08572483, 0.09135018, 0.09367174, 0.13231221, 0.08341929, 0.12625587, 0.12017974, 0.1158275 , 0.10337301, 0.11873408, 0.13931161],
核心问题排查与修正方案
1. 标签y的生成逻辑错误
原代码中用shift(-ts)+subsequences生成y的逻辑完全错误:shift(-12)会让原数组最后12个值变为NaN,再用subsequences处理会生成包含无效值的序列,后续截断操作进一步打乱了X与y的对应关系,导致模型根本无法学习到正确的输入输出映射。
正确的y应该是每个X对应的未来12个连续值,直接通过切片生成即可:
# 替换原y的生成代码 y = np.array([test_arr[i+ts:i+ts+output] for i in range(len(X))])
2. 不必要的数据截断导致训练样本不足
原代码中X = X[:(X.shape[0] - ts - 1), :, :]和y = y[:(y.shape[0] - ts - 1), :]的截断操作完全多余,大幅减少了有效训练样本。正确的样本量应为len(test_arr) - ts - output + 1 = 72-12-12+1=49个。
3. 未做数据归一化
数据分布在0.96左右,属于连续值回归任务,但未做归一化处理,LSTM的输出范围难以匹配原始数据尺度,导致预测值被压缩到小区间。建议用MinMaxScaler将数据缩至0-1区间,训练后再反归一化得到真实值。
4. 训练参数不合理
- batch_size设为24,远大于有效样本量,导致每个epoch的参数更新次数极少,模型收敛缓慢,建议调小至8或16;
- 可加入早停(EarlyStopping)回调函数,防止模型过拟合,同时自动停止无效训练。
修正后的完整代码示例
from keras.models import Sequential from keras.layers import LSTM, Dense from keras.callbacks import EarlyStopping import numpy as np from sklearn.preprocessing import MinMaxScaler def create_sequences(data, input_len, output_len): X, y = [], [] # 确保每个X都有对应的完整y序列 for i in range(len(data) - input_len - output_len + 1): X.append(data[i:i+input_len]) y.append(data[i+input_len:i+input_len+output_len]) return np.array(X), np.array(y) # 生成原始数据 test_arr = np.random.normal(0.975, 0.008, size=72) # 数据归一化 scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(test_arr.reshape(-1, 1)) input_len = 12 output_len = 12 # 创建训练序列 X, y = create_sequences(scaled_data, input_len, output_len) # 调整X维度为[样本数, 时间步, 特征数] X = X.reshape(X.shape[0], X.shape[1], 1) # 构建模型 model = Sequential() model.add(LSTM(12, return_sequences=True, input_shape=(input_len, 1))) model.add(LSTM(12)) model.add(Dense(output_len)) model.compile(loss='mae', optimizer='adam') # 早停回调:验证集损失10轮不下降则停止,恢复最优权重 early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) # 划分训练/验证集 split = int(0.8 * len(X)) X_train, X_val = X[:split], X[split:] y_train, y_val = y[:split], y[split:] # 训练模型 model.fit(X_train, y_train, validation_data=(X_val, y_val), batch_size=8, epochs=500, callbacks=[early_stop]) # 准备预测用的输入序列(最后12个归一化后的数据) X_predict = scaled_data[-input_len:].reshape(1, input_len, 1) # 预测并反归一化得到真实值 yhat = model.predict(X_predict, verbose=0) yhat = scaler.inverse_transform(yhat).flatten() print(yhat)
内容的提问来源于stack exchange,提问作者matsuo_basho
相关产品推荐
相关产品推荐

