我正在阅读有关keras-team.github.io(link)上的自定义训练循环的调谐器子类化教程。
在端到端的示例中,我不明白为什么要对优化器进行两次定义。
进入build_model
函数后:
optimizer = hp.Choice('optimizer', ['adam', 'sgd'])
model.compile(optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
return model
这对我来说很有意义,但是随后在trial_run
内又定义了一个优化器:
lr = hp.Float('learning_rate', 1e-4, 1e-2, sampling='log', default=1e-3)
optimizer = tf.keras.optimizers.Adam(lr)
然后在run_train_step
with tf.GradientTape() as tape:
# calculate loss, gradients
...
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
这是否意味着永远不会使用build_model
中为优化程序定义的超参数?以我对示例的理解方式,在apply_gradients
内部用于run_train_step
的优化器始终是Adam
,具有不同的学习率,但从来没有SGD
。
我在这里想错了吗?
我目前正在做的只是在建立模型后在run_trial
中获得相应的优化器:
def run_trial(self, trial, *fit_args, **fit_kwargs):
...
model = self.hypermodel.build(trial.hyperparameters)
optimizer = model.optimizer
...
本教程让我感到困惑,无论我在做什么,都对此感到满意,对此我很高兴。
编辑:我刚刚意识到设置学习率超参数也是一个问题。由于模型已经编译,因此在run_trial
期间无法轻松设置它。在此hp.Choice
之上仅返回一个字符串,因此我必须将优化器字符串映射到实际的优化器函数:
optimizer_str_to_func = {
"sgd": tf.keras.optimizers.SGD,
"adam": tf.keras.optimizers.Adam,
"rmsprop": tf.keras.optimizers.RMSprop
}
def build_model(hp):
num_res_blocks = hp.Int("res_blocks", 8, 32, step=8, default=16)
model = MyModel(num_res_blocks=num_res_blocks)
learning_rate = hp.Float("learning_rate", 1e-4, 1e-2, sampling="log", default=1e-3)
optimizer_name = hp.Choice("optimizer", ["adam", "sgd", "rmsprop"])
optimizer = optimizer_str_to_func[optimizer_name](lr=learning_rate)
model.compile(optimizer, loss="mse")
return model
我觉得这很不对劲。