LSTM预测汇率输出水平线问题排查求助
问题出在哪
- 输入特征完全搞错了:你用日期的数值化结果当LSTM的输入,这完全不符合时间序列预测的逻辑。汇率波动和日期的数字大小没关系,模型学不到任何有效规律,只能输出所有样本的均值,结果就是一条水平线。
- 时间序列数据集构造错误:LSTM做汇率预测,应该用前N天的汇率数据来预测当天的汇率,而不是拿日期当特征。你现在相当于让模型“看日期猜汇率”,这根本不合理。
- 模型和训练逻辑有问题:
- 第一层LSTM只给1个单元,模型容量太小,根本抓不住汇率的波动规律
- 连续用
return_sequences=True,导致输出维度和标签不匹配(你的输入是单时间步,return_sequences=True会让模型输出序列而非单个值) - 循环10000次每次训1个epoch,效率极低还容易训崩
怎么改
1. 重新构造时间序列数据集
核心是用历史汇率数据当输入,比如用前60天的收盘价预测第61天的收盘价:
import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense, LSTM from sklearn.preprocessing import MinMaxScaler # 下载数据 data = yf.download( tickers='EURUSD=X', start='2021-01-01', end='2023-01-01', interval='1d' ) # 只保留收盘价作为预测特征 df = data[['Adj Close']].copy() # 归一化(输入输出都要处理) scaler = MinMaxScaler(feature_range=(0,1)) scaled_data = scaler.fit_transform(df) # 构造时间序列样本:前60天数据 -> 第61天数据 time_steps = 60 X, y = [], [] for i in range(time_steps, len(scaled_data)): X.append(scaled_data[i-time_steps:i, 0]) y.append(scaled_data[i, 0]) # 转成LSTM需要的三维形状:(样本数, 时间步长, 特征数) X = np.array(X) X = np.reshape(X, (X.shape[0], X.shape[1], 1)) y = np.array(y)
2. 调整LSTM模型结构
给模型加够容量,修正输出维度问题:
model = Sequential() # 第一层LSTM,增加单元数,中间层return_sequences=True,最后一层设为False model.add(LSTM(50, return_sequences=True, input_shape=(X.shape[1], 1))) model.add(LSTM(50, return_sequences=False)) # 加全连接层提升拟合能力 model.add(Dense(25)) model.add(Dense(1)) # 编译模型,可自定义学习率 model.compile(optimizer='adam', loss='mean_squared_error')
3. 优化训练方式
别再循环单epoch训练了,直接批量训:
# 批量训练,batch_size和epochs按需调整 history = model.fit(X, y, batch_size=32, epochs=50) # 预测后反归一化,还原真实汇率值 predictions = model.predict(X) predictions = scaler.inverse_transform(predictions) actual = scaler.inverse_transform(y.reshape(-1,1)) # 可视化对比 plt.figure(figsize=(16,10)) plt.plot(df.index[time_steps:], actual, label='实际汇率') plt.plot(df.index[time_steps:], predictions, label='预测汇率', color='red') plt.xlabel('日期') plt.ylabel('EUR/USD汇率') plt.title('汇率预测与实际值对比') plt.legend() plt.grid(linestyle='--') plt.show()
额外提示
- 时间步长可以调整(比如30、60、90天),试试不同长度找最优效果
- 一定要划分训练集和测试集(比如前80%训,后20%测),不然容易过拟合
- 可以加Dropout层防过拟合:
from keras.layers import Dropout,在LSTM层后加model.add(Dropout(0.2)) - 学习率可以微调,比如用
Adam(learning_rate=0.001)控制训练速度
内容的提问来源于stack exchange,提问作者DuQer
相关产品推荐
相关产品推荐

