构造神经元网络模型时,我们一定会考虑需要几个卷积层,需要有几个过滤器,全连接层需要几个神经元?
在下面中我们将解决这个问题
在CV2中我们已经通过CNN成功的完成了人马识别的例子,但是识别的效果并不算很好。在CV3中我们将对其参数做优化。
目录
一.优化参数的三个方法
1.手动修改
2.for循环调参
3.Keras Tunner自动调参工具
介绍
1.安装
2.准备训练数据和加载的库
3.创建HyperParameters对象
4.创建Hyperband对象
4.开始优化
5.获取最佳模型
6.结果显示
二.注释
1.为什么二次调参无效,不起作用?(避坑)
有以下三个方法
我们可以有最原始的办法,就是手动修改参数,然后观察训练的效果(损失和精确度),从而判断参数的设置是否合理,但是这样很麻烦。
还有一个办法就是,那就是编程写for循环来调参,但是也有点麻烦。
在这里我们可以借助这款自动调参工具来实现我们参数的优化,优点是不容易出错,效果也比较好。
keras Tunner是一个可以自动搜索模型训练参数的库,它的基本思路是在需要调整参数的地方插入一个特殊的对象(可指定参数范围),然后调用类似训练那样的search方法。
依赖
安装命令:
pip install -U keras-tuner
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import RMSprop
#创建两个数据生成器,指定scaling范围0~1
train_datagen = ImageDataGenerator(rescale=1/255)
validataion_datagen = ImageDataGenerator(rescale=1/255)
#指向训练数据文件夹
train_generator = train_datagen.flow_from_directory(
'F:/deeplearning/tmp/horse-or-human',
target_size=(150,150),
batch_size=32,
class_mode='binary')
#指向测试数据文件夹
validation_generator = train_datagen.flow_from_directory(
'F:/deeplearning/tmp/validation-horse-or-human',
target_size=(150,150),
batch_size=32,
class_mode='binary')
from kerastuner.tuners import Hyperband
from kerastuner.engine.hyperparameters import HyperParameters
先创建HyperParameters对象。进而我们定义一个模型,然后在模型中插入Choice以及int等调参用的对象。该函数返回一个编译好的模型。
hp=HyperParameters()#声明一个变量,类型为HyperParameters,等会通过hp来调
#将创建模型的代码作为函数
def build_model(hp):
#构建模型
model = tf.keras.models.Sequential()
#用Choice是判断有几个filter比较合适
model.add(tf.keras.layers.Conv2D(hp.Choice('num_filters_top_layer', #随便起的名字,训练好之后他会把数值直接和这个名字对应起来
values=[16,64],#指定取值范围
default=16),#默认值
(3,3),
activation='relu',input_shape=(150,150,3)))
model.add(tf.keras.layers.MaxPooling2D(2,2))
#再看Conv应该有几层(因为我们也不知道应该有多少层卷积层)[只注意只for循环卷积层]
for i in range(hp.Int('num_conv_layers',1,3)):#这里默认step是1,数值不能太大,Max Pooling以后会越来越小,输出尺寸会越来越小,小到出现负数了这个训练就走不下去了
model.add(tf.keras.layers.Conv2D(hp.Choice(f'num_filters_layer{i}',#加f表示在字符串内支持大括号内的Python表达式
values=[16,64],
default=16),
(3,3),activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(2,2))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(hp.Int('hidden_units',128,512,step=32),#给出范围和搜索步长
activation='relu'))
model.add(tf.keras.layers.Dense(1,activation='sigmoid'))
model.compile(loss='binary_crossentropy', # 注意模型必须先编译
optimizer=RMSprop(lr=0.001),
metrics=['accuracy'])
return model
进而我们再创建Hyperband对象,这是keras tuner支持的四种方法的其中一种。
tuner=Hyperband(#生成一个tunner对象,输入Hyperband
build_model,#函数的名字,告诉他用哪个函数生成这个模型
objective='val_accuracy',#目标使用val_accuracy,以测试集的accuracy为目标
max_epochs=15,#猜最多几次可以达到会聚
directory='horse_human_params', #请看注释一(避坑),调参的过程会把数据加到本地,需要指定一个本地目录加名称,其他都是自动的,
hyperparameters=hp,#告诉他是用这个变量
project_name='my_horse_human_project' #存储的时候随便取的名字
)
搜索过程:通过调用模型构建函数,使用hp跟踪的超参空间(搜索空间)中的参数配置,多次构建模型。优化器逐渐探索超参空间,记录每种配置的评估结果。
#接下来搜一下参数,search和fit差不多的
tuner.search(train_generator,epochs=10,validation_data=validation_generator)
搜索到最优参数之后,可通过下面的程序,用tunner对象提取最优参数构建神经元网络模型。并调用summary方法观察优化后的网络结构。
#优化完参数后可以通过这个方法看到结果
best_hps=tuner.get_best_hyperparameters(1)[0]#可以用到这个办法读到它的参数
model=tuner.hypermodel.build(best_hps)#可以用这些参数把模型构建出来
model.summary()
tuner.results_summary()#可打印结果综述
结果:
Search: Running Trial #30
Hyperparameter |Value |Best Value So Far
num_filters_top...|16 |64
num_conv_layers |3 |2
num_filters_layer0|16 |64
hidden_units |224 |416
num_filters_layer1|16 |16
num_filters_layer2|16 |16
tuner/epochs |15 |15
tuner/initial_e...|0 |0
tuner/bracket |0 |0
tuner/round |0 |0
Epoch 1/15
33/33 [==============================] - 12s 333ms/step - loss: 0.6235 - accuracy: 0.6292 - val_loss: 0.9375 - val_accuracy: 0.7539
Epoch 2/15
33/33 [==============================] - 11s 342ms/step - loss: 0.2492 - accuracy: 0.8954 - val_loss: 0.6282 - val_accuracy: 0.8789
Epoch 3/15
33/33 [==============================] - 9s 270ms/step - loss: 0.1137 - accuracy: 0.9480 - val_loss: 1.7960 - val_accuracy: 0.8008
Epoch 4/15
33/33 [==============================] - 12s 355ms/step - loss: 0.1907 - accuracy: 0.9303 - val_loss: 1.0514 - val_accuracy: 0.8242
Epoch 5/15
33/33 [==============================] - 12s 363ms/step - loss: 0.0539 - accuracy: 0.9819 - val_loss: 1.0656 - val_accuracy: 0.7734
Epoch 6/15
33/33 [==============================] - 10s 309ms/step - loss: 0.0648 - accuracy: 0.9747 - val_loss: 1.1672 - val_accuracy: 0.8672
Epoch 7/15
33/33 [==============================] - 12s 372ms/step - loss: 0.0260 - accuracy: 0.9938 - val_loss: 0.8903 - val_accuracy: 0.8828
Epoch 8/15
33/33 [==============================] - 11s 321ms/step - loss: 0.0907 - accuracy: 0.9804 - val_loss: 1.1295 - val_accuracy: 0.8828
Epoch 9/15
33/33 [==============================] - 9s 273ms/step - loss: 0.0054 - accuracy: 0.9996 - val_loss: 1.5149 - val_accuracy: 0.8633
Epoch 10/15
33/33 [==============================] - 9s 263ms/step - loss: 0.1649 - accuracy: 0.9708 - val_loss: 1.0031 - val_accuracy: 0.8828
Epoch 11/15
33/33 [==============================] - 9s 259ms/step - loss: 0.0141 - accuracy: 0.9975 - val_loss: 0.8392 - val_accuracy: 0.8867
Epoch 12/15
33/33 [==============================] - 9s 271ms/step - loss: 0.0031 - accuracy: 1.0000 - val_loss: 1.3648 - val_accuracy: 0.8828
Epoch 13/15
33/33 [==============================] - 9s 257ms/step - loss: 0.0169 - accuracy: 0.9917 - val_loss: 2.4052 - val_accuracy: 0.8359
Epoch 14/15
33/33 [==============================] - 9s 281ms/step - loss: 0.0276 - accuracy: 0.9928 - val_loss: 1.5494 - val_accuracy: 0.8867
Epoch 15/15
33/33 [==============================] - 9s 271ms/step - loss: 4.4481e-04 - accuracy: 1.0000 - val_loss: 1.9674 - val_accuracy: 0.8594
Trial 30 Complete [00h 02m 35s]
val_accuracy: 0.88671875
Best val_accuracy So Far: 0.9140625
Total elapsed time: 00h 53m 12s
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 148, 148, 64) 1792
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 74, 74, 64) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 72, 72, 64) 36928
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 36, 36, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 34, 34, 16) 9232
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 17, 17, 16) 0
_________________________________________________________________
flatten (Flatten) (None, 4624) 0
_________________________________________________________________
dense (Dense) (None, 416) 1924000
_________________________________________________________________
dense_1 (Dense) (None, 1) 417
=================================================================
Total params: 1,972,369
Trainable params: 1,972,369
Non-trainable params: 0
_________________________________________________________________
发现了没有我们的结果其实还不是很理想,出现了过拟合的现象,在这里我们参数都已经优化了,训练集的样本也足够多了,那是哪里出了问题呢?我们查看一下我们的搜索结果,发现val_accuracy还不够高,这说明可能我们的搜索迭代参数还不够多,于是我们增加了搜索迭代的次数,得到下面的结果。这个结果还是能够接受的。
是因为第一次调参之后把调参之后的结果存储在directory里面了,二次调参需要把那个文件夹删了才会重新优化。