从keras.wrappers.sci-learn迁移到Scikeras的技术求助
从Keras Wrappers迁移到Scikeras的实操方案
关键迁移步骤
- 安装Scikeras:
pip install scikeras - 替换导入:使用
scikeras.wrappers.KerasRegressor替代旧版Keras wrapper - 参数命名规则:GridSearchCV的参数网格需给模型参数加上
model__前缀 - 模型定义优化:避免硬编码训练集形状,让模型更通用
修改后的完整代码
import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense from tensorflow.keras.optimizers import SGD from tensorflow.keras.regularizers import L2 from sklearn.model_selection import TimeSeriesSplit, GridSearchCV from sklearn.metrics import r2_score import numpy as np import matplotlib.pyplot as plt # 模型构建函数:参数保持与原定义一致 def create_model(lstm_1, lstm_2, dense, input_shape): model = Sequential() model.add(LSTM(lstm_1, input_shape=input_shape, return_sequences=True)) model.add(LSTM(lstm_2)) model.add(Dense(dense, activation='linear')) model.add(Dense(1, activation='linear')) model.compile(optimizer='adam', loss='mean_squared_error') return model # 定义参数网格:给每个模型参数加上model__前缀 param_grid = { 'model__lstm_1': [32, 64, 128], 'model__lstm_2': [32, 64, 128], 'model__dense': [16, 32, 64] } # 时间序列交叉验证拆分 tscv = TimeSeriesSplit(n_splits=5) # 用Scikeras的KerasRegressor包装模型 # 传入固定参数input_shape,可调参数通过GridSearchCV传递 estimator = tf.keras.wrappers.scikit_learn.KerasRegressor( build_fn=create_model, input_shape=(X_train.shape[1], X_train.shape[2]), verbose=0 ) # 网格搜索:使用包装后的estimator grid = GridSearchCV(estimator=estimator, param_grid=param_grid, cv=tscv, n_jobs=-1) grid_result = grid.fit(X_train, y_train) print("最优参数: ", grid_result.best_params_) # 获取最优模型(与原代码逻辑一致) best_model = grid_result.best_estimator_.model # 预测与评估 NN_predictions = best_model.predict(X_test) NN_mse = np.mean((y_test - NN_predictions.flatten()) ** 2) NN_rmse = np.sqrt(NN_mse) print("神经网络模型RMSE: ", NN_rmse) NN_r_squared = r2_score(y_test, NN_predictions) n = len(y_test) p = 8 NN_adjusted_r_squared = 1 - (1 - NN_r_squared) * (n - 1) / (n - p - 1) print('OOS R²: ', NN_r_squared) print('OOS 调整后R²: ', NN_adjusted_r_squared) # 可视化 plt.figure(figsize=(12, 6)) plt.plot(y_test, label='隐含波动率') plt.plot(NN_predictions, label='神经网络预测') plt.xlabel('日期索引') plt.ylabel('隐含波动率') plt.title('实际值 vs 预测值') plt.legend() plt.show() # 带正则化的模型训练 LSTM1 = grid_result.best_params_['model__lstm_1'] LSTM2 = grid_result.best_params_['model__lstm_2'] DENSE = grid_result.best_params_['model__dense'] K = 1 # 原代码中K未定义,这里补充为1(与输出层一致) N_epochs = 50 # 原代码中未定义,需根据实际情况设置 N_batch_size = 32 # 原代码中未定义,需根据实际情况设置 model_REG = Sequential([ LSTM(LSTM1, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, kernel_regularizer=L2(0.001)), LSTM(LSTM2), Dense(DENSE, activation='linear'), Dense(K, activation='linear') ]) model_REG.compile(optimizer='adam', loss='mean_squared_error') history_REG = model_REG.fit(X_train, y_train, epochs=N_epochs, batch_size=N_batch_size, validation_data=(X_test, y_test)) # 正则化模型评估 NN_REG_predictions = model_REG.predict(X_test) NN_REG_mse = np.mean((y_test - NN_REG_predictions.flatten()) ** 2) NN_REG_rmse = np.sqrt(NN_REG_mse) print("带正则化的神经网络模型RMSE: ", NN_REG_rmse) NN_r_squared = r2_score(y_test, NN_REG_predictions) NN_adjusted_r_squared = 1 - (1 - NN_r_squared) * (n - 1) / (n - p - 1) print('OOS R²: ', NN_r_squared) print('OOS 调整后R²: ', NN_adjusted_r_squared) # 可视化 plt.figure(figsize=(12, 6)) plt.plot(y_test, label='隐含波动率') plt.plot(NN_REG_predictions, label='正则化神经网络预测') plt.xlabel('日期索引') plt.ylabel('隐含波动率') plt.title('实际值 vs 预测值(正则化模型)') plt.legend() plt.show()
关键说明
- 参数前缀:Scikeras通过
model__前缀区分模型参数与wrapper自身参数(如epochs、batch_size),因此参数网格必须添加该前缀 - 模型包装:使用
KerasRegressor(回归任务)或KerasClassifier(分类任务)包装模型构建函数,固定参数(如input_shape)直接传入wrapper,可调参数通过GridSearchCV传递 - 未定义变量处理:原代码中
K、N_epochs、N_batch_size未定义,已补充默认值,需根据你的数据集调整 - 冗余代码清理:原代码中
TwoLayerFeedForward类与当前任务无关,已移除
内容的提问来源于stack exchange,提问作者Guesse
相关产品推荐
相关产品推荐

