超参数
机器学习模型中有大量需要事先进行人为设定的参数,比如说神经网络训练的batch-size,XGBoost等集成学习模型的树相关参数,我们将这类不是经过模型训练得到的参数叫做超参数(hyperparameter)。人为的对超参数调整的过程也就是我们熟知的调参。
常见的调参方法
机器学习中常用的调参方法包括网格搜索法(grid search)、随机搜索法(random search)和贝叶斯优化(bayesian optimization)。
网格搜索法
网格搜索是一项常用的超参数调优方法,常用于优化三个或者更少数量的超参数,
本质是一种穷举法。对于每个超参数,使用者选择一个较小的有限集去探索。然后,这些超参数笛卡尔乘积得到若干组超参数。网格搜索使用每组超参数训练模型,挑选验证集误差最小的超参数作为最好的超参数。
例如,有三个需要优化的超参数a,b,c,候选的取值分别是{1,2},{3,4},{5,6}。则所有可能的参数取值组合组成了一个8个点的3维空间网格如下:{(1,3,5),(1,3,6),(1,4,5),(1,4,6),(2,3,5),(2,3,6),(2,4,5),(2,4,6)},网格搜索就是通过遍历这8个可能的参数取值组合,进行训练和验证,最终得到最优超参数。
Sklearn中通过model_selection模块下的GridSearchCV来实现网格搜索调参,并且这个调参过程是加了交叉验证的。
### 基于XGBoost的GridSearch搜索范例
# 导入GridSearch模块
from sklearn.model_selection import GridSearchCV
# 创建xgb分类模型实例
model = xgb.XGBClassifier()
# 待搜索的参数列表空间
param_lst = {"max_depth": [3,5,7],
"min_child_weight" : [1,3,6],
"n_estimators": [100,200,300],
"learning_rate": [0.01, 0.05, 0.1]
}
# 创建网格搜索
grid_search = GridSearchCV(model, param_grid=param_lst, cv=3,
verbose=10, n_jobs=-1)
# 基于flights数据集执行搜索
grid_search.fit(X_train, y_train)
# 输出搜索结果
print(grid_search.best_estimator_)
代码给出了基于XGBoost的网格搜索范例。先创建XGBoost分类模型实例,然后给出需要搜索的参数和对应的参数范围列表,并基于GridSearch创建网格搜索对象,最后拟合训练数据,输出网格搜索的参数结果。可以看到,当树最大深度为5、最小子树权重取6以及树的棵数为300时,模型能达到相对最优的效果。
随机搜索
随机搜索,顾名思义,即在指定的超参数范围或者分布上随机搜索和寻找最优超参数。相较于网格搜索方法,给定超参数分布内并不是所有的超参数都会进行尝试,而是会从给定分布中抽样一个固定数量的参数,实际仅对这些抽样到的超参数进行实验。相较于网格搜索,随机搜索有时候会是一种更高效的调参方法。
Sklearn中通过model_selection模块下RandomizedSearchCV方法进行随机搜索。基于XGBoost的随机搜索调参示例如代码所示。
### 基于XGBoost的GridSearch搜索范例
# 导入GridSearch模块
from sklearn.model_selection import RandomizedSearchCV
# 创建xgb分类模型实例
model = xgb.XGBClassifier()
# 待搜索的参数列表空间
param_lst = {"max_depth": [3,5,7],
"min_child_weight" : [1,3,6],
"n_estimators": [100,200,300],
"learning_rate": [0.01, 0.05, 0.1]
}
# 创建网格搜索
random_search =RandomizedSearchCV(model, param_grid=param_lst, cv=3,
verbose=10, n_jobs=-1)
# 基于flights数据集执行搜索
random_search.fit(X_train, y_train)
# 输出搜索结果
print(random_search.best_estimator_)
代码给出了随机搜索的使用示例,模式上跟网格搜索基本一致,可以看到,随机搜索的结果认为树的棵树取300,最小子树权重为6,最大深度为5,学习率取0.1的时候模型达到最优。
贝叶斯调参
可能是最好的一种调参方法,即贝叶斯优化。贝叶斯优化是一种基于高斯过程(gaussian process)和贝叶斯定理的参数优化方法,近年来被广泛用于机器学习模型的超参数调优。这里不详细探讨高斯过程和贝叶斯优化的数学原理,仅展示贝叶斯优化的基本用法和调参示例。
贝叶斯优化其实跟其他优化方法一样,都是为了为了求目标函数取最大值时的参数值。作为一个序列优化问题,贝叶斯优化需要在每一次迭代时选取一个最佳观测值,这是贝叶斯优化的关键问题。而这个关键问题正好被上述的高斯过程完美解决。关于贝叶斯优化的大量数学原理,包括高斯过程、采集函数、Upper Confidence Bound(UCB)和Expectation Improvements(EI)等概念原理,限于篇幅不做展开描述。贝叶斯优化可直接借用现成的第三方库BayesianOptimization来实现。
### 基于XGBoost的BayesianOptimization搜索范例
# 导入xgb模块
import xgboost as xgb
# 导入贝叶斯优化模块
from bayes_opt import BayesianOptimization
# 定义目标优化函数
def xgb_evaluate(min_child_weight,
colsample_bytree,
max_depth,
subsample,
gamma,
alpha):
# 指定要优化的超参数
params['min_child_weight'] = int(min_child_weight)
params['cosample_bytree'] = max(min(colsample_bytree, 1), 0)
params['max_depth'] = int(max_depth)
params['subsample'] = max(min(subsample, 1), 0)
params['gamma'] = max(gamma, 0)
params['alpha'] = max(alpha, 0)
# 定义xgb交叉验证结果
cv_result = xgb.cv(params, dtrain, num_boost_round=num_rounds, nfold=5,
seed=random_state,
callbacks=[xgb.callback.early_stop(50)])
return cv_result['test-auc-mean'].values[-1]
# 定义相关参数
num_rounds = 3000
random_state = 2021
num_iter = 25
init_points = 5
params = {
'eta': 0.1,
'silent': 1,
'eval_metric': 'auc',
'verbose_eval': True,
'seed': random_state
}
# 创建贝叶斯优化实例
# 并设定参数搜索范围
xgbBO = BayesianOptimization(xgb_evaluate,
{'min_child_weight': (1, 20),
'colsample_bytree': (0.1, 1),
'max_depth': (5, 15),
'subsample': (0.5, 1),
'gamma': (0, 10),
'alpha': (0, 10),
})
# 执行调优过程
xgbBO.maximize(init_points=init_points, n_iter=num_iter)
代码给出了基于XGBoost的贝叶斯优化示例,在执行贝叶斯优化前,我们需要基于XGBoost的交叉验证xgb.cv定义一个待优化的目标函数,获取xgb.cv交叉验证结果,并以测试集AUC为优化时的精度衡量指标。最后将定义好的目标优化函数和超参数搜索范围传入贝叶斯优化函数BayesianOptimization中,给定初始化点和迭代次数,即可执行贝叶斯优化。