本文不仅向您展示如何调整神经网络的超参数,还将通过FAIR的Hiplot直观地查看调整过程/训练过程。
导入Python依赖
!pip install hiplotimport tensorflow as tfimport hiplot as hip
准备数据
我们将使用Fashion MNIST机器学习数据集
# download datamnist = tf.keras.datasets.fashion_mnist(x_train, y_train), (x_test, y_test) = mnist.load_data()# define the input shape and normalise datax_train=x_train.reshape(60000, 28, 28, 1)x_train=x_train / 255.0x_test = x_test.reshape(10000, 28, 28, 1)x_test=x_test/255.0
定义我们的神经网络模型
我们将构建一个简单的模型,其中包含几个卷积层,最大池化层,dropout和dropout层
model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(64, (3,3), activation=’relu’, input_shape=(28, 28, 1)), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Dropout(0.5), tf.keras.layers.Conv2D(64, (3,3), activation=’relu’), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Dropout(0.5), tf.keras.layers.Flatten(), tf.keras.layers.Dense(128, activation=’relu’), tf.keras.layers.Dense(10, activation=’softmax’) ])
我们可以编译我们的模型并打印它的摘要
model.compile(optimizer=’adam’, loss=’sparse_categorical_crossentropy’, metrics=[‘accuracy’])# model.summary()
我们可以绘制刚刚定义的神经网络模型的结构:
一旦编译完成,就可以对模型进行训练和评估。我们声明一个变量,它将用于提取历史训练数据
num_epochs = 20history = model.fit(training_images, training_labels, epochs=num_epochs, validation_split=0.2 )model.evaluate(x_test, y_test)
我们的模型配置非常简单,在测试集中显示了90.7%的准确率。
现在让我们进行一些可视化。当在Jupyter笔记本中运行时,Hiplot要求其输入数据采用python字典的形式,因此我们可以使用列表来解析历史数据并将其绘制出来。
import hiplot as hipdata = [{'epoch': idx, 'loss': history.history['loss'][idx], 'val_loss': history.history['val_loss'][idx], 'accuracy': history.history['accuracy'][idx], 'val_accuracy': history.history['val_accuracy'][idx]} for idx in range(num_epochs)]hip.Experiment.from_iterable(data).display()
我们可以在一个位置查看损失,指标值及其关系,从而看到我们的模型在每个epoch的表现如何。
!pip install keras-tunerfrom kerastuner import HyperModelfrom kerastuner.tuners import RandomSearch
首先,我们需要为每个需要调整的参数定义模型和搜索空间。您可以使用build_model函数或我们将要执行的HyperModel类来执行此操作:
class CNNHyperModel(HyperModel): def __init__(self, input_shape, num_classes): self.input_shape = input_shape self.num_classes = num_classes def build(self, hp): model = tf.keras.Sequential() model.add( tf.keras.layers.Conv2D( filters=hp.Choice( 'num_filters_1', values=[32, 64, 128], default=64, ), kernel_size=3, activation='relu', input_shape=self.input_shape ) ) model.add(tf.keras.layers.MaxPooling2D(pool_size=2)) model.add( tf.keras.layers.Dropout( rate=hp.Float( 'dropout_1', min_value=0.0, max_value=0.5, default=0.25, step=0.05 ) ) ) model.add( tf.keras.layers.Conv2D( filters=hp.Choice( 'num_filters_2', values=[32, 64, 128], default=64, ), activation='relu', kernel_size=3 ) ) model.add(tf.keras.layers.MaxPooling2D(pool_size=2)) model.add( tf.keras.layers.Dropout( rate=hp.Float( 'dropout_2', min_value=0.0, max_value=0.5, default=0.25, step=0.05 ) ) ) model.add(tf.keras.layers.Flatten()) model.add( tf.keras.layers.Dense( units=hp.Int( 'units', min_value=32, max_value=512, step=32, default=128 ), activation=hp.Choice( 'dense_activation', values=['relu', 'tanh', 'sigmoid'], default='relu' ) ) ) model.add(tf.keras.layers.Dense(self.num_classes, activation='softmax')) model.compile( optimizer=tf.keras.optimizers.Adam( hp.Float( 'learning_rate', min_value=1e-4, max_value=1e-2, sampling='LOG', default=1e-3 ) ), loss='sparse_categorical_crossentropy', metrics=['accuracy'] ) return modelhypermodel = CNNHyperModel(input_shape=(28, 28, 1), num_classes=10)
我们必须以这种方式描述每个层,指定要调优的参数、搜索空间和默认值。
为了搜索超参数值的不同组合,我们将使用RandomSearch类。其背后的思想是从搜索空间中随机迭代采样值,训练模型并测试它们的性能,以选择最佳组合。
这是超参数调优的几个参数:
max_epochs :训练模型的最大epochs数max_trials:最多测试的试验总数(模型配置)PROJECT_NAME:用于可视化的数据将被保存到的文件夹的名称
from kerastuner.tuners import RandomSearchtuner = RandomSearch( hypermodel, objective='val_accuracy', seed=42, max_trials=20, directory='random_search', project_name='fashion_mnist')
您可以调用tuner.search_space_summary()来查看您的tuner所拥有的搜索空间。
对于我们的优化器来说,在训练期间使用early stopping来减少搜索时间是完全有意义的(例如,通过回调)。
callback = tf.keras.callbacks.EarlyStopping(monitor=’val_loss’, patience=3)tuner.search(training_images, training_labels, epochs=num_of_epochs, validation_split=0.2, callbacks=[callback])tuner.results_summary()
让我们提取我们拥有的最佳模型,在测试集中评估它的结果,看看调优是否有不同:
best_model = tuner.get_best_models(num_models=1)[0]best_model.evaluate(x_test, y_test)
尽管调谐器的搜索参数很弱,但在测试集上它使我们模型的精度提高到91.4%。考虑到Keras Tuner具有更高级的搜索算法,建议您设置一些搜索参数“在资源预算范围内尽可能高的值”,因此这种改进并不是您能获得的最佳效果,因此我认为这将是一个不错的工具进入您的武器库。
RandomSearch是其他优化器在您的项目目录中创建的一个文件夹,它将保存带有搜索历史数据的JSON文件,我们将对这些数据进行可视化处理。我们所需要做的就是解析所有这些文件并生成一个带有数据的字典。
import osimport jsonvis_data = []rootdir = 'random_search/fashion_mnist'for subdirs, dirs, files in os.walk(rootdir): for file in files: if file.endswith("trial.json"): with open(subdirs + '/' + file, 'r') as json_file: data = json_file.read() vis_data.append(json.loads(data))import hiplot as hipdata = [{'num_filters_1': vis_data[idx]['hyperparameters']['values']['num_filters_1'], 'num_filters_2': vis_data[idx]['hyperparameters']['values']['num_filters_2'], 'units': vis_data[idx]['hyperparameters']['values']['units'], 'dense_activation': vis_data[idx]['hyperparameters']['values']['dense_activation'], 'learning_rate': vis_data[idx]['hyperparameters']['values']['learning_rate'], 'loss': vis_data[idx]['metrics']['metrics']['loss']['observations'][0]['value'], 'val_loss': vis_data[idx]['metrics']['metrics']['val_loss']['observations'][0]['value'], 'accuracy': vis_data[idx]['metrics']['metrics']['accuracy']['observations'][0]['value'], 'val_accuracy': vis_data[idx]['metrics']['metrics']['val_accuracy']['observations'][0]['value'] } for idx in range(num_of_epochs)]hip.Experiment.from_iterable(data).display()
这些信息可以帮助您了解哪些参数最容易影响准确性