LSTM多对多模型交叉验证遇3D数组MSE报错,求解决方案
问题解决:LSTM多对多模型交叉验证中的3D数组适配及代码修正
核心问题有两个:一是sklearn的mean_squared_error不支持3D数组输入,二是你的交叉验证代码逻辑错误,未正确使用KFold划分的索引。
1. 3D数组导致MSE计算报错的解决
你的y_train1和y_test1形状为(N,1,9),而模型最后一层Dense(y_train1.shape[2])输出的是(N,9),两者维度不匹配,同时sklearn的metrics仅支持≤2D的输入。有两种解决方式:
- 调整目标变量维度:直接去掉y中多余的中间维度,使其与模型输出一致:
y_train1 = y_train1.reshape(-1, 9) y_test1 = y_test1.reshape(-1, 9) - 保留3D形状时转换计算:如果需要保留原维度,可临时将数组reshape为2D后计算MSE:
score = np.sqrt(metrics.mean_squared_error(pred.reshape(-1,9), y_test.reshape(-1,9)))
2. 交叉验证逻辑的修正
你的代码未使用KFold生成的train/test索引,等于每个fold都在训练完整训练集、测试完整测试集,这不是真正的交叉验证。正确做法是在训练集内部划分验证fold,测试集留到最后做最终评估:
修正后的完整代码
from sklearn.model_selection import KFold from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from sklearn import metrics import numpy as np import pandas as pd # 调整目标变量维度,适配模型输出和sklearn metrics y_train1 = y_train1.reshape(-1, 9) y_test1 = y_test1.reshape(-1, 9) # 初始化KFold交叉验证 kf = KFold(n_splits=5, shuffle=True, random_state=42) oos_y = [] oos_pred = [] fold = 0 for train_idx, val_idx in kf.split(X_train1): fold += 1 print(f"Fold #{fold}") # 使用KFold索引划分训练/验证子集 x_train, x_val = X_train1[train_idx], X_train1[val_idx] y_train, y_val = y_train1[train_idx], y_train1[val_idx] # 构建模型 model = Sequential() model.add(LSTM(128, activation='relu', input_shape=(X_train1.shape[1], X_train1.shape[2]), return_sequences=True)) model.add(LSTM(64, activation='relu', return_sequences=False)) model.add(Dropout(0.2)) model.add(Dense(y_train1.shape[1])) # 现在y是(样本数,9),shape[1]对应特征数9 model.compile(optimizer='adam', loss='mse', metrics=['mae']) model.summary() # 训练模型,用验证子集做验证 history = model.fit(x_train, y_train, epochs=1, batch_size=16, validation_data=(x_val, y_val), verbose=1) # 验证集预测 pred = model.predict(x_val) oos_y.append(y_val) oos_pred.append(pred) # 计算当前fold的RMSE score = np.sqrt(metrics.mean_squared_error(pred, y_val)) print(f"Fold score (RMSE): {score}") # 计算交叉验证整体RMSE oos_y = np.concatenate(oos_y) oos_pred = np.concatenate(oos_pred) cv_score = np.sqrt(metrics.mean_squared_error(oos_pred, oos_y)) print(f"Cross-Validation Average RMSE: {cv_score}") # 最终用测试集评估模型 test_pred = model.predict(X_test1) test_score = np.sqrt(metrics.mean_squared_error(test_pred, y_test1)) print(f"Test Set RMSE: {test_score}") # 保存结果(按需启用) # oos_y_df = pd.DataFrame(oos_y) # oos_pred_df = pd.DataFrame(oos_pred) # oosDF = pd.concat([df, oos_y_df, oos_pred_df], axis=1) # oosDF.to_csv(filename_write, index=False)
总结
不需要手动编写交叉验证函数,只需完成两步:
- 调整目标变量维度,使其匹配模型输出并满足sklearn metrics的输入要求;
- 正确使用KFold生成的索引划分训练/验证子集,实现真正的交叉验证。
内容的提问来源于stack exchange,提问作者Tan
相关产品推荐
相关产品推荐

