如何获取Keras GridSearchCV所有超参数组合的全轮次训练历史
获取Keras GridSearchCV中所有超参数组合的每轮训练历史
嘿,我完全懂你想要的——不只是GridSearchCV给出的平均得分,而是每个超参数组合在每一轮epoch的完整训练/验证准确率记录对吧?默认的GridSearchCV确实不会帮你保存这些细节,但我们可以通过自定义Keras分类器包装器来实现这个需求。
下面是具体的实现步骤,一步步来:
1. 自定义KerasClassifier子类,保存训练历史
首先,我们需要创建一个继承自KerasClassifier的子类,它会在每个折叠训练时自动保存该模型的训练历史:
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier import pandas as pd class HistoryTrackingKerasClassifier(KerasClassifier): def __init__(self, **kwargs): super().__init__(**kwargs) self.fold_histories = [] # 存储当前折叠的训练历史 def fit(self, X, y, **kwargs): # 调用父类的fit方法,获取训练历史 training_history = super().fit(X, y, **kwargs) # 将当前折叠的历史添加到列表中 self.fold_histories.append(training_history.history) return training_history
2. 定义模型构建函数与参数网格
接下来,你需要定义你的Keras模型构建函数(接受超参数作为输入),以及要搜索的参数网格:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense def build_keras_model(units=64, activation='relu'): model = Sequential() model.add(Dense(units, activation=activation, input_shape=(X_train.shape[1],))) model.add(Dense(1, activation='sigmoid')) # 假设是二分类任务 model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model # 定义要搜索的超参数网格 param_grid = { 'units': [32, 64, 128], 'activation': ['relu', 'tanh'], 'epochs': [10, 20] # 也可以把epochs作为超参数搜索 }
3. 运行GridSearchCV并收集所有历史数据
现在用我们自定义的分类器包装模型,运行网格搜索,然后从结果中提取每个超参数组合的所有折叠训练历史:
from sklearn.model_selection import GridSearchCV # 初始化自定义分类器 model = HistoryTrackingKerasClassifier(build_fn=build_keras_model, batch_size=32, verbose=0) # 初始化GridSearchCV,设置交叉验证折数 grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=3, verbose=1) grid_results = grid_search.fit(X_train, y_train) # 创建字典存储所有超参数组合的历史数据 all_param_histories = {} # 遍历每个超参数组合 for idx, params in enumerate(grid_results.cv_results_['params']): # 将参数转为可哈希的键(比如字符串) param_key = str(params) # 获取该参数组合对应的所有折叠的模型实例 fold_history_list = [] for fold_num in range(grid_search.cv): # 计算当前折叠的模型在cv_results_中的索引 estimator_idx = idx * grid_search.cv + fold_num fold_estimator = grid_results.cv_results_['estimator'][estimator_idx] # 添加该折叠的训练历史 fold_history_list.extend(fold_estimator.fold_histories) all_param_histories[param_key] = fold_history_list
4. 分析与可视化历史数据
现在all_param_histories里就保存了每个超参数组合对应的所有折叠的每轮训练历史。你可以把这些数据转换成DataFrame,方便分析或绘图:
def convert_history_to_dataframe(histories): df_list = [] for fold_idx, hist in enumerate(histories): df = pd.DataFrame(hist) df['fold'] = fold_idx + 1 df['epoch'] = df.index + 1 df_list.append(df) return pd.concat(df_list, ignore_index=True) # 示例:获取units=32, activation='relu', epochs=10的历史数据 target_params = "{'units': 32, 'activation': 'relu', 'epochs': 10}" history_df = convert_history_to_dataframe(all_param_histories[target_params]) # 查看前5轮的数据 print(history_df.head()) # 绘制该参数组合的训练/验证准确率变化 import matplotlib.pyplot as plt plt.figure(figsize=(10,6)) for fold in history_df['fold'].unique(): fold_data = history_df[history_df['fold'] == fold] plt.plot(fold_data['epoch'], fold_data['accuracy'], label=f'Fold {fold} - Train Acc') plt.plot(fold_data['epoch'], fold_data['val_accuracy'], label=f'Fold {fold} - Val Acc') plt.title('Training & Validation Accuracy per Epoch') plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.legend() plt.show()
注意事项
- 这种方法会占用更多内存,因为要保存所有模型的每轮训练数据,如果你的参数组合多、epoch数大,需要注意内存限制。
- 如果你的任务是多分类,记得修改模型的输出层和损失函数,对应的metrics也要调整(比如
metrics=['categorical_accuracy'])。
内容的提问来源于stack exchange,提问作者Akhan
相关产品推荐
相关产品推荐

