W&Bを使用したKerasチューナー
概要
Kaggle Notebookを確認
人工ニューラルネットワークは、これまでの多くの制約条件、ウエイトおよびバイアスで構成されています。このような制約条件、つまりニューロン数や非線形活性化関数、レイヤー数は、一般的に「ハイパーパラメータ」と呼ばれます。このハイパーパラメータの最適化について広大な研究が行われています。これは人々が、ウエイトとバイアスだけでなく、ハイパーパラメータのノブを回すことにも興味があることを意味します。すでに、この分野には、いくつかの優れたアプローチ(グリッド、ランダム、ベイジアンなど)があります。
深層学習の実験には、適切なハイパーパラメータの選択に多くの時間が費やされています。適切なハイパーパラメータの選択は、実験のゲームチェンジャーになる場合があります。このトピックは広く研究されています。そしてさまざまな検索アルゴリズムの出現によってハイパーパラメータが自動チューニングできるようになっています。ハイパーパラメータのスペースを自動検索でチューニングするという概念は、手動でそれを行っていたDL研究者の時間短縮に役立ちます。
この記事では、ハイパーパラメータ・チューニングの自動化に役立つツールの1つ「keras-tuner」について説明します。ツールの基本を理解するだけでなく、私たちがよく使っているお気に入りの実験トラッカー「wandb」と統合してみます。
以下について説明します。
- keras-tunerのAPI
- wandbの統合コード
- スイープの一部の紹介
- 終わりに
keras-tunerのAPI
kerasチームは、ツールのAPIデザインに常に多大な労力を費やしています。そのツールは、同様の思考プロセスから逸脱することはありません。
このAPIが提供する基本インターフェースは4つあり、APIの最も重要な部分となっています。
- HyperParameters: このクラスはハイパーパラメータのコンテナとして機能します。このクラスのインスタンスには、現在のハイパーパラメータおよび検索スペースの合計に関する情報が含まれています。
- Hypermodel: このクラスのインスタンスは、ハイパーパラメータのスペース全体をモデル化するオブジェクトと考えることができます。このインスタンスは、スペースを構築するだけでなく、ハイパーパラメータからサンプリングするDLモデルも構築します。
- Oracles: このクラスの各インスタンスは、特定のハイパーパラメータ・チューニングのアルゴリズムを実装しています。
- Tuners: ハイパーパラメータのチューニングを行います。Oracleは、Tunerに引数として渡されます。渡されたOracleは、どのハイパーパラメータを次に試行する必要があるかをTunerに通知します。
API設計へのトップダウンアプローチにより、APIを読みやすく、理解しやすくできます。次のようにすべてを繰り返します:
-
HyperParametersオブジェクトを作成する。
-
HyperParametersをHypermodelに渡す。Hypermodelは検索スペースを構築できる。
-
チューニングアルゴリズムを提供するOraclesを構築する。
-
Oraclesに従ってハイパーパラメータをチューニングするTunersを構築する。
keras-tunerを使用したコード
このセクションでは、keras-tunerの基本的な使用法を例で説明します。この例は、こちらのドキュメントから抜粋したものです。
チューナーを実行するために必要なインポートとは別に、最初に検索スペース全体をエミュレートするHypermodelを構築する必要があります。
ハイパーモデルは2つの方法で構築できます。
- 関数によるモデル構築
- Hypermodelクラスのサブクラス
関数
ここでは、HyperParametersを引数として取る関数を作成します。関数はHyperParametersからサンプリングし、モデルを構築して返します。このようにして、検索スペースからさまざまなモデルが作成されます
# build with function
def build_model(hp):
model = keras.Sequential()
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=keras.optimizers.Adam(
hp.Choice('learning_rate',
values=[1e-2, 1e-3, 1e-4])),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
Hypermodelクラスのサブクラス化
このメソッドは、build()メソッドをオーバーライドする必要があります。build()メソッドで、ユーザーはHyperParametersからサンプリングして、適切なモデルを構築できます。
# build with inheritance
class MyHyperModel(HyperModel):
def __init__(self, num_classes):
self.num_classes = num_classes
def build(self, hp):
model = keras.Sequential()
model.add(layers.Dense(units=hp.Int('units',
min_value=32,
max_value=512,
step=32),
activation='relu'))
model.add(layers.Dense(self.num_classes, activation='softmax'))
model.compile(
optimizer=keras.optimizers.Adam(
hp.Choice('learning_rate',
values=[1e-2, 1e-3, 1e-4])),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
どちらの場合も、HypermodelはHyperParametersの提供で作成されます。興味のある方は、ハイパーパラメータがサンプリングされる方法を調べることをお勧めします。このパッケージは、静的オプションだけでなく、条件付きハイパーパラメータも提供します。
Hypermodelの準備ができたら、Tunerを作成します。Tunerはハイパーパラメータスペースを検索し、最適化されたハイパーパラメータのセットを提供します。以下に、両方のHypermodel設定のチューナーを記述しました。
# tuner for function
tuner = RandomSearch(
build_model,
objective='val_accuracy',
max_trials=5,
executions_per_trial=3,
directory='my_dir',
project_name='helloworld')
# tuner for subclass
hypermodel = MyHyperModel(num_classes=10)
tuner = RandomSearch(
hypermodel,
objective='val_accuracy',
max_trials=10,
directory='my_dir',
project_name='helloworld')
注:カスタムTunerでは、検索アルゴリズムでチューナーを支援する Oracleをチューナーに渡す必要があります。 すべて設定されたら、検索を実行できます。search 方法は、fit メソッドと同じデザインに従います。search後、チューナーに最適なモデルとハイパーパラメータを照会できます。
tuner.search(x, y,
epochs=5,
validation_data=(val_x, val_y))
keras-tunerをwandbと統合するコード
Kaggle Notebookを確認
keras-tunerと一緒にすべてのモデルを1か所で追跡できれば、どれほど素晴らしいでしょう。ここでは、wandbをkeras-tunerと統合して、作成および検索されたすべてのモデルを追跡できるようにします。これによって、最良のモデルを取得するのに役立つだけでなく、価値あるインサイトも得られます。
このセクションでは、変更したkeras-tinerサブクラス化のコードを実行します。
Hypermodel
ここでは、Hypermodelを構築するにあたって機能的な方法を採用しています。これは、モデルを構築するための非常に簡単な方法として機能します。
この例では、条件付きハイパーパラメータの使用法が実装されていることがわかります。調整可能な数のconv_layersを作成するforループがあり、それ自体が調整可能なfiltersとkernel_sizeパラメーターを含みます。
def build_model(hp):
"""
Builds a convolutional model.
Args:
hp: Hyperparamet object, This is the object that helps
us sample hyperparameter for a particular trial.
Returns:
model: Keras model, Returns a keras model.
"""
inputs = tf.keras.Input(shape=(28, 28, 1))
x = inputs
# In this example we also get to look at
# conditional heyperparameter settings.
# Here the `kernel_size` is conditioned
# with the for loop counter.
for i in range(hp.Int('conv_layers', 1, 3)):
x = tf.keras.layers.Conv2D(
filters=hp.Int('filters_' + str(i), 4, 32, step=4, default=8),
kernel_size=hp.Int('kernel_size_' + str(i), 3, 5),
activation='relu',
padding='same')(x)
# choosing between max pool and avg pool
if hp.Choice('pooling' + str(i), ['max', 'avg']) == 'max':
x = tf.keras.layers.MaxPooling2D()(x)
else:
x = tf.keras.layers.AveragePooling2D()(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.ReLU()(x)
if hp.Choice('global_pooling', ['max', 'avg']) == 'max':
x = tf.keras.layers.GlobalMaxPooling2D()(x)
else:
x = tf.keras.layers.GlobalAveragePooling2D()(x)
outputs = tf.keras.layers.Dense(10, activation='softmax')(x)
model = tf.keras.Model(inputs, outputs)
return model
Tuner
wandbでチューナーを統合してconfig とlossをログに記録するのは、簡単でした。APIは、kt.Tunerクラスのrun_trialメソッドをオーバーライドするユーザーを提供します。run_trialメソッドでは、HyperParametersオブジェクトを利用できます。これは、wandb実行のコンフィギュレーションに現在のハイパーパラメータをクエリするために使用されます。これは、モデルのメトリックをログに記録できるようになっただけでなく、wandbがダッシュボードに提供している優れたウィジェットを使用してハイパーパラメータを比較できることを意味します。
class MyTuner(kt.Tuner):
"""
Custom Tuner subclassed from `kt.Tuner`
"""
def run_trial(self, trial, train_ds):
"""
The overridden `run_trial` function
Args:
trial: The trial object that holds information for the
current trial.
train_ds: The training data.
"""
hp = trial.hyperparameters
# Batching the data
train_ds = train_ds.batch(
hp.Int('batch_size', 32, 128, step=32, default=64))
# The models that are created
model = self.hypermodel.build(trial.hyperparameters)
# Learning rate for the optimizer
lr = hp.Float('learning_rate', 1e-4, 1e-2, sampling='log', default=1e-3)
if hp.Choice('optimizer', ['adam', 'sgd']) == 'adam':
optimizer = tf.keras.optimizers.Adam(lr)
else:
optimizer = tf.keras.optimizers.SGD(lr)
epoch_loss_metric = tf.keras.metrics.Mean()
# build the train_step
@tf.function
def run_train_step(data):
"""
The run step
Args:
data: the data that needs to be fit
Returns:
loss: Returns the loss for the present batch
"""
images = tf.dtypes.cast(data['image'], 'float32') / 255.
labels = data['label']
with tf.GradientTape() as tape:
logits = model(images)
loss = tf.keras.losses.sparse_categorical_crossentropy(
labels, logits)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
epoch_loss_metric.update_state(loss)
return loss
# WANDB INITIALIZATION
# Here we pass the configuration so that
# the runs are tagged with the hyperparams
# This also directly means that we can
# use the different comparison UI widgets in the
# wandb dashboard off the shelf.
run = wandb.init(entity='ariG23498', project='keras-tuner', config=hp.values)
for epoch in range(10):
self.on_epoch_begin(trial, model, epoch, logs={})
for batch, data in enumerate(train_ds):
self.on_batch_begin(trial, model, batch, logs={})
batch_loss = run_train_step(data)
self.on_batch_end(trial, model, batch, logs={'loss': batch_loss})
if batch % 100 == 0:
loss = epoch_loss_metric.result().numpy()
# Log the batch loss for WANDB
run.log({f'e{epoch}_batch_loss':loss})
# Epoch loss logic
epoch_loss = epoch_loss_metric.result().numpy()
# Log the epoch loss for WANDB
run.log({'epoch_loss':epoch_loss, 'epoch':epoch})
# `on_epoch_end` has to be called so that
# we can send the logs to the `oracle` which handles the
# tuning.
self.on_epoch_end(trial, model, epoch, logs={'loss': epoch_loss})
epoch_loss_metric.reset_states()
# Finish the wandb run
run.finish()
終わりに
読者のみなさんに、ご自身で素晴らしいツールを今すぐお試しいただくことをお勧めします。今後の参考のためにkeras-tunerのす
ハイパーパラメータ・チューニングの研究は非常に広範囲に行われています。人々は遺伝的アルゴリズムも取り入れ、生物に似たモデルを進化させるコンセプトを使用しました。少し厚かましい事ですが、これに興味を持った読者のみなさんは、私の記事のひとつである遺伝的アルゴリズムを使用したハイパーパラメータ調整の概念の分析を、このリンクからご覧いただければ幸いです。
ご連絡はTwitter @ariG23498にお願いいたします。