使用GridSearchCV调优Keras模型报错:未实现get_params方法
我编写了以下Python代码,尝试用scikit-learn的GridSearchCV对Keras Sequential模型进行超参数调优:
import numpy as np import tensorflow as tf from sklearn.preprocessing import minmax_scale from sklearn.model_selection import GridSearchCV, KFold # Extract the main and side frequency factors concentractions and catalyst concentrations from the data main_freq_factors = np.array(FreqFac['Main frequency factors concentraction (l/(mol*s))']) side_freq_factors = np.array(FreqFac['Side frequency factors concentraction (1/s)']) catalyst_conc = np.array(FreqFac.iloc[:,1].values) # Scale the data using the min-max scaler main_freq_factors_scaled = minmax_scale(main_freq_factors) side_freq_factors_scaled = minmax_scale(side_freq_factors) catalyst_conc_scaled = minmax_scale(catalyst_conc) # Combine the scaled data into a single array X = catalyst_conc_scaled y = np.column_stack((main_freq_factors_scaled, side_freq_factors_scaled)) X_train, X_test, y_train, y_test = train_test_split(Xsc, Ysc, test_size=0.33, random_state=42) # Define the model model = tf.keras.Sequential() model.add(tf.keras.layers.Dense(32, activation='relu', input_shape=(1,))) model.add(tf.keras.layers.Dense(1, activation='linear')) # Compile the model with the mean squared error loss function and Adam optimization algorithm model.compile(loss='mean_squared_error', optimizer='adam') # Define the grid of hyperparameters to search param_grid = { 'epochs': [50, 100, 150], 'batch_size': [32, 64, 128] } # Create a K-fold cross-validation generator kfold = KFold(n_splits=5, shuffle=True, random_state=42) # Create a grid search object using the model, param_grid, and kfold grid_search = GridSearchCV(model, param_grid, cv=kfold, scoring='neg_mean_squared_error', return_train_score=True) # Fit the grid search object to the data grid_search.fit(catalyst_conc.reshape(-1, 1), main_freq_factors) # Print the results of the grid search print(grid_search.best_params_)
运行时出现如下错误:
Cannot clone object '<keras.engine.sequential.Sequential object at 0x7eff87f72580>' (type <class 'keras.engine.sequential.Sequential'>): it does not seem to be a scikit-learn estimator as it does not implement a 'get_params' methods.
请问我哪里操作出错了?
错误核心原因:Keras的Sequential模型本身不是scikit-learn兼容的estimator,它没有实现scikit-learn要求的get_params()和set_params()方法,导致GridSearchCV无法对其进行克隆和参数调优。
解决步骤如下:
导入兼容包装器
添加KerasRegressor导入(你的场景是回归任务,对应MSE损失):from tensorflow.keras.wrappers.scikit_learn import KerasRegressor将模型定义封装为函数
GridSearchCV需要每次调参时重新构建模型,因此必须把模型定义写成可调用函数:def build_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Dense(32, activation='relu', input_shape=(1,))) model.add(tf.keras.layers.Dense(1, activation='linear')) model.compile(loss='mean_squared_error', optimizer='adam') return model用KerasRegressor包装模型
将模型转换为scikit-learn兼容的estimator:model = KerasRegressor(build_fn=build_model, verbose=0)verbose=0用于屏蔽训练过程日志,方便聚焦GridSearch结果。修正代码中的变量不一致问题
原代码存在几处变量不匹配:- 定义了
X = catalyst_conc_scaled,但后续用Xsc做数据集划分,需统一为X和y fit时使用未缩放的catalyst_conc,建议改用已缩放的X保持数据一致性
- 定义了
修正后的完整代码
import numpy as np import tensorflow as tf from sklearn.preprocessing import minmax_scale from sklearn.model_selection import GridSearchCV, KFold, train_test_split from tensorflow.keras.wrappers.scikit_learn import KerasRegressor # 提取数据 main_freq_factors = np.array(FreqFac['Main frequency factors concentraction (l/(mol*s))']) side_freq_factors = np.array(FreqFac['Side frequency factors concentraction (1/s)']) catalyst_conc = np.array(FreqFac.iloc[:,1].values) # 数据缩放 main_freq_factors_scaled = minmax_scale(main_freq_factors) side_freq_factors_scaled = minmax_scale(side_freq_factors) catalyst_conc_scaled = minmax_scale(catalyst_conc) # 组合特征与标签(若需多输出预测,将y改为二维数组,模型输出层改为Dense(2)) X = catalyst_conc_scaled y = main_freq_factors_scaled # 划分数据集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42) # 定义模型构建函数 def build_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Dense(32, activation='relu', input_shape=(1,))) model.add(tf.keras.layers.Dense(1, activation='linear')) model.compile(loss='mean_squared_error', optimizer='adam') return model # 包装模型为scikit-learn兼容estimator model = KerasRegressor(build_fn=build_model, verbose=0) # 超参数网格 param_grid = { 'epochs': [50, 100, 150], 'batch_size': [32, 64, 128] } # K折交叉验证生成器 kfold = KFold(n_splits=5, shuffle=True, random_state=42) # 构建GridSearchCV grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=kfold, scoring='neg_mean_squared_error', return_train_score=True) # 拟合数据 grid_search.fit(X.reshape(-1, 1), y) # 输出最佳参数 print(grid_search.best_params_)
补充说明:如果你的任务是多输出回归(同时预测主、副频率因子),需要将模型输出层改为Dense(2),并将y设置为np.column_stack((main_freq_factors_scaled, side_freq_factors_scaled)),保证模型输出与标签维度匹配。
内容的提问来源于stack exchange,提问作者Tom Duym

