网格搜索时应用最广泛的超参数搜素算法,网格搜索通过查找搜索范围内的所有点,来确定最优值。一般是通过给出较大的搜索范围以及较小的步长,网格搜索时一定可以找到全局最大值或全局最小值的。
但是网格搜索有一个较大的问题时:它十分消耗计算资源,特别是需要调优的超参数比较多的时候。因此在实践比赛中,需要调参的模型数量与对应的超参数比较多,而设计的数据量又比较大,因此相当消耗时间。此外,由于给出的超参数的组合比较多,因此一般都会固定多数参数,分布对1~2个超参数进行调节,这样能够减少时间但是难以自动进行。而且由于目标参数一般是非凸的,因此容易陷入局部最小值。
from sklearn.model_selection import GridSearchCV
#定义自己的网格搜索函数
def GridSearch(clf, params, X, y):
gscv = GridSearchCV(clf, params, scoring='neg_mean_squared_error', n_jobs=1, cv=5)
gscv.fit(X, y)
print("The best result: ", gscv.cv_results_)
print("The best params: ", gscv.best_params_)
#实验
params_sklearn = {
"boosting_type" : 'gbdt',
'max_depth':3,
"learning_rate" : 0.1,
"objective" : "binary",
"min_child_samples" : 20,
"metric" : ['binary_logloss','auc'],
"verbose" : -1,
'reg_lambda': 0.1,
'reg_alpha': 0.2,
"random_state": 420,
}
gbm = lgb.LGBMClassifier(**params_sklearn)
#网格搜索的参数
params_grid = {
'num_leaves':range(30,50),
'max_depth': range(4,8),
}
gscv = GridSearch(gbm, params_grid, train, y_train)
#The best params: {'max_depth': 6, 'num_leaves': 40}
#Timing 16.8s
与网格搜索相比,随机搜索并未尝试所有参数值,而是从指定的分布中采样固定数量的参数设置。它的理论依据是,如果随即样本点集足够大,那么也可以找到全局的最大或最小值,或它们的近似值。通过对搜索范围的随机取样,随机搜索一般会比网格搜索要快一些。但是和网格搜索的快速版(非自动版)相似,结果也是没法保证的。
当超参数的搜索空间很大时,最好使用RandomizedSearchCV
。这个类的使用方法和类 GridSearchCV
很相似,但它不是尝试所有可能的组合,而是通过选择每个超参数的一个随机值的特定数量的随机组合。
#随机搜索,和网格搜索代码一致,除了更改GridSearchCV为RandomizedSearchCV
from sklearn.model_selection import RandomizedSearchCV
#定义自己的网格搜索函数
def RandomizedSearch(clf, params, X, y):
rscv = RandomizedSearchCV(clf, params, scoring='neg_mean_squared_error', n_jobs=1, cv=5)
rscv.fit(X, y)
print("The best result: ", rscv.cv_results_)
print("The best params: ", rscv.best_params_)
#实验
params_sklearn = {
"boosting_type" : 'gbdt',
'max_depth':3,
"learning_rate" : 0.1,
"objective" : "binary",
"min_child_samples" : 20,
"metric" : ['binary_logloss','auc'],
"verbose" : -1,
'reg_lambda': 0.1,
'reg_alpha': 0.2,
"random_state": 420,
}
gbm = lgb.LGBMClassifier(**params_sklearn)
#网格搜索的参数
params_randm = {
'num_leaves':range(30,50),
'max_depth': range(4,8),
}
rscv = RandomizedSearch(gbm, params_randm, train, y_train)
#The best params: {'num_leaves': 49, 'max_depth': 7}
#Timing:2.8s
主要思想是:给定优化的目标函数(广义的函数,只需要指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数地后验分布。简单来说,就是考虑和上一次参数地信息,从而更好地调整当前地参数。
贝叶斯优化与常规的网格搜索或者随机搜索的区别是:
- 贝叶斯调参采用高斯过程,考虑之前的参数信息,不断地更新先验;网格搜索未考虑之前地参数信息
- 贝叶斯调参迭代次数少,速度快,网格搜索速度慢,参数多时容易导致维度爆炸。
- 贝叶斯调参针对非凸问题依旧稳健,网格搜索针对非凸问题容易陷入局部最小值。
#设定贝叶斯优化的黑盒函数LGB_bayesian
def LGB_bayesian(
num_leaves, # int
min_data_in_leaf, # int
learning_rate,
min_sum_hessian_in_leaf, # int
feature_fraction,
lambda_l1,
lambda_l2,
min_gain_to_split,
max_depth):
# LightGBM expects next three parameters need to be integer. So we make them integer
num_leaves = int(num_leaves)
min_data_in_leaf = int(min_data_in_leaf)
max_depth = int(max_depth)
assert type(num_leaves) == int
assert type(min_data_in_leaf) == int
assert type(max_depth) == int
param = {
'num_leaves': num_leaves,
'max_bin': 63,
'min_data_in_leaf': min_data_in_leaf,
'learning_rate': learning_rate,
'min_sum_hessian_in_leaf': min_sum_hessian_in_leaf,
'bagging_fraction': 1.0,
'bagging_freq': 5,
'feature_fraction': feature_fraction,
'lambda_l1': lambda_l1,
'lambda_l2': lambda_l2,
'min_gain_to_split': min_gain_to_split,
'max_depth': max_depth,
'save_binary': True,
'seed': 1337,
'feature_fraction_seed': 1337,
'bagging_seed': 1337,
'drop_seed': 1337,
'data_random_seed': 1337,
'objective': 'binary',
'boosting_type': 'gbdt',
'verbose': 1,
'metric': 'auc',
'is_unbalance': True,
'boost_from_average': False,
"verbosity":-1
}
lgb_train = lgb.Dataset(train,
label=y_train)
lgb_valid = lgb.Dataset(test,label=y_test,reference=lgb_train)
num_round = 500
gbm= lgb.train(param, lgb_train, num_round, valid_sets = [lgb_valid],callbacks=[lgb.early_stopping(stopping_rounds=5)])
predictions = gbm.predict(test,num_iteration=gbm.best_iteration)
score = roc_auc_score(y_test, predictions)
return score
bounds_LGB = {
'num_leaves': (5, 20),
'min_data_in_leaf': (5, 20),
'learning_rate': (0.01, 0.3),
'min_sum_hessian_in_leaf': (0.00001, 0.01),
'feature_fraction': (0.05, 0.5),
'lambda_l1': (0, 5.0),
'lambda_l2': (0, 5.0),
'min_gain_to_split': (0, 1.0),
'max_depth':(3,15),
}
#将它们全部放在BayesianOptimization对象中
from bayes_opt import BayesianOptimization
LGB_BO = BayesianOptimization(LGB_bayesian, bounds_LGB, random_state=13)
print(LGB_BO.space.keys)#显示要优化的参数
import warnings
import gc
pd.set_option('display.max_columns', 200)
init_points = 5
n_iter = 5
print('-' * 130)
with warnings.catch_warnings():
warnings.filterwarnings('ignore')
LGB_BO.maximize(init_points=init_points, n_iter=n_iter, acq='ucb', xi=0.0, alpha=1e-6)