使用Keras Tuner调参时,TensorBoard提取数据遇KeyError问题求助
解决Keras Tuner回归任务中TensorBoard标量提取的KeyError问题
问题场景
用Keras Tuner对序列神经网络做回归任务超参调优,采用MSE作为损失函数,需要提取所有试验的损失、超参数、试验编号、训练轮次等数据存到文件用于后续绘图。基于官方教程搭建框架后,使用TensorBoard回调提取数据时出现KeyError: 'Key epoch_loss was not found in Reservoir',且调用ea.scalars.Keys()返回空列表,无法获取正确的标量键名。
问题原因
- 路径错误:Keras Tuner默认会将每个试验的日志存放在
project_name指定的目录下(示例中是keras_tuner_test),而非手动指定的sample_log_directory,导致找不到日志文件,ea.scalars.Keys()返回空。 - 键名错误:Keras默认的训练损失标量键是
loss,验证损失是val_loss,而非代码中的epoch_loss;且回归任务未配置准确率指标,代码中尝试提取的epoch_acc本身不存在。 - 遍历不完整:代码仅提取了
execution0的数据,未覆盖executions_per_trial指定的多次执行,会丢失部分数据。
解决方案
1. 调整TensorBoard回调配置
无需手动指定log_dir,Keras Tuner会自动在项目目录下为每个试验创建独立的日志子目录,确保日志路径正确。
2. 修正数据提取逻辑
- 使用正确的标量键名
loss和val_loss - 移除所有准确率相关的提取代码
- 遍历所有试验和每个试验下的所有执行
3. 提取超参数信息
从tuner.oracle.trials中获取每个试验的超参数、试验ID、最终损失等信息,和训练过程的损失数据合并。
修改后的完整代码
模型与调参部分
import numpy as np import keras from tensorflow.keras.optimizers import Adam from tensorflow.keras import layers import keras_tuner from sklearn.model_selection import train_test_split from tensorboard.backend.event_processing import event_accumulator import pandas as pd # 生成随机回归数据 random_data = np.random.rand(100,4) x_data = random_data[:, :-1] y_data = random_data[:, -1:] input_dimensions = len(x_data[0, :]) # 划分训练集和验证集 x_train, x_eval, y_train, y_eval = train_test_split(x_data, y_data, test_size=0.3, random_state=101) # 构建超参数模型 def build_model(hp): model = keras.Sequential() # 搜索层数、每层神经元数、激活函数 for i in range(hp.Int("num_layers", 2, 4)): model.add(layers.Dense( units=hp.Int(f"units_{i}", min_value=32, max_value=1024, step=32), activation=hp.Choice("activation", ["relu", "sigmoid"]))) model.add(layers.Dense(1, activation="linear")) model.compile(optimizer=Adam(learning_rate=0.0005), loss='mse') return model # 初始化调优器 tuner = keras_tuner.RandomSearch( hypermodel=build_model, objective=keras_tuner.Objective('val_loss', direction="min"), # 用验证损失更合理 max_trials=5, executions_per_trial=3, overwrite=True, project_name="keras_tuner_test") # 添加TensorBoard回调,无需指定log_dir,自动存在keras_tuner_test目录下 tensorboard_callback = keras.callbacks.TensorBoard() tuner.search(x_train, y_train, epochs=3, validation_data=(x_eval, y_eval), callbacks=[tensorboard_callback])
数据提取与保存部分
def extract_trial_data(trial_id, project_dir="keras_tuner_test"): """提取单个试验所有执行的训练/验证损失数据""" trial_data = [] # 遍历所有执行(executions_per_trial指定的次数) for exec_idx in range(tuner.executions_per_trial): log_dir = f"{project_dir}/{trial_id}/execution{exec_idx}" # 加载训练日志 train_ea = event_accumulator.EventAccumulator(f"{log_dir}/train") train_ea.Reload() # 加载验证日志 val_ea = event_accumulator.EventAccumulator(f"{log_dir}/validation") val_ea.Reload() # 获取训练损失序列 train_loss = [scalar.value for scalar in train_ea.Scalars('loss')] # 获取验证损失序列 val_loss = [scalar.value for scalar in val_ea.Scalars('val_loss')] # 按轮次整理数据 for epoch in range(len(train_loss)): trial_data.append({ "trial_id": trial_id, "execution_idx": exec_idx, "epoch": epoch+1, "train_loss": train_loss[epoch], "val_loss": val_loss[epoch] }) return trial_data # 提取所有试验的数据 all_data = [] for trial in tuner.oracle.trials.values(): # 提取试验的超参数 hyperparams = trial.hyperparameters.values # 提取训练过程数据 trial_history = extract_trial_data(trial.trial_id) # 将超参数合并到每条记录中 for record in trial_history: record.update(hyperparams) # 添加试验的最终损失 record["final_val_loss"] = trial.score all_data.append(record) # 转换为DataFrame并保存到CSV文件 df = pd.DataFrame(all_data) df.to_csv("keras_tuner_trial_data.csv", index=False) print("数据已保存到keras_tuner_trial_data.csv")
说明
- 保存的CSV文件包含所有试验的试验ID、执行序号、训练轮次、训练损失、验证损失、所有超参数、最终验证损失,可直接用于绘图分析
- 若需要查看日志中的所有标量键名,可在加载
event_accumulator后打印train_ea.scalars.Keys(),确认可用的键
内容的提问来源于stack exchange,提问作者Tobitobitobi
相关产品推荐
相关产品推荐

