训练超模型

超模型

对于初级炼丹师,往往苦于调参。那么有没有什么高科技炼丹炉,可以让我们只要按下按钮,就可以自行调整,炼出一炉品质上佳的仙丹呢?
那肯定是有的,下面,请允许我隆重介绍KerasTuner。在下面的例子里,将使用KerasTuner进行超参数搜索,从现在开始,你炼的模型就是超模型啦~
KerasTuner并没有限制我们的操作空间,它仍允许我们进行大量自定义。当然,它也是十分便利的,我们只要简单的设定一下搜索空间,就可以去摸鱼了。不过,你的显卡就要替你受罪了。训练超模型需要的算力较大,所以,没GPU的同学不建议使用。

在我们开始之前,先给出其官方文档:
KerasTuner
这会有助于理解代码。

简单例子

下面先来一个简单的超模型

模型定义

这里继承父类keras_tuner.HyperModel,我们需要编写其中的build方法与fit方法。其中为了将模型定义与超参数分离开,编写了一个model方法,这样有助于提高代码的条理性与可读性。

from tensorflow import keras
import keras_tuner

class HyperModel(keras_tuner.HyperModel):
    def model(self,units,num_layers,lr):
        model = keras.Sequential()
        model.add(keras.layers.Rescaling(scale=1 / 127.5, offset=-1))
        model.add(keras.layers.Flatten())
        for i in range(num_layers):
            model.add(keras.layers.Dense(units, activation='relu'))
        model.add(keras.layers.Dropout(rate=0.3))
        model.add(keras.layers.Dense(10, activation="softmax"))
        model.compile(
            optimizer=keras.optimizers.Adam(learning_rate=lr),
            loss="categorical_crossentropy",
            metrics=["accuracy"],
        )
        return model
    def build(self, hp):

        units = hp.Int("units", min_value=64, max_value=256, step=32)
        num_layers = hp.Int("num_layers",min_value=1,max_value=3)
        lr = hp.Float("lr",min_value=1e-5,max_value=1e-3,sampling="log")

        return self.model(units,num_layers,lr) 
    def fit(self, hp, model, x_train,y_train, **kwargs):
        return model.fit(
            x_train,
            y_train,
            **kwargs
        )

利用mnist测试

简单的例子用简单的数据进行测试,这里就使用经典的手写数字数据集吧。

from tensorflow import keras
import numpy as np

(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()

x = np.expand_dims(x,axis=-1)
x_test = np.expand_dims(x_test,axis=-1)

num_classes =10
y = keras.utils.to_categorical(y, num_classes)
y_test = keras.utils.to_categorical(y_test,num_classes)

开始搜索

这里设定最多搜10次,每次迭代2个epoch。

tuner = keras_tuner.RandomSearch(
    HyperModel(),
    objective="val_accuracy",
    max_trials=10,
    overwrite=True,
    directory="my_dir",
    project_name="tune_hypermodel",

)
tuner.search(x,y,epochs=2,batch_size=128,validation_data=(x_test, y_test),workers =8)

用最棒的超参数构建模型

我们需要使用在验证集表现最好的超参数构建模型,进行训练。
首先看看每次的结果是咋样的:

tuner.results_summary()

构建模型并训练

hypermodel = HyperModel()
best_hp = tuner.get_best_hyperparameters()[0]
model = hypermodel.build(best_hp)
hypermodel.fit(best_hp, model, x, y, epochs=20,batch_size=128,validation_data=(x_test, y_test),workers =8)
model.save('demo_hypermodel.h5')

超·MobileNetV2

好了,通过上面的例子,相信你已经对KerasTuner有一定的了解了。下面我们正式构建可以用于比赛的超·MobileNetV2

模型定义

下面的模型将会稍微复杂点。我们将数据增强的参数也纳入了搜索范围,而对模型的参数,我们搜索学习率和dropout比率。
事实上,搜索什么参数不一定按照这样定义,你完全可以根据自己的需求来,这里仅做一个简单的示范。
要注意的是,并不是把所有的参数都纳入搜索就是最好的,要考虑实际情况。

from tensorflow.keras.preprocessing.image import ImageDataGenerator
class HyperMobilenet_v2(keras_tuner.HyperModel):
    def __init__(self,input_size,batch_size,train_root):
        super(keras_tuner.HyperModel, self).__init__()
        self.input_size = input_size
        self.batch_size = batch_size
        self.train_root = train_root
    def model(self,Dropout_rate,lr):
        model = Mobilenet_v2(
            input_size=self.input_size,
            weights='imagenet',
            Dropout_rate=Dropout_rate,
            Trainable=True
        )
        model.compile(optimizer=keras.optimizers.Adam(learning_rate=lr),
                    loss=keras.losses.CategoricalCrossentropy(),
                    metrics=["accuracy"])
        return model
    def build(self, hp):
        lr = hp.Float("lr",min_value=1e-5,max_value=1e-3,sampling="log")
        Dropout_rate = hp.Choice("Dropout_rate",values =[0.1,0.2,0.3,0.4,0.5,0.6])
        return self.model(Dropout_rate,lr) 
    
    def dataset(self, hp):

        train_root = self.train_root

        zoom_range = hp.Float("zoom_range",min_value=0.1,max_value=0.3,sampling="linear")
        channel_shift_range = hp.Int("channel_shift_range",min_value=0,max_value=30,step=10)

        train_generator = ImageDataGenerator(rotation_range=360,
                                            zoom_range =zoom_range,
                                            horizontal_flip = True,
                                            validation_split =0.2,
                                            channel_shift_range =channel_shift_range
                                            )
        train_dataset = train_generator.flow_from_directory(batch_size=self.batch_size,
                                                            directory=train_root,
                                                            shuffle=True,
                                                            target_size=(self.input_size,self.input_size),
                                                            subset='training')
        valid_dataset = train_generator.flow_from_directory(batch_size=self.batch_size,
                                                            directory=train_root,
                                                            shuffle=True,
                                                            target_size=(self.input_size,self.input_size),
                                                            subset='validation')
        return train_dataset,valid_dataset

    def fit(self, hp, model,**kwargs):
        
        train_dataset,valid_dataset = self.dataset(hp)

        return model.fit(
            train_dataset,
            validation_data=valid_dataset,
            **kwargs
        ) 

开始搜索

因为我们搜索的超参数比上面例子的更多,我们的搜索次数设定得更大些,每次的epochs也增加到10次。你也可以调得更大,但这样需要的时间会更多。

tuner = keras_tuner.BayesianOptimization(
    hypermodel =HyperMobilenet_v2(input_size=128,batch_size=128,train_root='./train/'),
    objective="val_accuracy",
    max_trials=50,
    overwrite=True,
    directory="my_dir",
    project_name="tune_hypermodel",
)
tuner.search(epochs=10,workers=8)

重新训练

用表现最好的超参数构建模型。

hypermodel = HyperMobilenet_v2(input_size=128,batch_size=128,train_root='./train/')
best_hp = tuner.get_best_hyperparameters()[0]
model = hypermodel.build(best_hp)

加入回调进行训练。

import time
import os
save_path = './models_save/%s' % (time.strftime('%Y_%m_%d_%H_%M_%S'))
reduce_lr = keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2,patience=10,verbose=1)
early_stop =keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=15,verbose=1)
save_weights = keras.callbacks.ModelCheckpoint(save_path + "/model_{epoch:02d}_{val_accuracy:.4f}.h5",
                                                   save_best_only=True, monitor='val_accuracy')

hypermodel.fit(
    best_hp, 
    model,
    epochs=100,
    workers =8,
    callbacks=[save_weights,early_stop,reduce_lr]
    )

你可能感兴趣的:(智能汽车竞赛,深度学习,tensorflow,python)