使用GridSearchCV调优LSTM超参数时出现NaN精度问题求助
问题分析与代码修正
你的代码出现NaN精度值,主要是以下几个关键错误导致的,逐一修正如下:
1. 时间序列数据拆分错误
train_test_split会随机打乱数据,破坏时间序列的时序性,必须改用TimeSeriesSplit做时间序列的交叉验证,训练集拆分也要保持时序顺序,不能随机打乱。
2. LSTM输入形状不匹配
LSTM要求输入是三维数组:(样本数, 时间步长n_steps, 特征数n_features),但你当前的X_train是二维数组,需要先将数据转换成LSTM需要的时序格式。
3. 回归任务误用分类评分指标
你的任务是回归(预测连续值rn_val),但GridSearchCV里指定了分类任务的scoring="accuracy",这会导致评分计算错误,出现NaN。应该用回归类评分指标,比如'neg_mean_squared_error'(sklearn中回归指标常用负值,因为默认规则是分数越高模型越好)。
4. 目标变量未归一化
输入数据做了MinMaxScaler归一化,但目标变量target还是原始尺度,和输入尺度不匹配,容易导致训练不稳定,出现NaN或梯度爆炸。需要对目标变量也做归一化,后续预测时再反转换回原始尺度。
修正后的完整代码
import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import TimeSeriesSplit, GridSearchCV from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense from tensorflow.keras.wrappers.scikit_learn import KerasRegressor import warnings warnings.filterwarnings('ignore') # Load and preprocess the dataset data = pd.read_csv("dataset.csv") # 替换为实际路径 target_col = 'rn_val' # 分离特征和目标 features = data.drop(target_col, axis=1).values target = data[target_col].values.reshape(-1, 1) # 转成二维方便归一化 # 归一化特征和目标 scaler_features = MinMaxScaler() scaler_target = MinMaxScaler() features_normalized = scaler_features.fit_transform(features.astype(float)) target_normalized = scaler_target.fit_transform(target) # 将数据转换为LSTM需要的时序格式:(样本数, n_steps, n_features) def create_sequences(data, target, n_steps): X, y = [], [] for i in range(n_steps, len(data)): X.append(data[i-n_steps:i, :]) y.append(target[i, 0]) return np.array(X), np.array(y) n_steps = 7 # 时间步长 n_features = features_normalized.shape[1] X, y = create_sequences(features_normalized, target_normalized, n_steps) # 时间序列交叉验证策略 tscv = TimeSeriesSplit(n_splits=3) # 定义LSTM模型 def create_lstm_model(neurons, optimizer, activation): model = Sequential() model.add(LSTM(units=neurons, input_shape=(n_steps, n_features))) model.add(Dense(1, activation=activation)) model.compile(loss='mse', optimizer=optimizer) return model # 网格搜索参数 param_grid = { 'neurons': [8, 16, 32, 64], 'optimizer': ['RMSprop', 'Adam'], 'activation': ['relu', 'tanh', 'linear'] } # 包装Keras模型为sklearn兼容的回归器 model = KerasRegressor(build_fn=create_lstm_model, epochs=10, batch_size=16, verbose=0) # 初始化网格搜索:使用回归评分指标,时间序列交叉验证 grid = GridSearchCV( estimator=model, param_grid=param_grid, cv=tscv, refit=True, # 训练完成后用最佳参数重新训练整个数据集 scoring='neg_mean_squared_error', n_jobs=-1 ) # 执行网格搜索 grid_result = grid.fit(X, y) # 输出结果 print(f"最佳负MSE: {grid_result.best_score_:.4f} 使用参数: {grid_result.best_params_}") means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print(f"{mean:.4f} ({stdev:.4f}) 参数: {param}")
额外说明
- 时序数据转换函数
create_sequences:遍历数据,每次取前n_steps个时间步的特征作为输入,对应下一个时间步的目标值作为标签,这是时间序列预测的标准做法。 - 目标变量归一化后,后续预测时需要用
scaler_target.inverse_transform()将预测值转换回原始尺度。 - 减少了部分参数组合(比如去掉128神经元、SGD、swish等),可以加快网格搜索速度,你可以根据需求再加回来。
内容的提问来源于stack exchange,提问作者geethuth
相关产品推荐
相关产品推荐

