通过包装 Keras 模型来使用 scikit-learn,并学习怎么使用网格搜索(grid search) - 怎样网格搜索通用神经网络参数,如学习速率(learning rate),丢弃率(dropout rate),迭代次数(epoches)及其神经元的个数 - 在自己的项目上怎么定义超参调节实验。
通过 Keras 提供的 KerasClassifier
与 KerasRegressor
类,将 Keras 模型包装起来就可以在 scikit-learn 中使用了。KerasClassifier
的构造器可以接收默认参数,这些参数被传递给调用model.fit()
,如迭代的次数、批次的大小。例如:
def create_model():
...
return model
model = KerasClassifier(build_fn=create_model, epochs=10)
KerasClassifier
的构造器也可以接收新的参数,它可以被传递给你自己定义的create_model()
函数。这些新的参数必须定义在你的create_model()
函数的签名通过默认参数。例如:
def create_model(dropout_rate=0.0):
...
return model
model = KerasClassifier(build_fn=create_model, dropout_rate=0.2)
构建这个类的时候,你必须提供超参的字典来评估param_grid
参数。他是模型参数名字与一组用于尝试值的映射。默认情况下,accuracy 是被用于优化的分数,但通过 GridSearchCV
构造器的 score
参数,可以指定其他的得分评估方法。
默认情况下,网格搜索只是用一个线程,通过将 GridSearchCV
构造器的 n_jobs
参数设置为 -1,进程会使用你机器上的所有内核。依据不 Keras 的后端,这可能会影响神经网络的训练进程。
GridSearchCV
进程会为每一个参数组合构建并训练一个模型。交叉验证(Cross validation)被用于评估每一个独立的模型,同时默认的3折交叉验证(3-fold cross validation)被使用,尽管通过 GridSearchCV
构造器的 cv
参数可以重新指定他的值。
param_grid = dict(epochs=[10,20,30])
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)
grid_result = grid.fit(X, Y)
数据:pima-indians-diabetes.csv
batch size 是权重更新前输入网络的样本数。在训练网络时他也是一个优化,他决定了一次有多少样本读入到内存中。epochs 数是在训练期间,整个训练数据集输入到网络的次数。
import numpy as np
from sklearn.model_selection import GridSearchCV
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasClassifier
# 构建模型的函数
def create_model():
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
def print_res(grid_result):
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型
model = KerasClassifier(build_fn=create_model, verbose=0)
# 定义网格搜索参数
batch_size = [10, 20, 40, 60, 80, 100]
epochs = [10, 50, 100]
param_grid = dict(batch_size=batch_size, epochs=epochs)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)
grid_result = grid.fit(X, Y)
# 总结结果
print_res(grid_result)
# 构建模型的函数
def create_model(optimizer='adam'):
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])
return model
def print_res(grid_result):
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
optimizer = ['SGD', 'RMSprop', 'Adagrad', 'Adadelta', 'Adam', 'Adamax', 'Nadam']
param_grid = dict(optimizer=optimizer)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print_res(grid_result)
from keras.optimizers import SGD
# 构建模型的函数
def create_model(learn_rate=0.01, momentum=0):
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 编译模型
optimizer = SGD(lr=learn_rate, momentum=momentum)
model.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])
return model
def print_res(grid_result):
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
learn_rate = [0.001, 0.01, 0.1, 0.2, 0.3]
momentum = [0.0, 0.2, 0.4, 0.6, 0.8, 0.9]
param_grid = dict(learn_rate=learn_rate, momentum=momentum)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print_res(grid_result)
神经网络权重初始化被简单的运用:使用较小的随机值。 现在可以从 Keras 提供的一组列表来选择不同的初始化技术。
# 构建模型的函数
def create_model(init_mode='uniform'):
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer=init_mode, activation='relu'))
model.add(Dense(1, kernel_initializer=init_mode, activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
init_mode = ['uniform', 'lecun_uniform', 'normal', 'zero', 'glorot_normal',
'glorot_uniform', 'he_normal', 'he_uniform']
param_grid = dict(init_mode=init_mode)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
激活函数控制着神经元的非线性在激活时。通常,relu 激活函数是最经常使用的,但对于不同的问题,sigmoid 和 tanh 这些函数可能更合适。
# 构建模型的函数
def create_model(activation='relu'):
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation=activation))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
activation = ['softmax', 'softplus', 'softsign', 'relu',
'tanh', 'sigmoid', 'hard_sigmoid', 'linear']
param_grid=dict(activation=activation)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
from keras.layers import Dropout
from keras.constraints import maxnorm
# 构建模型的函数
def create_model(dropout_rate=0.0, weight_constraint=0):
# 创建模型
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation='relu'))
model.add(Dropout(dropout_rate))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
weight_constraint = [1, 2, 3, 4, 5]
dropout_rate = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
param_grid = dict(weight_constraint=weight_constraint, dropout_rate=dropout_rate)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
from keras.layers import Dropout
from keras.constraints import maxnorm
# 构建模型的函数
def create_model(neurons=1):
# 创建模型
model = Sequential()
model.add(Dense(neurons, input_dim=8, kernel_initializer='uniform', activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# 为了复现,设置随机种子
seed = 7
np.random.seed(seed)
# 加载数据
dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# 切分数据为输入 X 和输出 Y
X = dataset[:,0:8]
Y = dataset[:,8]
# 创建模型,使用到了上一步找出的 epochs、batch size 最优参数
model = KerasClassifier(build_fn=create_model, epochs=100, batch_size=80, verbose=0)
# 定义网格搜索参数
neurons = [1, 5, 10, 15, 20, 25, 30]
param_grid = dict(neurons=neurons)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)
grid_result = grid.fit(X, Y)
# 总结结果
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))
这一张列出了一些遍历的技巧当你调节你的神经网络超参时。