基于GridSearchCV的LSTM模型训练异常:损失高精度低求助
LSTM模型训练异常:损失极高、精度极低问题排查
问题背景
尝试使用GridSearchCV构建LSTM深度神经网络模型,但训练后模型损失值极高、精度值极低,无法定位问题根源。
代码重现
import numpy as np import pandas as pd import matplotlib.pyplot as plt import tensorflow as tf from sklearn.preprocessing import MinMaxScaler from sklearn.metrics import r2_score, median_absolute_error, mean_absolute_error, mean_absolute_percentage_error, mean_squared_error from keras.layers import Dense,Dropout,LSTM, LayerNormalization from keras.models import Sequential from datetime import datetime # from scikeras.wrappers import KerasClassifier, KerasRegressor from keras.wrappers.scikit_learn import KerasClassifier from sklearn.model_selection import GridSearchCV from sklearn.model_selection import RandomizedSearchCV from sklearn.model_selection import train_test_split import seaborn as sb df = pd.read_excel('izmir_saatlik_tuketim_verisi.xlsx', sheet_name='Veri (2)') time_index = pd.date_range(start='2017-01-01 00:00', periods=len(df), freq='H') time_index = pd.DatetimeIndex(time_index) df['time']=time_index df['hour']= df['time'].dt.hour df['week']= df['time'].dt.week df['dayofweek']= df['time'].dt.dayofweek df['dayofyear']= df['time'].dt.dayofyear df['month']= df['time'].dt.month df['Unnamed: 0']=df['time'] df.rename(columns ={'Unnamed: 0':'Time'},inplace=True) df.drop(['time'], axis=1, inplace=True) df['Nispi_Nem(%)'].fillna(df['Nispi_Nem(%)'].median(), inplace=True) X=df.iloc[:,2:9].values y=df.iloc[:,1].values X_train, X_test, y_train, y_test=train_test_split(X,y, test_size=0.1, random_state=0) #---------------------------Normalize of data---------------------- scaler=MinMaxScaler() X_train=scaler.fit_transform(X_train) X_test=scaler.fit_transform(X_test) y_train=scaler.fit_transform(y_train.reshape(-1,1)) y_test=scaler.fit_transform(y_test.reshape(-1,1)) X_train = X_train.reshape((X_train.shape[0], 1, X_train.shape[1])) X_test = X_test.reshape((X_test.shape[0], 1, X_test.shape[1])) #-------------------------------Built in model------------------------- param_grid = {'batch_size' : [50,100,250], # 'activation':['tanh','sigmoid','relu'], # 'optimizer':['adam','rmsprop','adagrad'], 'epochs' : [20,50,100], # 'units':[16,32,64,128,256] } Dropout_rate=0.5 def create_model(units=16, optimizer='adam'): lstm_model = Sequential() lstm_model.add(LSTM(units=units,activation='tanh',return_sequences=True, input_shape=(X_train.shape[1], X_train.shape[2]))) lstm_model.add(LSTM(units=units,activation='tanh',return_sequences=False)) lstm_model.add(Dense(1, activation='Softmax')) lstm_model.compile(optimizer=optimizer,loss="mae", metrics=["acc"]) return lstm_model tf.random.set_seed(111) #-------------------------Hyperparamaters Optimization------------------------ model = KerasClassifier(build_fn=create_model, verbose=1) grid = GridSearchCV(estimator=model, param_grid=param_grid, cv = 2, verbose=0) grid_result=grid.fit(X_train, y_train) print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
核心问题与修正方案
1. 任务类型混淆(关键错误)
- 问题:当前是回归任务(预测连续值,如电力消耗),但误用了
KerasClassifier(分类任务专用),同时搭配分类指标acc,导致模型优化方向完全错误,精度计算无意义。 - 修正:
- 取消注释
from scikeras.wrappers import KerasRegressor,替换KerasClassifier为KerasRegressor。 - 编译模型时,将
metrics=["acc"]改为回归适用指标,比如metrics=["mse"],后续评估用r2_score、mean_absolute_error等回归指标。
- 取消注释
2. 输出层激活函数错误(关键错误)
- 问题:回归任务最后一层使用
Softmax激活,该函数用于多分类任务的概率归一化,完全不符合回归输出连续值的需求。 - 修正:将输出层改为线性激活(默认即为线性,可省略激活参数):
lstm_model.add(Dense(1)) # 等价于 activation='linear'
3. 数据归一化流程错误
- 问题:测试集使用
fit_transform会重新计算归一化参数,导致训练/测试集数据分布不一致,模型无法正确泛化。 - 修正:仅在训练集上拟合归一化器,测试集直接复用训练集的归一化参数:
# 特征归一化 scaler_X = MinMaxScaler() X_train = scaler_X.fit_transform(X_train) X_test = scaler_X.transform(X_test) # 目标值归一化 scaler_y = MinMaxScaler() y_train = scaler_y.fit_transform(y_train.reshape(-1,1)) y_test = scaler_y.transform(y_test.reshape(-1,1))
4. 时间序列数据拆分错误
- 问题:
train_test_split随机划分数据集,破坏了时间序列的时序性,LSTM无法学习到时间依赖关系。 - 修正:按时间顺序划分训练/测试集,比如取前90%数据训练,后10%测试:
split_idx = int(len(df) * 0.9) X_train, X_test = X[:split_idx], X[split_idx:] y_train, y_test = y[:split_idx], y[split_idx:]
5. LSTM输入结构未发挥时序特性
- 问题:将数据reshape为
(样本数, 1, 特征数),每个样本仅含1个时间步,LSTM的时序建模能力完全无法体现。 - 修正:构造多步时序输入,比如用过去24小时的数据预测当前值:
def create_time_sequences(X, y, seq_len): X_seq, y_seq = [], [] for i in range(len(X) - seq_len): X_seq.append(X[i:i+seq_len]) y_seq.append(y[i+seq_len]) return np.array(X_seq), np.array(y_seq) # 使用过去24小时的数据作为输入 seq_length = 24 X_train_seq, y_train_seq = create_time_sequences(X_train, y_train, seq_length) X_test_seq, y_test_seq = create_time_sequences(X_test, y_test, seq_length) # 此时输入形状为 (样本数, seq_length, 特征数),符合LSTM时序输入要求
6. 未使用定义的Dropout层
- 问题:代码定义了
Dropout_rate=0.5但未添加Dropout层,后续优化时可能出现过拟合。 - 修正:在LSTM层后添加Dropout层:
def create_model(units=16, optimizer='adam'): lstm_model = Sequential() lstm_model.add(LSTM(units=units,activation='tanh',return_sequences=True, input_shape=(X_train_seq.shape[1], X_train_seq.shape[2]))) lstm_model.add(Dropout(Dropout_rate)) lstm_model.add(LSTM(units=units,activation='tanh',return_sequences=False)) lstm_model.add(Dropout(Dropout_rate)) lstm_model.add(Dense(1)) lstm_model.compile(optimizer=optimizer,loss="mae", metrics=["mse"]) return lstm_model
内容的提问来源于stack exchange,提问作者Fatih BERBER
相关产品推荐
相关产品推荐

