本文主要介绍了使用Keras Tuner进行超参数自动调优的示例,还介绍了一些高级用法,包括分布式调优,自定义调优模型等等。如果想了解Keras Tuner的安装和基本用法请参考第一篇博客。
周大侠:Keras-Tuner:适用于TensorFlow 2.0和keras的超参数调优器zhuanlan.zhihu.com此文主要翻译于TensorFlow的官方Blog,同时也补充了些个人注释。
Hyperparameter tuning with Keras Tunerblog.tensorflow.org一个机器学习项目的成功通常都严重依赖于好的超参数的选择。随着机器学习已经发展成一个领域的不断成熟,仅仅依靠反复尝试和试错(trial and error)来为这些超参数找到较优的值是不合适的。事实上,如今许多效果最好的算法如EfficientNet,是通过复杂的超参数优化算法发现的。
Keras Tuner 是一个易于使用、可分布式的超参数优化框架,用于解决执行超参数搜索的痛点。Keras Tuner可以很容易地定义搜索空间,并利用所包含的算法来查找最佳超参数值。 Keras Tuner内置了贝叶斯优化(Bayesian Optimization)、Hyperband和随机搜索(Random Search)算法,同时也便于研究人员扩展,进行新搜索算法的试验。
下面将介绍一个简单的端到端的示例。首先,定义一个model-building
函数,通过该函数中的参数hp
进行超参数的定义,例如:
hp.Int('units', min_value=32, max_value=512, step=32) #该句定义了一个范围内的整数
请注意查看如何在model-building
函数中定义超参数,下面的示例将创建一个简单的可调(tunable)模型,其训练使用的数据是CIFAR-10 :
import tensorflow as tf
def build_model(hp):
inputs = tf.keras.Input(shape=(32, 32, 3)) #模型输入 RGB图片
x = inputs
for i in range(hp.Int('conv_blocks', 3, 5, default=3)): # 调优卷积层数
filters = hp.Int('filters_' + str(i), 32, 256, step=32) # 调优filters数量
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': #调优pooling函数
x = tf.keras.layers.MaxPool2D()(x)
else:
x = tf.keras.layers.AvgPool2D()(x)
x = tf.keras.layers.GlobalAvgPool2D()(x)
x = tf.keras.layers.Dense(
hp.Int('hidden_size', 30, 100, step=10, default=50),
activation='relu')(x) #调优隐含层大小
x = tf.keras.layers.Dropout(
hp.Float('dropout', 0, 0.5, step=0.1, default=0.5))(x) #调优dropout大小
outputs = tf.keras.layers.Dense(10, activation='softmax')(x)
model = tf.keras.Model(inputs, outputs)
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
#返回一个构建好的模型(compiled model,指整体模型结构已经搭好,包括损失函数的定义等等,但模型还未经过训练)
下一步,实例化(instantiate)一个tuner。首先应该指定model-building函数,需要要优化的目标的名称(其中优化目标是最小化还是最大化是根据内置metrics自动推断出来的,或者可以通过kerastuner.Objective
class 使用自定义的metric )。在本示例中,Keras tuner使用Hyperband算法用于超参搜索:
import kerastuner as kt
tuner = kt.Hyperband(
build_model,
objective='val_accuracy',
max_epochs=30,
hyperband_iterations=2)
接下来通过TensorFlow Datasets 下载CIFAR-10数据集,然后调用search
方法进行超参搜索。search
方法与keras.model.fit
具有相同的参数(signature):
import tensorflow_datasets as tfds
data = tfds.load('cifar10')
train_ds, test_ds = data['train'], data['test']
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个epochs,以及Hyperband会迭代2次(在你的算力允许下,越多越好)。随后通过使用get_best_models
函数得到搜索期间的最佳模型:
best_model = tuner.get_best_models(1)[0]
还可以查看通过搜索找到的最佳超参数值:
best_hyperparameters = tuner.get_best_hyperparameters(1)[0]
至此就是执行复杂的超参数搜索所需的全部代码! 完整代码在此。
除了上述允许定义自己的可调模型之外,Keras Tuner 提供2个内置的可调模型:HyperResnet 和 HyperXception。这两个模型分别会搜索HyperResnet 和 HyperXception的各种参数组合,通过配合Tuner
一起使用:
tuner = kt.tuners.BayesianOptimization(
kt.applications.HyperResNet(input_shape=(256, 256, 3), classes=10),
objective='val_accuracy',
max_trials=50)
当使用Keras Tuner,可以同时进行数据并行和试验并行的分布式(both data-parallel and trial-parallel distribution)。即可以使用tf.distribute.Strategy
在多个GPUs上运行模型;还可以在不同的worker上并行地搜索多个不同的超参数组合。
执行并行试验不需要修改原来的搜索代码,仅仅需要设置the KERASTUNER_TUNER_ID
, KERASTUNER_ORACLE_IP
, 以及 KERASTUNER_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
所有的tuner通过一个中央Oracle
服务器来协调它们的参数搜索,该服务器分发每个tuner接下来尝试哪个超参数值。更多的细节请参考 Distributed Tuning guide。
你可以自定义 kerastuner.Tuner
类的子类(subclass)来支持更高级的用法:
下面是一个简单的例子,更多细节请参考Tuner Subclassing guide.
class MyTuner(kt.Tuner):
def run_trial(self, trial, ...):
model = self.hypermodel.build(trial.hyperparameters)
score = … # Run the training loop and return the result.
self.oracle.update_trial(trial.trial_id, {
'score': score})
self.oracle.save_model(trial.trial_id, model)
尽管其名字叫Keras Tuner,但它可以用来调优各种机器学习模型。除了内置用于Keras模型的tuner外,Keras Tuner还提供了一个能用于Scikit-learn模型的内置Tuner。下面是如何使用的一个简单示例:
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
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)
所以只要你封装得好,Keras Tuner还能调优Pytorch(手动滑稽)!具体可以参考官方如何实现对Scikit-learn模型调优的源码。
最后,又发现了一个TensorFlow最新发布的Keras Tuner Tutorial,包含了另一个简单却完整的示例,链接如下:
Keras Tuner简介 | TensorFlow Coretensorflow.google.cn