摘要:KerasTuner是一款专为深度学习设计的超参数优化工具,支持贝叶斯优化、Hyperband和随机搜索算法。开发者可轻松定义搜索空间,在模型构建代码中直接嵌入超参数采样逻辑。框架提供端到端解决方案,从模型定义(如卷积层数、滤波器数量、学习率等)到分布式训练,并支持自定义训练循环和Scikit-learn模型调优。通过内置算法自动寻找最优参数组合,显著提升模型性能,同时保持代码简洁性。其分布式架构支持多节点并行搜索,大幅提高调优效率。

目录

使用 Keras Tuner 进行超参数调优

Keras Tuner 实战演示

内置可调优模型

分布式调优

自定义训练循环

调优 Scikit-learn 模型


使用 Keras Tuner 进行超参数调优

Keras Tuner 是一款易用、支持分布式部署的超参数优化框架,能够解决超参数搜索过程中的各类痛点问题。借助它,开发者可以轻松定义超参数搜索空间,并利用框架内置的算法找到最优的超参数取值。Keras Tuner 内置了贝叶斯优化、超波段算法(Hyperband)和随机搜索三种核心算法,同时其架构设计也为研究人员提供了便捷的扩展能力,方便他们尝试研发新的搜索算法。

Keras Tuner 实战演示

下方为你提供完整的代码示例。这里展示一个简单的端到端实战案例,首先我们需要定义一个模型构建函数,该函数接收一个hp参数,通过这个参数可以对超参数进行采样,例如hp.Int('units', min_value=32, max_value=512, step=32)(用于从指定范围内选取整数超参数)。可以看到,超参数能够直接内嵌在模型构建代码中定义。以下示例将构建一个简单的可调优模型,并在 CIFAR-10 数据集上完成训练:

import tensorflow as tf

def build_model(hp):
  inputs = tf.keras.Input(shape=(32, 32, 3))
  x = inputs
  # 定义卷积块数量的超参数,取值3-5,默认值3
  for i in range(hp.Int('conv_blocks', 3, 5, default=3)):
    # 为每个卷积块定义滤波器数量超参数,取值32-256,步长32
    filters = hp.Int('filters_' + str(i), 32, 256, step=32)
    for _ in range(2):
      x = tf.keras.layers.Convolution2D(
        filters, kernel_size=(3, 3), padding='same')(x)
      x = tf.keras.layers.BatchNormalization()(x)
      x = tf.keras.layers.ReLU()(x)
    # 选择池化方式,可选平均池化或最大池化
    if hp.Choice('pooling_' + str(i), ['avg', 'max']) == 'max':
      x = tf.keras.layers.MaxPool2D()(x)
    else:
      x = tf.keras.layers.AvgPool2D()(x)
  x = tf.keras.layers.GlobalAvgPool2D()(x)
  # 定义全连接层神经元数量超参数,取值30-100,步长10,默认值50
  x = tf.keras.layers.Dense(
      hp.Int('hidden_size', 30, 100, step=10, default=50),
      activation='relu')(x)
  # 定义dropout概率超参数,取值0-0.5,步长0.1,默认值0.5
  x = tf.keras.layers.Dropout(
      hp.Float('dropout', 0, 0.5, step=0.1, default=0.5))(x)
  # 输出层,适配CIFAR-10的10分类任务
  outputs = tf.keras.layers.Dense(10, activation='softmax')(x)

  model = tf.keras.Model(inputs, outputs)
  # 编译模型,优化器学习率为超参数,对数采样1e-4至1e-2
  model.compile(
    optimizer=tf.keras.optimizers.Adam(
      hp.Float('learning_rate', 1e-4, 1e-2, sampling='log')),
    loss='sparse_categorical_crossentropy', 
    metrics=['accuracy'])
  return model

接下来,实例化一个调优器。需要指定模型构建函数,以及待优化的目标指标名称(对于框架内置的指标,会自动推断是求最大值还是最小值;自定义指标则可通过kerastuner.Objective类手动指定)。本示例中,我们将使用超波段算法(Hyperband)进行超参数搜索:

import kerastuner as kt

tuner = kt.Hyperband(
    build_model,
    objective='val_accuracy',  # 优化目标:验证集准确率
    max_epochs=30,             # 单模型最大训练轮数
    hyperband_iterations=2)    # 超波段算法迭代次数

然后,我们通过 TensorFlow Datasets 下载 CIFAR-10 数据集,随后启动超参数搜索。调用search方法即可开始搜索,该方法的参数签名与keras.Model.fit完全一致:

import tensorflow_datasets as tfds

# 加载CIFAR-10数据集
data = tfds.load('cifar10')
train_ds, test_ds = data['train'], data['test']

# 数据标准化处理:将像素值缩放到0-1区间
def standardize_record(record):
  return tf.cast(record['image'], tf.float32) / 255., record['label']

# 数据集预处理:标准化、缓存、批处理、打乱
train_ds = train_ds.map(standardize_record).cache().batch(64).shuffle(10000)
test_ds = test_ds.map(standardize_record).cache().batch(64)

# 启动超参数搜索,加入早停策略防止过拟合
tuner.search(train_ds,
             validation_data=test_ds,
             epochs=30,
             callbacks=[tf.keras.callbacks.EarlyStopping(patience=1)])

每个模型最多训练 30 轮,同时超波段算法会运行 2 次迭代。搜索完成后,可通过get_best_models函数获取搜索过程中得到的最优模型:

best_model = tuner.get_best_models(1)[0]  # 获取排名第一的最优模型

也可以查看搜索得到的最优超参数取值:

best_hyperparameters = tuner.get_best_hyperparameters(1)[0]  # 获取最优超参数配置

以上就是实现一次专业的超参数搜索所需的全部代码!你可以在 [此链接] 获取上述示例的完整代码。

内置可调优模型

除了支持自定义可调优模型外,Keras Tuner 还提供了两个内置的可调优模型:HyperResnet 和 HyperXception。这两个模型会分别在 ResNet 和 Xception 网络架构的各类变体中进行搜索。可通过以下方式将其与调优器配合使用:

tuner = kt.tuners.BayesianOptimization(
  # 实例化HyperResnet,输入尺寸256×256×3,10分类任务
  kt.applications.HyperResNet(input_shape=(256, 256, 3), classes=10),
  objective='val_accuracy',  # 优化目标:验证集准确率
  max_trials=50)             # 最大搜索试验次数

分布式调优

Keras Tuner 同时支持数据并行和试验并行两种分布式调优方式。也就是说,既可以通过tf.distribute.Strategy在多块 GPU 上运行单个模型,也可以在不同的工作节点上并行搜索不同的超参数组合。

实现试验并行搜索无需修改任何代码,只需设置三个环境变量:KERASTUNER_TUNER_IDKERASTUNER_ORACLE_IPKERASTUNER_ORACLE_PORT,示例如下(bash 脚本):

export KERASTUNER_TUNER_ID="chief"
export KERASTUNER_ORACLE_IP="127.0.0.1"
export KERASTUNER_ORACLE_PORT="8000"
python run_my_search.py

所有调优器会通过一个中央的 “预言机”(Oracle)服务协同完成搜索,该服务会为每个调优器分配下一个待尝试的超参数取值。更多相关信息可查阅官方文档。

自定义训练循环

通过继承kerastuner.Tuner基类,可实现各类高级用法,例如:

  • 自定义训练循环(生成对抗网络 GAN、强化学习等场景)
  • 在模型构建函数外添加超参数(数据预处理、数据增强、测试时增强等环节)

以下是一个简单的示例:

class MyTuner(kt.Tuner):
    def run_trial(self, trial, ...):
        # 根据超参数配置构建模型
        model = self.hypermodel.build(trial.hyperparameters)
        score = …  # 运行自定义训练循环并返回评估分数
        # 更新试验结果
        self.oracle.update_trial(trial.trial_id, {'score': score})
        # 保存当前模型
        self.oracle.save_model(trial.trial_id, model)

调优 Scikit-learn 模型

尽管命名中带有 “Keras”,但 Keras Tuner 可用于调优各类机器学习模型。除了为 Keras 模型设计的内置调优器外,它还提供了适配 Scikit-learn 模型的专属调优器,使用示例如下:

from sklearn import ensemble
from sklearn import linear_model

def build_model(hp):
    # 选择模型类型:随机森林或岭回归分类器
    model_type = hp.Choice('model_type', ['random_forest', 'ridge'])
    if model_type == 'random_forest':
        # 随机森林专属超参数作用域
        with hp.conditional_scope('model_type', 'random_forest'):
            model = ensemble.RandomForestClassifier(
                n_estimators=hp.Int('n_estimators', 10, 50, step=10),
                max_depth=hp.Int('max_depth', 3, 10))
    elif model_type == 'ridge':
        # 岭回归专属超参数作用域
        with hp.conditional_scope('model_type', 'ridge'):
            model = linear_model.RidgeClassifier(
                alpha=hp.Float('alpha', 1e-3, 1, sampling='log'))
    else:
        raise ValueError('Unrecognized model_type')
    return model

# 实例化Scikit-learn调优器,使用贝叶斯优化算法
tuner = kt.tuners.Sklearn(
        oracle=kt.oracles.BayesianOptimization(
            objective=kt.Objective('score', 'max'),  # 优化目标:最大化评估分数
            max_trials=10),                          # 最大试验次数
        hypermodel=build_model,
        directory=tmp_dir)  # 模型保存目录
X, y = ...  # 加载特征数据和标签数据
tuner.search(X, y)  # 启动超参数搜索

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐