Keras深度学习框架第二十七讲:KerasTuner超参数优化基础

本文主要是介绍Keras深度学习框架第二十七讲:KerasTuner超参数优化基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、超参数优化概念

1.1 什么是超参数优化

超参数调优,也称为超参数优化或参数调优,是寻找学习算法或模型最佳超参数组合的过程。超参数是在训练过程开始之前设置的参数,模型无法直接从数据中学习这些参数。它们控制着学习算法的行为,并对模型的性能产生重大影响。

超参数调优的目标是搜索导致给定任务上最佳性能的超参数组合,例如最大化准确率或最小化误差。该过程通常包括以下步骤:

  1. 定义搜索空间:确定要调优的每个超参数的可能值范围。这个搜索空间可以是离散的(例如,一组预定义的值)或连续的(例如,一系列浮点数)。

  2. 选择调优策略:有多种超参数调优策略可供选择,包括网格搜索、随机搜索、贝叶斯优化、基于梯度的优化和进化算法。这些策略在计算效率、样本效率和找到良好解决方案的能力方面有不同的权衡。

  3. 评估模型:对于每一组超参数组合,训练模型并在验证集上评估其性能。使用的性能指标(例如,准确率、损失、F1分数)取决于特定任务。

  4. 选择最佳超参数:选择在验证集上表现最好的超参数组合。

  5. 重新训练模型(可选):使用在调优过程中找到的最佳超参数,在整个数据集(包括验证集)上重新训练模型。这一步不是必需的,但有助于提高模型在测试集上的性能。

超参数调优是机器学习流程中的一个重要步骤,因为超参数的选择可以对模型的性能产生显著影响。然而,它也可能是计算密集型的,特别是对于具有大量超参数和大型搜索空间的复杂模型。因此,选择一个在计算效率和找到良好解决方案的能力之间取得平衡的调优策略是非常重要的。

1.2 KerasTuner简介

KerasTuner 是一个用于超参数调优的通用库,它与 Keras 工作流程紧密结合,但不仅限于此,它也可以用于调优 scikit-learn 模型或其他任何需要调优的模型。以下是一个使用 KerasTuner 来调优模型架构、训练过程和数据预处理步骤的简单示例。

1.2.1 安装 KerasTuner

如果你还没有安装 KerasTuner,你可以使用 pip 来安装:

pip install keras-tuner
1.2.2 准备数据和模型

假设我们有一个简单的 Keras 模型和一个数据集,我们想要调优这个模型的超参数。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split# 假设我们有一个简单的分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_informative=2, n_redundant=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 定义一个简单的 Keras 模型构建函数
def build_model(hp):model = Sequential()model.add(Dense(units=hp.Int('units_1', min_value=32, max_value=128, step=16), activation='relu', input_shape=(20,)))model.add(Dense(units=hp.Int('units_2', min_value=32, max_value=64, step=16), activation='relu'))model.add(Dense(1, activation='sigmoid'))model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])return model
1.2.3使用 KerasTuner 搜索超参数

接下来,我们使用 KerasTuner 来搜索最佳的超参数。在这个例子中,我们将使用 RandomSearch 策略,但 KerasTuner 还提供了 HyperbandBayesianOptimization 等其他策略。

from kerastuner import RandomSearch
from kerastuner.engine.hyperparameters import HyperParameters# 创建一个 RandomSearch 对象
tuner = RandomSearch(build_model,objective='val_accuracy',max_trials=10,executions_per_trial=3,directory='my_dir',project_name='helloworld')# 运行搜索
tuner.search(X_train, y_train, epochs=2, validation_data=(X_test, y_test))# 获取最佳模型
best_model = tuner.get_best_models(num_models=1)[0]# 使用最佳模型进行评估
loss, accuracy = best_model.evaluate(X_test, y_test)
print(f'Loss: {loss}, Accuracy: {accuracy}')

在这个例子中,RandomSearch 会随机尝试不同的超参数组合,每个组合都会进行三次训练和验证(executions_per_trial=3)。max_trials=10 表示总共会尝试 10 个不同的超参数组合。

1.2.4 数据预处理步骤的调优

虽然 KerasTuner 主要用于模型架构和训练过程的调优,但你也可以在构建模型之前定义一些可调优的数据预处理步骤。例如,你可以定义不同的归一化或特征选择方法,并在搜索超参数时一起调优它们。

这通常需要在 build_model 函数中封装一些预处理逻辑,并使用 hp(HyperParameters 对象)来定义预处理步骤中的可调参数。

2、KerasTuner使用技巧

2.1调整模型架构

首先,我们需要编写一个函数,它返回一个编译好的Keras模型。该函数接受一个hp参数来在构建模型时定义超参数。

2.1.1定义搜索空间

在以下代码示例中,我们定义了一个具有两个Dense层的Keras模型。我们想要调整第一个Dense层中的单元数。我们只需要使用hp.Int('units', min_value=32, max_value=512, step=32)定义一个整数超参数,其范围是从32到512(包含这两个值)。当从该范围中采样时,通过区间的最小步长为32。

import keras
from keras import layersdef build_model(hp):model = keras.Sequential()model.add(layers.Flatten())model.add(layers.Dense(# Define the hyperparameter.units=hp.Int("units", min_value=32, max_value=512, step=32),activation="relu",))model.add(layers.Dense(10, activation="softmax"))model.compile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"],)return model

模型一旦建立成功,可以进行如下测试

import keras_tunerbuild_model(keras_tuner.HyperParameters())

当然,超参数的种类很多。我们可以在函数中定义多个超参数。在以下代码中,我们将使用hp.Boolean()来调整是否使用Dropout层,使用hp.Choice()来调整使用哪种激活函数,以及使用hp.Float()来调整优化器的学习率。

def build_model(hp):model = keras.Sequential()model.add(layers.Flatten())model.add(layers.Dense(# Tune number of units.units=hp.Int("units", min_value=32, max_value=512, step=32),# Tune the activation function to use.activation=hp.Choice("activation", ["relu", "tanh"]),))# Tune whether to use dropout.if hp.Boolean("dropout"):model.add(layers.Dropout(rate=0.25))model.add(layers.Dense(10, activation="softmax"))# Define the optimizer learning rate as a hyperparameter.learning_rate = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate),loss="categorical_crossentropy",metrics=["accuracy"],)return modelbuild_model(keras_tuner.HyperParameters())

正如下面所展示的,超参数看起来像是实际的值。但实际上,它们只是返回实际值的函数。例如,hp.Int() 返回一个整数(int)值。因此,你可以将这些超参数放入变量中、用于循环(for loops)或条件判断(if conditions)中。

在Keras Tuner或类似的超参数搜索框架中,这些超参数函数(如 hp.Int(), hp.Float(), hp.Choice(), hp.Boolean() 等)是在模型构建阶段定义的占位符。在模型训练和评估的过程中,这些占位符会被搜索算法赋予具体的值,以找到最佳的模型配置。

在模型构建函数中,程序员可以使用这些超参数函数来动态地创建模型的不同版本,这些版本具有不同的层配置、激活函数、优化器设置等。然后,搜索算法会评估这些不同版本的模型,并基于某种性能指标(如验证集上的损失或准确率)来选择最佳的超参数组合。

hp = keras_tuner.HyperParameters()
print(hp.Int("units", min_value=32, max_value=512, step=32))

程序员也可以提前定义超参数,并将你的Keras代码放在一个单独的函数中。

这意味着可以将超参数的定义(例如使用hp.Int(), hp.Float(), hp.Choice(), hp.Boolean()等)与实际的模型构建代码分开。这样做的好处是,程序员可以更清晰地组织代码,使得超参数的搜索和模型的定义更加模块化。

在Keras Tuner中,通常会定义一个模型构建函数,该函数接受一个HyperParameters对象作为输入,并使用该对象中的超参数来构建模型。这个HyperParameters对象是在搜索过程中由Keras Tuner自动生成的,并包含了所有需要调整的超参数值。

但是,程序员也可以选择提前定义一些超参数的默认值或范围,并将这些定义与模型构建函数分开。然后,在搜索过程中,可以将这些预定义的超参数传递给模型构建函数,或者使用Keras Tuner来覆盖这些默认值,并进行更广泛的搜索。

def call_existing_code(units, activation, dropout, lr):model = keras.Sequential()model.add(layers.Flatten())model.add(layers.Dense(units=units, activation=activation))if dropout:model.add(layers.Dropout(rate=0.25))model.add(layers.Dense(10, activation="softmax"))model.compile(optimizer=keras.optimizers.Adam(learning_rate=lr),loss="categorical_crossentropy",metrics=["accuracy"],)return modeldef build_model(hp):units = hp.Int("units", min_value=32, max_value=512, step=32)activation = hp.Choice("activation", ["relu", "tanh"])dropout = hp.Boolean("dropout")lr = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")# call existing model-building code with the hyperparameter values.model = call_existing_code(units=units, activation=activation, dropout=dropout, lr=lr)return modelbuild_model(keras_tuner.HyperParameters())

每个超参数都通过其名称(第一个参数)唯一标识。为了将不同Dense层中的单元数作为不同的超参数分别调整,我们给它们赋予不同的名称,如f"units_{i}"

值得注意的是,这也是创建条件超参数的一个例子。有许多超参数指定了Dense层中的单元数。这些超参数的数量由层数决定,而层数本身也是一个超参数。因此,每次试验(trial)中使用的超参数总数可能会有所不同。一些超参数仅在满足特定条件时才会被使用。例如,units_3仅在num_layers大于3时才会被使用。使用Keras Tuner,你可以在创建模型时轻松地动态定义这样的超参数。

在Keras Tuner中,程序员可以通过条件逻辑(如if语句)来定义这样的条件超参数。这允许你根据其他超参数的值来动态地确定哪些超参数是相关的,并需要被调整。这种灵活性使得Keras Tuner成为一个强大的工具,用于自动化神经网络架构的超参数搜索和优化。

def build_model(hp):model = keras.Sequential()model.add(layers.Flatten())# Tune the number of layers.for i in range(hp.Int("num_layers", 1, 3)):model.add(layers.Dense(# Tune number of units separately.units=hp.Int(f"units_{i}", min_value=32, max_value=512, step=32),activation=hp.Choice("activation", ["relu", "tanh"]),))if hp.Boolean("dropout"):model.add(layers.Dropout(rate=0.25))model.add(layers.Dense(10, activation="softmax"))learning_rate = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate),loss="categorical_crossentropy",metrics=["accuracy"],)return modelbuild_model(keras_tuner.HyperParameters())
2.1.2 开始搜索

在定义了搜索空间之后,我们需要选择一个搜索器类来运行搜索。你可以从RandomSearch、BayesianOptimization和Hyperband中选择,它们分别对应不同的调优算法。这里我们以RandomSearch为例。

为了初始化搜索器,我们需要在初始化器中指定几个参数。

  • hypermodel:这是构建模型的函数,在我们的例子中build_model
  • objective:要优化的目标名称(对于内置指标,是否最小化或最大化会自动推断)。稍后在本教程中我们将介绍如何使用自定义指标。
  • max_trials:在搜索期间运行的总试验次数。
  • executions_per_trial:每个试验应该构建和拟合的模型数量。不同的试验有不同的超参数值。在相同的试验中,执行的模型具有相同的超参数值。每次试验中进行多次执行的目的是减少结果的方差,从而能够更准确地评估模型的性能。如果你希望更快地获得结果,你可以设置executions_per_trial=1(每个模型配置进行一轮训练)。
  • overwrite:控制是否覆盖相同目录中的先前结果,还是恢复先前的搜索。这里我们设置overwrite=True以开始新的搜索并忽略任何先前的结果。
  • directory:用于存储搜索结果的目录的路径。
  • project_name:在目录中的子目录的名称。

通过配置这些参数,你可以启动搜索过程,并根据定义的搜索空间来寻找最佳的模型配置。

tuner = keras_tuner.RandomSearch(hypermodel=build_model,objective="val_accuracy",max_trials=3,executions_per_trial=2,overwrite=True,directory="my_dir",project_name="helloworld",
)

你可以打印搜索空间的摘要,以便查看你定义的超参数的范围和类型。

tuner.search_space_summary()

在开始搜索之前,应提前准备MNIST数据集。

import keras
import numpy as np(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()x_train = x[:-10000]
x_val = x[-10000:]
y_train = y[:-10000]
y_val = y[-10000:]x_train = np.expand_dims(x_train, -1).astype("float32") / 255.0
x_val = np.expand_dims(x_val, -1).astype("float32") / 255.0
x_test = np.expand_dims(x_test, -1).astype("float32") / 255.0num_classes = 10
y_train = keras.utils.to_categorical(y_train, num_classes)
y_val = keras.utils.to_categorical(y_val, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

然后,开始搜索最佳的超参数配置。传递给search的所有参数都会在每个执行过程中传递给model.fit()。请记住传递validation_data来评估模型。

tuner.search(x_train, y_train, epochs=2, validation_data=(x_val, y_val))

在搜索过程中,模型构建函数会使用不同的超参数值在不同的试验中被调用。在每个试验中,搜索器会生成一组新的超参数值来构建模型。然后模型会被训练并评估,评估指标会被记录下来。搜索器会逐步探索搜索空间并最终找到一组良好的超参数值。

2.1.3 查询结果

当搜索结束后,你可以检索到表现最好的模型或多个模型。这些模型是在验证集上评估时表现最佳的epoch时被保存的。

# Get the top 2 models.
models = tuner.get_best_models(num_models=2)
best_model = models[0]
best_model.summary()

打印查询结果概要

tuner.results_summary()

程序员可以在my_dir/helloworld文件夹中找到详细的日志、检查点等,即directory/project_name

程序员还可以使用TensorBoard和HParams插件来可视化调优结果。要获取更多信息,请遵循这个链接。

2.2 重新训练模型

如果你想要使用整个数据集来训练模型,你可以检索出最佳的超参数,并自己重新训练模型。

# Get the top 2 hyperparameters.
best_hps = tuner.get_best_hyperparameters(5)
# Build the model with the best hp.
model = build_model(best_hps[0])
# Fit with the entire dataset.
x_all = np.concatenate((x_train, x_val))
y_all = np.concatenate((y_train, y_val))
model.fit(x=x_all, y=y_all, epochs=1)

2.3 模型训练调优

为了调优模型构建过程,我们需要继承HyperModel类,这也使得超模型易于共享和重用。

我们需要重写HyperModel.build()和HyperModel.fit()方法来分别调优模型构建和训练过程。HyperModel.build()方法与模型构建函数相同,它使用超参数创建Keras模型并返回该模型。

在HyperModel.fit()中,你可以访问由HyperModel.build()返回的模型、hp以及传递给search()的所有参数。你需要训练模型并返回训练历史记录。

在以下代码中,我们将调整model.fit()中的shuffle参数。

通常不需要调整epoch的数量,因为model.fit()会传递一个内置回调来保存由验证数据评估的最佳epoch时的模型。

注意:**kwargs应该始终传递给model.fit(),因为它包含了用于模型保存和TensorBoard插件的回调。

class MyHyperModel(keras_tuner.HyperModel):def build(self, hp):model = keras.Sequential()model.add(layers.Flatten())model.add(layers.Dense(units=hp.Int("units", min_value=32, max_value=512, step=32),activation="relu",))model.add(layers.Dense(10, activation="softmax"))model.compile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"],)return modeldef fit(self, hp, model, *args, **kwargs):return model.fit(*args,# Tune whether to shuffle the data in each epoch.shuffle=hp.Boolean("shuffle"),**kwargs,)

再次,我们可以进行快速检查以确保代码正常工作。

hp = keras_tuner.HyperParameters()
hypermodel = MyHyperModel()
model = hypermodel.build(hp)
hypermodel.fit(hp, model, np.random.rand(100, 28, 28), np.random.rand(100, 10))
2.3.1数据预处理调优

为了调优数据预处理,我们只需在HyperModel.fit()中添加一个额外的步骤,在这个步骤中我们可以从参数中访问数据集。在以下代码中,我们将调优是否在训练模型之前对数据进行归一化。这次我们明确地将x和y放入函数签名中,因为我们需要在函数中使用它们。

class MyHyperModel(keras_tuner.HyperModel):def build(self, hp):model = keras.Sequential()model.add(layers.Flatten())model.add(layers.Dense(units=hp.Int("units", min_value=32, max_value=512, step=32),activation="relu",))model.add(layers.Dense(10, activation="softmax"))model.compile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"],)return modeldef fit(self, hp, model, x, y, **kwargs):if hp.Boolean("normalize"):x = layers.Normalization()(x)return model.fit(x,y,# Tune whether to shuffle the data in each epoch.shuffle=hp.Boolean("shuffle"),**kwargs,)hp = keras_tuner.HyperParameters()
hypermodel = MyHyperModel()
model = hypermodel.build(hp)
hypermodel.fit(hp, model, np.random.rand(100, 28, 28), np.random.rand(100, 10))

如果某个超参数在build()和fit()中都被使用,程序员可以在build()中定义它,然后在fit()中使用hp.get(hp_name)来检索它。我们以图像大小为例,它既在build()中用作输入形状,也在fit()中的数据预处理步骤中用于裁剪图像。

class MyHyperModel(keras_tuner.HyperModel):def build(self, hp):image_size = hp.Int("image_size", 10, 28)inputs = keras.Input(shape=(image_size, image_size))outputs = layers.Flatten()(inputs)outputs = layers.Dense(units=hp.Int("units", min_value=32, max_value=512, step=32),activation="relu",)(outputs)outputs = layers.Dense(10, activation="softmax")(outputs)model = keras.Model(inputs, outputs)model.compile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"],)return modeldef fit(self, hp, model, x, y, validation_data=None, **kwargs):if hp.Boolean("normalize"):x = layers.Normalization()(x)image_size = hp.get("image_size")cropped_x = x[:, :image_size, :image_size, :]if validation_data:x_val, y_val = validation_datacropped_x_val = x_val[:, :image_size, :image_size, :]validation_data = (cropped_x_val, y_val)return model.fit(cropped_x,y,# Tune whether to shuffle the data in each epoch.shuffle=hp.Boolean("shuffle"),validation_data=validation_data,**kwargs,)tuner = keras_tuner.RandomSearch(MyHyperModel(),objective="val_accuracy",max_trials=3,overwrite=True,directory="my_dir",project_name="tune_hypermodel",
)tuner.search(x_train, y_train, epochs=2, validation_data=(x_val, y_val))
2.3.2 重新训练模型

使用HyperModel也允许你自行重新训练最佳模型。

hypermodel = MyHyperModel()
best_hp = tuner.get_best_hyperparameters()[0]
model = hypermodel.build(best_hp)
hypermodel.fit(best_hp, model, x_all, y_all, epochs=1)
2.3.3 指定调优目标

在之前的所有示例中,我们都只是使用验证准确率(“val_accuracy”)作为调优目标来选择最佳模型。实际上,你可以使用任何指标作为调优目标。最常用的指标是"val_loss",即验证损失。

使用内置指标作为调优目标
Keras中有许多其他内置指标可以作为调优目标。以下是内置指标的列表。

要使用内置指标作为调优目标,你需要遵循以下步骤:

  1. 使用内置指标编译模型。例如,如果你想要使用平均绝对误差(MeanAbsoluteError)。你需要用metrics=[MeanAbsoluteError()]来编译模型。你也可以使用其名称字符串代替:metrics=[“mean_absolute_error”]。指标的名称字符串始终是类名的蛇形命名(snake_case)形式。

  2. 确定目标名称字符串。目标名称字符串的格式通常是f"val_{metric_name_string}"。例如,在验证数据上评估的均方误差的目标名称字符串应该是"val_mean_absolute_error"。

  3. 将其包装到keras_tuner.Objective中。我们通常需要将目标包装到keras_tuner.Objective对象中,以指定要优化目标的方向。例如,如果我们想要最小化均方误差,我们可以使用keras_tuner.Objective(“val_mean_absolute_error”, “min”)。方向应该是"min"或"max"。

  4. 将包装后的目标传递给调优器。

以下是简化版的代码示例。

def build_regressor(hp):model = keras.Sequential([layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),layers.Dense(units=1),])model.compile(optimizer="adam",loss="mean_squared_error",# Objective is one of the metrics.metrics=[keras.metrics.MeanAbsoluteError()],)return modeltuner = keras_tuner.RandomSearch(hypermodel=build_regressor,# The objective name and direction.# Name is the f"val_{snake_case_metric_class_name}".objective=keras_tuner.Objective("val_mean_absolute_error", direction="min"),max_trials=3,overwrite=True,directory="my_dir",project_name="built_in_metrics",
)tuner.search(x=np.random.rand(100, 10),y=np.random.rand(100, 1),validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),
)tuner.results_summary()
2.3.4 自定义指标作为调优目标

程序员可以实现自己的指标并将其用作超参数搜索的目标。这里,我们以均方误差(MSE)为例。首先,我们通过继承keras.metrics.Metric来实现MSE指标。记得在super().__init__()name参数中给你的指标命名,这个名称稍后会用到。注意:MSE实际上是内置指标,可以通过keras.metrics.MeanSquaredError导入。这里只是一个例子,展示如何将自定义指标用作超参数搜索的目标。

关于实现自定义指标的更多信息,请参阅这个教程。如果你想要一个具有不同函数签名的指标(不同于update_state(y_true, y_pred, sample_weight)),你可以按照这个教程来重写你的模型的train_step()方法。

from keras import opsclass CustomMetric(keras.metrics.Metric):def __init__(self, **kwargs):# Specify the name of the metric as "custom_metric".super().__init__(name="custom_metric", **kwargs)self.sum = self.add_weight(name="sum", initializer="zeros")self.count = self.add_weight(name="count", dtype="int32", initializer="zeros")def update_state(self, y_true, y_pred, sample_weight=None):values = ops.square(y_true - y_pred)count = ops.shape(y_true)[0]if sample_weight is not None:sample_weight = ops.cast(sample_weight, self.dtype)values *= sample_weightcount *= sample_weightself.sum.assign_add(ops.sum(values))self.count.assign_add(count)def result(self):return self.sum / ops.cast(self.count, "float32")def reset_states(self):self.sum.assign(0)self.count.assign(0)

然后使用自定义目标运行搜索。

def build_regressor(hp):model = keras.Sequential([layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),layers.Dense(units=1),])model.compile(optimizer="adam",loss="mean_squared_error",# Put custom metric into the metrics.metrics=[CustomMetric()],)return modeltuner = keras_tuner.RandomSearch(hypermodel=build_regressor,# Specify the name and direction of the objective.objective=keras_tuner.Objective("val_custom_metric", direction="min"),max_trials=3,overwrite=True,directory="my_dir",project_name="custom_metrics",
)tuner.search(x=np.random.rand(100, 10),y=np.random.rand(100, 1),validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),
)tuner.results_summary()

如果自定义目标很难放入一个自定义指标中,程序员还可以在HyperModel.fit()中自行评估模型并返回目标值。默认情况下,这个目标值会被最小化。在这种情况下,你不需要在初始化调优器时指定目标。但是,这样做的话,只有KerasTuner会记录这个指标值,而不是通过Keras日志来跟踪。因此,这些值不会通过任何使用Keras指标的TensorBoard视图来显示。

简而言之,如果选择在HyperModel.fit()中直接计算并返回目标值,那么程序员将失去通过Keras的日志和TensorBoard来跟踪和可视化这些指标值的能力。相反,程序员需要依赖KerasTuner的日志来查看和评估这些自定义目标值。

class HyperRegressor(keras_tuner.HyperModel):def build(self, hp):model = keras.Sequential([layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),layers.Dense(units=1),])model.compile(optimizer="adam",loss="mean_squared_error",)return modeldef fit(self, hp, model, x, y, validation_data, **kwargs):model.fit(x, y, **kwargs)x_val, y_val = validation_datay_pred = model.predict(x_val)# Return a single float to minimize.return np.mean(np.abs(y_pred - y_val))tuner = keras_tuner.RandomSearch(hypermodel=HyperRegressor(),# No objective to specify.# Objective is the return value of `HyperModel.fit()`.max_trials=3,overwrite=True,directory="my_dir",project_name="custom_eval",
)
tuner.search(x=np.random.rand(100, 10),y=np.random.rand(100, 1),validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),
)tuner.results_summary()

如果程序员在KerasTuner中要跟踪多个指标,但只使用其中一个作为目标,可以在HyperModel.fit()中返回一个字典,其中键是指标名称,值是指标值。例如,返回{"metric_a": 1.0, "metric_b": 2.0}。然后,程序员可以使用这些键中的一个作为目标名称来配置KerasTuner的Objective,例如keras_tuner.Objective("metric_a", "min")

这样,KerasTuner将使用这个指定的指标(“metric_a”)作为优化目标,但也会记录并跟踪所有在字典中返回的其他指标("metric_b"等)。这样,你就可以在调优过程中同时观察多个指标的变化,而不仅仅是最小化的目标指标。

class HyperRegressor(keras_tuner.HyperModel):def build(self, hp):model = keras.Sequential([layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),layers.Dense(units=1),])model.compile(optimizer="adam",loss="mean_squared_error",)return modeldef fit(self, hp, model, x, y, validation_data, **kwargs):model.fit(x, y, **kwargs)x_val, y_val = validation_datay_pred = model.predict(x_val)# Return a dictionary of metrics for KerasTuner to track.return {"metric_a": -np.mean(np.abs(y_pred - y_val)),"metric_b": np.mean(np.square(y_pred - y_val)),}tuner = keras_tuner.RandomSearch(hypermodel=HyperRegressor(),# Objective is one of the keys.# Maximize the negative MAE, equivalent to minimize MAE.objective=keras_tuner.Objective("metric_a", "max"),max_trials=3,overwrite=True,directory="my_dir",project_name="custom_eval_dict",
)
tuner.search(x=np.random.rand(100, 10),y=np.random.rand(100, 1),validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),
)tuner.results_summary()
2.3.5 端到端工作流程的调优

在某些情况下,很难将代码拆分为构建和拟合函数。你还可以通过重写Tuner.run_trial()来保持端到端的工作流程在一个地方,这样你可以完全控制一个试验的运行。你可以将其视为任何事物的黑盒优化器。

调优任何函数

例如,你可以找到一个值x,使得函数f(x) = x*x + 1取得最小值。在下面的代码中,我们仅仅将x定义为超参数,并返回f(x)作为目标值。初始化调优器时,可以省略hypermodel和objective参数。

class MyTuner(keras_tuner.RandomSearch):def run_trial(self, trial, *args, **kwargs):# Get the hp from trial.hp = trial.hyperparameters# Define "x" as a hyperparameter.x = hp.Float("x", min_value=-1.0, max_value=1.0)# Return the objective value to minimize.return x * x + 1tuner = MyTuner(# No hypermodel or objective specified.max_trials=20,overwrite=True,directory="my_dir",project_name="tune_anything",
)# No need to pass anything to search()
# unless you use them in run_trial().
tuner.search()
print(tuner.get_best_hyperparameters()[0].get("x"))

2.4 保持Keras代码独立

程序员可以保持所有的Keras代码不变,并使用KerasTuner来调优它。这在由于某种原因程序员不能修改Keras代码时特别有用。

同时,这也给了你更多的灵活性。程序员不需要将模型构建和训练代码分开。然而,这种工作流程不会帮助程序员保存模型或连接TensorBoard插件。

要保存模型,程序员可以使用trial.trial_id,它是一个唯一标识一个试验的字符串,来构造不同的路径以保存来自不同试验的模型。可以将这些trial_id值用于文件路径或数据库条目中,以便跟踪和检索不同试验的模型。

import osdef keras_code(units, optimizer, saving_path):# Build modelmodel = keras.Sequential([layers.Dense(units=units, activation="relu"),layers.Dense(units=1),])model.compile(optimizer=optimizer,loss="mean_squared_error",)# Prepare datax_train = np.random.rand(100, 10)y_train = np.random.rand(100, 1)x_val = np.random.rand(20, 10)y_val = np.random.rand(20, 1)# Train & eval modelmodel.fit(x_train, y_train)# Save modelmodel.save(saving_path)# Return a single float as the objective value.# You may also return a dictionary# of {metric_name: metric_value}.y_pred = model.predict(x_val)return np.mean(np.abs(y_pred - y_val))class MyTuner(keras_tuner.RandomSearch):def run_trial(self, trial, **kwargs):hp = trial.hyperparametersreturn keras_code(units=hp.Int("units", 32, 128, 32),optimizer=hp.Choice("optimizer", ["adam", "adadelta"]),saving_path=os.path.join("/tmp", f"{trial.trial_id}.keras"),)tuner = MyTuner(max_trials=3,overwrite=True,directory="my_dir",project_name="keep_code_separate",
)
tuner.search()
# Retraining the model
best_hp = tuner.get_best_hyperparameters()[0]
keras_code(**best_hp.values, saving_path="/tmp/best_model.keras")

2.5 预制调用

KerasTuner 包含预制的可调应用:HyperResNet 和 HyperXception

这些是专为计算机视觉准备的即用型超模型(hypermodels)。

这些模型预编译时设置了损失函数为 “categorical_crossentropy” 和评估指标为 [“accuracy”]。

from keras_tuner.applications import HyperResNethypermodel = HyperResNet(input_shape=(28, 28, 1), classes=10)tuner = keras_tuner.RandomSearch(hypermodel,objective="val_accuracy",max_trials=2,overwrite=True,directory="my_dir",project_name="built_in_hypermodel",
)

3、总结

Keras超参数调优是指在使用Keras深度学习框架进行模型训练时,对模型的超参数进行搜索和调整,以找到最优的超参数组合,从而提高模型的性能。

  1. 超参数定义:超参数是在模型训练之前需要设置的参数,它们影响模型的训练过程和最终性能。在Keras中,常见的超参数包括学习率、批处理大小、训练轮次(epochs)、优化器类型、损失函数、正则化参数、层数、每层神经元数量、激活函数等。

  2. 调优方法

    • 网格搜索(Grid Search):在预定义的超参数空间中,对每一组超参数组合都进行训练并评估性能,最后选择性能最好的一组。这种方法简单但计算量大。
    • 随机搜索(Random Search):在超参数空间中随机选择一组超参数进行训练,这种方法通常比网格搜索更有效率,因为不是所有超参数都是等价的。
    • 贝叶斯优化(Bayesian Optimization):使用贝叶斯定理来智能地选择下一个要评估的超参数组合,基于之前的评估结果。这种方法能够更快地找到最优解。
    • 基于模型的优化:使用如高斯过程、决策树等方法来构建超参数和性能之间的模型,从而指导超参数的搜索。
  3. KerasTuner

    • KerasTuner是一个Keras官方提供的超参数调优工具,它封装了上述的调优方法,并提供了易于使用的API。
    • KerasTuner允许用户定义可调的超参数范围或选择,并在后台自动执行调优过程,包括创建模型、编译、训练、评估等步骤。
    • KerasTuner还支持分布式调优,可以在多个计算节点或GPU上并行执行调优试验。
  4. 注意事项

    • 评估指标:选择合适的评估指标来衡量模型的性能,如准确率、损失函数值、召回率、F1分数等。
    • 早停(Early Stopping):当模型性能在连续多个轮次中没有提升时,提前停止训练,以节省资源和时间。
    • 结果分析:分析调优结果,了解哪些超参数对模型性能影响最大,并根据结果进行进一步的调整。
  5. 集成和扩展

    • KerasTuner可以与Keras的其他功能(如数据预处理、模型保存/加载、回调函数等)无缝集成,提供完整的模型训练和调优流程。
    • 用户还可以根据自己的需求扩展KerasTuner的功能,如添加自定义的超参数搜索策略、评估指标等。

通过使用KerasTuner等工具进行超参数调优,可以更有效地找到最优的超参数组合,提高模型的性能,并节省大量的调优时间和计算资源。

使用Keras Tuner进行模型训练的过程可以分为以下几个步骤:

1. 安装并导入Keras Tuner

首先,你需要确保已经安装了Keras Tuner。如果还没有安装,可以使用pip进行安装:

pip install keras-tuner

然后在你的Python脚本中导入Keras Tuner:

import keras_tuner as kt

2. 准备数据集

根据你的任务准备数据集,并进行必要的预处理。例如,对于图像分类任务,你可以使用Keras的内置数据集(如MNIST或Fashion MNIST),或者加载你自己的数据集。

3. 定义模型构建函数

在Keras Tuner中,你需要定义一个模型构建函数,该函数接受一个hp(HyperParameters)对象作为输入,并返回一个编译好的Keras模型。在这个函数中,你可以使用hp对象来定义可调的超参数。

def build_model(hp):model = keras.Sequential()model.add(keras.layers.Flatten(input_shape=(28, 28)))  # 假设输入是28x28的图像# 搜索最佳的隐藏层单元数hp_units = hp.Int('units', min_value=32, max_value=512, step=32)model.add(keras.layers.Dense(units=hp_units, activation='relu'))# 如果需要,可以添加更多层model.add(keras.layers.Dense(10, activation='softmax'))  # 假设有10个类别# 编译模型model.compile(optimizer=keras.optimizers.Adam(),loss='sparse_categorical_crossentropy',metrics=['accuracy'],)return model

4. 实例化Tuner类

接下来,你需要实例化一个Tuner类(如RandomSearch, Hyperband, BayesianOptimization等),并传入模型构建函数、数据集、训练轮次等参数。

tuner = kt.RandomSearch(build_model,objective='val_accuracy',  # 要优化的指标max_trials=10,  # 最大试验次数executions_per_trial=3,  # 每个试验的重复次数directory='my_dir',  # 保存结果的目录project_name='helloworld',  # 项目名称
)

5. 运行Tuner进行搜索

使用search方法来运行Tuner进行超参数搜索。你可以传入训练数据和验证数据。

(x_train, y_train), (x_val, y_val) = keras.datasets.mnist.load_data()
# 对数据进行必要的预处理...tuner.search(x_train, y_train, epochs=10, validation_data=(x_val, y_val))

6. 获取最佳模型

搜索完成后,你可以从Tuner中获取最佳模型。

best_model = tuner.get_best_models(num_models=1)[0]

7. 评估并保存模型

你可以使用测试集来评估最佳模型的性能,并保存模型以供将来使用。

# 加载测试集...
test_loss, test_acc = best_model.evaluate(x_test, y_test)
print('Test accuracy:', test_acc)# 保存模型...
best_model.save('best_model.h5')

这篇关于Keras深度学习框架第二十七讲:KerasTuner超参数优化基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1004589

相关文章

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Tomcat高效部署与性能优化方式

《Tomcat高效部署与性能优化方式》本文介绍了如何高效部署Tomcat并进行性能优化,以确保Web应用的稳定运行和高效响应,高效部署包括环境准备、安装Tomcat、配置Tomcat、部署应用和启动T... 目录Tomcat高效部署与性能优化一、引言二、Tomcat高效部署三、Tomcat性能优化总结Tom

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex