本文正在参与「金石方案 . 分割6万现金大奖」

前言

本文运用 cpu 版本的 tensorflow 2.4 ,选用 Keras Tuner 东西以 Fashion 数据集的分类任务为例,完结最优超参数的快速挑选任务。

当咱们建立完结深度学习模型结构之后,咱们在练习模型的进程中,有很大一部分工作主要是通过验证集评价指标,来不断调节模型的超参数,这是比较耗时耗力的,如果只是不计价值为找到模型最优的超参数组合,咱们大能够运用暴力穷举,把所有超参数都调配组合试用一遍,肯定能找到一组最优的超参数成果。可是现实情况是咱们不仅要考虑时刻本钱,还要考虑计算本钱等要素,而 Tuner 东西包可协助咱们省时省力做这件工作,为咱们的 TensorFlow 程序挑选最佳的超参数集,整个这一找最佳超参数集的进程称为超参数调节或超调。

咱们要知道超参数有两种类型:

  • 模型超参:也便是能够影响模型的架构参数,例如神经元个数等
  • 算法超参:也便是能够影响模型学习算法参数,例如学习率和 epoch 等

本文纲要

  1. 获取 MNIST 数据并进行处理
  2. 建立超模型结构
  3. 实例化调节器并进行模型超调
  4. 练习模型取得最佳 epoch
  5. 运用最有超参数集进行模型练习和评价

实现进程

1. 获取 MNIST 数据并进行处理

(1)首先咱们要确保 tensorflow 不低于 2.4.0 ,python 不低于 3.8 ,不然无法运用 keras-tuner ,然后运用 pip 装置 keras-tuner 运用即可。

(2)运用 tensorflow 的内置函数从网络获取 Fashion 数据集 。

(3)将整个数据集做归一化操作,加速模型练习的收敛。

import tensorflow as tf
from tensorflow import keras
import keras_tuner as kt
(train_img, train_label), (test_img, test_label) = keras.datasets.fashion_mnist.load_data()
train_img = train_img.astype('float32') / 255.0
test_img = test_img.astype('float32') / 255.0

2. 建立超模型

(1)这儿主要是定义超模型,在构建用于超调的模型时,除了定义模型结构之外,还要定义超参的可选范围,这种为超调建立的模型称为超模型。

(2)第一层是将每张图片的输入从二维压缩成一维。

(3)第二层是输出一个维度为 units 的全衔接层,units 是咱们的神经元个数挑选器,咱们规则了从 16-256 中随机挑选一个可用的整数来进行模型的练习,整数挑选的步长为 32 ,并最终能确定一个使得模型能到达最好作用的神经元个数,而且运用了激活函数 relu 来进行非线性变换。

(4)第三层是一个输出 10 个维度向量的全衔接层,也便是输出该图片属于这 10 个类别的概率散布。

(5)学习率也是一个需要不断调整的超参数,所以咱们运用 learning_rate 作为咱们优化器学习率的挑选器,从 [1e-2, 1e-3, 1e-4] 中挑选能使模型到达最好作用的那个。

(6)编译模型的时候咱们挑选了最常用的 Adam 优化器,其学习率便是用咱们刚才定义好的 learning_rate ,一会在模型学习的进程中会不断随机挑选一个学习率。

(7)丢失函数挑选常见的 SparseCategoricalCrossentropy 。

(8)评价指标挑选最简略的准确率 accuracy 。

def model_builder(hp):
    model = keras.Sequential()
    model.add(keras.layers.Flatten(input_shape=(28, 28)))
    units = hp.Int('units', min_value=16, max_value=256, step=32)
    model.add(keras.layers.Dense(units=units, activation='relu'))
    model.add(keras.layers.Dense(10))
    learning_rate = hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])
    model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate),
                loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                metrics=['accuracy'])
    return model

3. 实例化调节器并进行模型超调

(1)Tuner 中常见的调节器包含:RandomSearch、Hyperband、BayesianOptimization 和 Sklearn。在本文中咱们运用 Hyperband 调节器来完结超参数的挑选。

(2)咱们知道现实中将所有的超参数进行调配能够形成很多组,这个组数越多,那么最优超参数组合呈现的概率也越大,可是与此相悖的是组数越多,在有限资源的情况下,能对每一组超参数进行测验的资源就越少,找到最优组的概率会下降, Hyperband 由此而生,Hyperband 便是假定尽可能呈现多的超参数组,而且每组所能得到的资源要尽可能多,从而确保尽可能找到有最优超参数的那个组。

(3)在实际超调进程中,Hyperband 会假定 n 组超参数组合,然后对这 n 组超参数均匀地分配预算并进行验证评价,依据验证成果淘汰一半表现差的超参数组,不断重复上述进程直到找到一个最优超参数组合。

(4)调用函数 Hyperband 将调节器进行实例化,咱们需要传入超模型、练习目标和最大的练习 epoch 。

(5)为了练习进程中避免过拟合现象,咱们还加入了 EarlyStopping ,当通过 3 次 epoch 都没有优化之后会停止模型练习。

(6)这儿便是运用超调实例 tuner 在模型练习进程中,通过调用 model_builder 函数不断地在 units 、learning_rate 中运用适宜的超参构建新模型,并运用练习集为新模型练习 10 个 epoch ,最终选用练习集 20% 比例的验证集,记录下每个装备下的模型在验证集上表现出的评价指标 val_accuracy 。

(7)当超调结束之后,咱们回来最好的超参选用成果 best_hps 。

tuner = kt.Hyperband(model_builder, objective='val_accuracy', max_epochs=10)
stop_early = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=3)
tuner.search(train_img, train_label, epochs=10, validation_split=0.2, callbacks=[stop_early])
best_hps=tuner.get_best_hyperparameters(num_trials=1)[0]
print(f"""超调结束, 第一层全衔接层的神经元个数主张选为 {best_hps.get('units')} ,优化器学习率主张选为 {best_hps.get('learning_rate')}.""")

输出成果为:

Trial 30 Complete [00h 00m 15s]
val_accuracy: 0.8845000267028809
Best val_accuracy So Far: 0.8864166736602783
Total elapsed time: 00h 03m 04s
INFO:tensorflow:Oracle triggered exit
超调结束, 第一层全衔接层的神经元个数主张选为176 ,优化器学习率主张选为0.001.

4. 练习模型取得最佳 epoch

(1)咱们已经通过 tuner 取得了最优的超参数,接下来咱们只需要用最优的超参数构建模型,然后运用练习数据对模型进行练习 30 个 epoch 即可,而且运用练习数据的 20% 作为验证集对模型进行作用评价。

(2)咱们能够将通过验证集评价得到的每个 epoch 发生的 val_accuracy 都取出来,然后挑选其间最大的那个 epoch ,说明当通过 14 次 epoch 就能够到达最佳的模型作用

model = tuner.hypermodel.build(best_hps)
history = model.fit(img_train, label_train, epochs=30, validation_split=0.2)
val_acc_per_epoch = history.history['val_accuracy']
best_epoch = val_acc_per_epoch.index(max(val_acc_per_epoch)) + 1
print('发生最好的 val_accuracy 是在第 %d 个 epoch ' % (best_epoch,))

输出为:

Epoch 1/30
1500/1500 [==============================] - 2s 1ms/step - loss: 0.6338 - accuracy: 0.7770 - val_loss: 0.4494 - val_accuracy: 0.8401
Epoch 2/30
1500/1500 [==============================] - 1s 938us/step - loss: 0.3950 - accuracy: 0.8575 - val_loss: 0.3971 - val_accuracy: 0.8497
...
Epoch 14/30
1500/1500 [==============================] - 2s 1ms/step - loss: 0.2027 - accuracy: 0.9229 - val_loss: 0.3150 - val_accuracy: 0.8943
Epoch 15/30
1500/1500 [==============================] - 1s 985us/step - loss: 0.1951 - accuracy: 0.9280 - val_loss: 0.3200 - val_accuracy: 0.8912
...
Epoch 29/30
1500/1500 [==============================] - 1s 906us/step - loss: 0.1298 - accuracy: 0.9517 - val_loss: 0.3939 - val_accuracy: 0.8902
Epoch 30/30
1500/1500 [==============================] - 1s 951us/step - loss: 0.1194 - accuracy: 0.9561 - val_loss: 0.4027 - val_accuracy: 0.8904
发生最好的 val_accuracy 是在第 14  epoch 

5. 运用最有超参数集进行模型练习和评价

(1) 通过上面的进程咱们已经找到了最好的神经元个数、学习率、以及练习模型的 epoch ,接下来运用这些超参重新实例化新的模型并运用上面的 best_epoch 对其进行练习,仍然挑选练习集的 20% 作为验证集对模型作用进行验证 。

best_model = tuner.hypermodel.build(best_hps)
best_model.fit(img_train, label_train, epochs=best_epoch, validation_split=0.2)

(2)咱们运用测验集堆模型进行评价。

eval_result = best_model.evaluate(test_img, test_label)
print("测验集丢失值 %f , 测验集准确率为 %f"% (eval_result[0], eval_result[1]))

输出成果为:

测验集丢失值 0.345943 , 测验集准确率为 0.889400