TensorFlow2.0(六)--超参数搜索

1. 超参数搜索简介

1.1 超参数

超参数就是在神经网络的训练过程中,不变的参数。比如:

  • 网络结构参数:层数,每层宽度,每层激活函数等
  • 训练参数: batch_size, 学习率, 学习率衰减算法
1.2 超参数搜索

如果我们在训练模型的过程中手动的一个个的更改上述的超参数组合,那么工作量是巨大的,所以我们需要采取超参数搜索策略。超参数搜索有一下几个策略:

  • 网格搜索
    网课搜索是一种最简答和最容易理解的超参数搜索策略。以dropout rate和learning rate两个超参数为例,我们可以将两个超参数组成一个二维网格,比如dropout rate取值[0.1, 0.3, 0.6, 0.8]四个值,learning rate取[0.001, 0.005, 0.01, 0.005],我们用二维网格将二个超参数两两结合,然后在多台机器上进行并行训练,就可以快速得到相对优的超参数组合。
    在这里插入图片描述

  • 随机搜索
    随机搜索和网格搜索比较接近,二者的区别是网格搜索的参数分布是固定和相对均匀的,随机搜索的参数是随机生成的。对于网格搜索,最优参数很可能分布在网格中间而非网格的节点上,所以我们往往很难找到最优的超参数组合。随机搜索因为参数分布是随机的,所以找到的超参数组合往往要优于网格搜索,但是随机搜索生成的超参数组合也是要多于网格搜索。
    在这里插入图片描述

  • 遗传算法搜索
    遗传算法是对自然界的模拟。

    • 首先我们先初始化候选参数集合,然后进行训练,以得到的模型指标作为该模型参数的生存概率,指标越好,生存概率越大。
    • 其次,我们对参数进行选择–>交叉–>变异–>产生下一代
    • 然后再次进行训练,重复以上步骤,最后得到的最优的参数集合就是我们搜索的最优结果
  • 启发式搜索
    启发式搜索是AutoML中的研究热点,启发式搜索使用循环神经网络来生成参数,然后使用强化学习来进行反馈,使用模型来训练生成参数。

2. 手动实现超参数搜索

2.1 导入相应的库
# matplotlib 用于绘图
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
# 处理数据的库
import numpy as np
import sklearn
import pandas as pd
# 系统库
import os
import sys
import time
# TensorFlow的库
import tensorflow as tf
from tensorflow import keras
2.2 数据载入与处理

本篇博客选择使用房价预测的回归问题来完成超参数搜索,因为这个问题的维度比较小,实现起来比较容易。
数据集加载:

from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing()

数据集分割为训练集、测试集与验证集:

from sklearn.model_selection import train_test_split
"""
# test_size 指的是划分的训练集和测试集的比例
# test_size 默认值为0.25 表示数据分四份,测试集占一份
"""
x_train_all, x_test, y_train_all, y_test = train_test_split(housing.data, housing.target, random_state = 7, test_size = 0.25)
x_train, x_valid, y_train, y_valid = train_test_split(x_train_all, y_train_all, random_state = 11, test_size = 0.25)

数据归一化处理:

# 数据归一化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
"""
# 训练集数据使用的是 fit_transform,和验证集与测试集中使用的 transform 是不一样的
# fit_transform 可以计算数据的均值和方差并记录下来
# 验证集和测试集用到的均值和方差都是训练集数据的,所以二者的归一化使用 transform 即可
# 归一化只针对输入数据, 标签不变
"""
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)
2.3 手动实现超参数搜索

手动实现超参数搜索:

# 搜索learning rate: [1e-4, 3e-4, 1e-3, 3e-3, 1e-2, 3e-2]
learning_rate = [1e-4, 3e-4, 1e-3, 3e-3, 1e-2, 3e-2]
histories = []
"""
# 我们只以学习率为例
# 学习率的取值有6个
# 以for循环为表达进行学习率的遍历
"""
for lr in learning_rate:
	# 模型的构建
    model = keras.models.Sequential([
        keras.layers.Dense(10, activation='relu', input_shape=x_train.shape[1:]),
        keras.layers.Dense(1),
    ])
    # 模型的编译
    model.compile(loss="mean_squared_error", optimizer = keras.optimizers.SGD(lr))
    # 回调函数
    callbacks = [keras.callbacks.EarlyStopping(patience=5, min_delta=1e-2)]
    # 开始训练
    history = model.fit(x_train_scaled, y_train,
                   validation_data=(x_valid_scaled, y_valid),
                   epochs = 100,
                   callbacks= callbacks)
    # histories存放每个学习率下的训练结果
    histories.append(history)

3. sklearn实现超参数搜索

手动实现超参数搜索是一件很麻烦的事情,我们只举了一个学习率的例子,但是实际情况中,我们要搜索的超参数有很多,这就造成了我们实际上要做的for循环可能不止上述的6个,可能有成百上千次循环。所以我们利用现有的sklearn库进行超参数搜索。

3.1 sklearn实现超参数搜索
"""
我们利用RandomizedSearchCV包实现超参数搜索
1. 转化为sklearn的model
2. 定义参数集合
3. 搜索参数
"""
# 转化为sklearn的model
def build_model(hidden_layers = 1,
               layer_size = 30,
               learning_rate = 3e-3):
    model = keras.models.Sequential()
    model.add(keras.layers.Dense(layer_size, activation='relu', input_shape=x_train.shape[1:]))
    for _ in range(hidden_layers - 1):
        model.add(keras.layers.Dense(layer_size, activation='relu'))
    model.add(keras.layers.Dense(1))
    model.compile(loss="mean_squared_error", optimizer = keras.optimizers.SGD(learning_rate))
    return model

sklearn_model = keras.wrappers.scikit_learn.KerasRegressor(build_model)
callbacks = [keras.callbacks.EarlyStopping(patience=5, min_delta=1e-2)]

# 定义参数集合
param_distribution = {
    "hidden_layers":[1,2,3,4],
    "layer_size":np.arange(1,100),
    "learning_rate":[1e-4, 3e-4, 1e-3, 3e-3, 1e-2, 3e-2]
}

# 搜索参数
from sklearn.model_selection import RandomizedSearchCV
random_search_CV =RandomizedSearchCV(sklearn_model,
                                  param_distribution,
                                  n_iter  =10,  # 生成的超参数组合数
                                  n_jobs = 1)   # 并行处理的数量
# 开始训练
history = random_search_CV.fit(x_train_scaled, y_train, 
                 epochs = 100,
                 validation_data = (x_valid_scaled, y_valid),
                 callbacks = callbacks)
3.2 最优训练结果

我们可以打印出来最优的参数,得分以及模型:

print(random_search_CV.best_params_)
print(random_search_CV.best_score_)
print(random_search_CV.best_estimator_)

在这里插入图片描述

3.3 对得到超参数进行验证

我们对得到的最优的模型进行验证:

model = random_search_CV.best_estimator_.model
model.evaluate(x_test_scaled, y_test)

输出为:
在这里插入图片描述

发布了182 篇原创文章 · 获赞 243 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_42580947/article/details/105310078
今日推荐