在进行机器学习的过程中,最为核心的一个概念就是参数,而参数又分为模型参数与超参数。模型参数,顾名思义就是我们使用的模型根据训练数据的分布学习到的参数,这一部分不需要我们人为的先验经验。超参数是在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据。通常情况下,需要对超参数进行优化,给模型选择一组最优超参数,以提高学习的性能和效果。通常情况下,常用的超参数调参的方法有:网格搜索,随机搜索与贝叶斯优化。
网格搜索(GridSearch)用于选取模型的最优超参数。获取最优超参数的方式可以绘制验证曲线,但是验证曲线只能每次获取一个最优超参数。如果多个超参数有很多排列组合的话,就可以使用网格搜索寻求最优超参数的组合。
网格搜索针对超参数组合列表中的每一个组合,实例化给定的模型,做cv次交叉验证,将平均得分最高的超参数组合作为最佳的选择,返回模型对象。
GridSearchCV的sklearn官方网址:
http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV
网格搜索的方法如下:
sklearn.model_selection.GridSearchCV(
estimator = RandomForestRegressor(bootstrap=True, criterion='mse',
max_depth=None,max_features='auto',
max_leaf_nodes=None,min_impurity_decrease=0.0,
min_impurity_split=None,min_samples_leaf=1,
min_samples_split=2,min_weight_fraction_leaf=0.0,
n_estimators='warn', n_jobs=None,
oob_score=False, random_state=42,
verbose=0, warm_start=False),
param_grid=[{'max_features': [2, 4, 6, 8],
'n_estimators': [3, 10, 30]},
{'bootstrap': [False], 'max_features': [2, 3, 4],
'n_estimators': [3, 10]}],
scoring='neg_mean_squared_error',n_jobs=None,iid=’warn’,
refit=True, cv=5, verbose=0, pre_dispatch=‘2*n_jobs’,
error_score=’raise-deprecating’, return_train_score=True)
1. estimator
选择使用的分类器,并且传入除需要确定最佳的参数之外的其他参数。
2. param_grid
需要最优化的参数的取值,值为字典或者列表。
3.scoring=None
模型评价标准,默认None。
根据所选模型不同,评价准则不同。比如scoring=”accuracy”。
如果是None,则使用estimator的误差估计函数。
4. n_jobs=1
进程个数,默认为1。 若值为 -1,则用所有的CPU进行运算。 若值为1,则不进行并行运算,这样的话方便调试。
5.iid=True
默认True,为True时,默认为各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。
6. refit=True
默认为True,程序将会以交叉验证训练集得到的最佳参数,重新对所有可用的训练集与开发集进行,作为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍全部数据集。
7. cv=None
交叉验证参数,默认None,使用三折交叉验证。
8.verbose:日志冗长度
9. pre_dispatch=‘2*n_jobs’
指定总共分发的并行任务数。当n_jobs大于1时,数据将在每个运行点进行复制,这可能导致OOM,而设置pre_dispatch参数,则可以预先划分总共的job数量,使数据最多被复制pre_dispatch次。
10.error_score:'raise' or numeric
如果在估计器拟合中出现错误,则将值赋给该分数。如果设置为“引发”,则会引发错误。如果给定一个数值,则会引发FitFailedWarning。此参数不影响refit步骤,因为后者总是会引起错误。默认是np.nan。
11.return_train_score:boolean,默认(False)
如果为假,cv_results_属性将不包括训练分数。计算训练分数是用来了解不同的参数设置如何影响过拟合/欠拟合权衡。然而,计算训练集上的分数在计算上是很昂贵的,并且并不严格要求选择产生最佳泛化性能的参数。
与网格搜索相比,随机搜索并未尝试所有参数值,而是从指定的分布中采样固定数量的参数设置。它的理论依据是,如果随即样本点集足够大,那么也可以找到全局的最大或最小值,或它们的近似值。通过对搜索范围的随机取样,随机搜索一般会比网格搜索要快一些。但是和网格搜索的快速版(非自动版)相似,结果也是没法保证的。
随机搜索的过程如下,使用方法与网格搜索完全一致:
sklearn.model_selection.RandomizedSearchCV(
estimator = RandomForestRegressor(bootstrap=True, criterion='mse',
max_depth=None,max_features='auto',
max_leaf_nodes=None,min_impurity_decrease=0.0,
min_impurity_split=None,min_samples_leaf=1,
min_samples_split=2,min_weight_fraction_leaf=0.0,
n_estimators='warn', n_jobs=None,
oob_score=False, random_state=42,
verbose=0, warm_start=False),
param_distributions={
'max_features': randint(low = 1,high = 8),
'n_estimators': randint(low = 1,high = 200)},
iid = 'warn',n_iter = 10, n_jobs=None,
refit=True,cv=5,scoring='neg_mean_squared_error',
verbose=0, pre_dispatch=‘2*n_jobs’, return_train_score=True)
贝叶斯优化用于机器学习调参由J. Snoek(2012)提出,主要思想是,给定优化的目标函数(广义的函数,只需指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数的后验分布(高斯过程,直到后验分布基本贴合于真实分布。简单的说,就是考虑了上一次参数的信息,从而更好的调整当前的参数。
贝叶斯优化与常规的网格搜索或者随机搜索的区别是:
1.贝叶斯调参采用高斯过程,考虑之前的参数信息,不断地更新先验;网格搜索未考虑之前的参数信息。
2.贝叶斯调参迭代次数少,速度快;网格搜索速度慢,参数多时易导致维度爆炸。
3.贝叶斯调参针对非凸问题依然稳健;网格搜索针对非凸问题易得到局部优最。
使用BayesOpt包来进行贝叶斯优化调参,安装命令如下所示:
pip install bayesian-optimization
BayesOpt包主要使用BayesianOptimization函数来创建一个优化对象,该函数接受一个模型评估函数function,这个function的输入应该是xgboost(或者其他ML模型)的超参数,输出是模型在测试集上的效果(可以是Accuracy,也可以是RMSE,取决于具体的任务,一般返回K-Fold的均值)。
基于5-Fold的LightGBM贝叶斯优化的过程如下所示:
import lightgbm as lgb
from bayes_opt import BayesianOptimization
train_X, train_y = None, None
def BayesianSearch(clf, params):
"""贝叶斯优化器"""
# 迭代次数
num_iter = 25
init_points = 5
# 创建一个贝叶斯优化对象,输入为自定义的模型评估函数与超参数的范围
bayes = BayesianOptimization(clf, params)
# 开始优化
bayes.maximize(init_points=init_points, n_iter=num_iter)
# 输出结果
params = bayes.res['max']
print(params['max_params'])
return params
def GBM_evaluate(min_child_samples, min_child_weight, colsample_bytree, max_depth, subsample, reg_alpha, reg_lambda):
"""自定义的模型评估函数"""
# 模型固定的超参数
param = {
'objective': 'regression',
'n_estimators': 275,
'metric': 'rmse',
'random_state': 2018}
# 贝叶斯优化器生成的超参数
param['min_child_weight'] = int(min_child_weight)
param['colsample_bytree'] = float(colsample_bytree),
param['max_depth'] = int(max_depth),
param['subsample'] = float(subsample),
param['reg_lambda'] = float(reg_lambda),
param['reg_alpha'] = float(reg_alpha),
param['min_child_samples'] = int(min_child_samples)
# 5-flod 交叉检验,注意BayesianOptimization会向最大评估值的方向优化,因此对于回归任务需要取负数。
# 这里的评估函数为neg_mean_squared_error,即负的MSE。
val = cross_val_score(lgb.LGBMRegressor(**param),
train_X, train_y ,scoring='neg_mean_squared_error', cv=5).mean()
return val
if __name__ == '__main__':
# 获取数据,这里使用的是Kaggle比赛的数据
train_X, train_y = get_data()
# 调参范围
adj_params = {'min_child_weight': (3, 20),
'colsample_bytree': (0.4, 1),
'max_depth': (5, 15),
'subsample': (0.5, 1),
'reg_lambda': (0.1, 1),
'reg_alpha': (0.1, 1),
'min_child_samples': (10, 30)}
# 调用贝叶斯优化
BayesianSearch(GBM_evaluate, adj_params)