TPE CMAES 网格搜索 随机搜索 贝叶斯优化
用贝叶斯优化进行超参数调优
@QI ZHANG · JUL 12, 2019 · 7 MIN READ
超参数调优一直是机器学习里比较intractable的问题,繁多的超参数以及指数型爆炸的参数空间,往往让人无从下手。调参是一个很枯燥的过程,而且最后也不一定有很好的reward。很多的机器学习工程师也会戏称自己是”调参民工”,”炼丹师”……
超参数(Hyper-parameters):Hyper-parameters are parameters that are not directly learnt within estimators.
超参数的优化可以看做是这样一个方程:
???=argmin??∈??(??)x?=arg?minx∈Xf(x)
其中??(??)f(x) 表示目标函数,用于衡量误差,可以是MSE, RMSE, MAE等(如果是accuracy等指标可以将其添加负号求最小值),???x?是使得??(??)f(x)最小的参数组合,理论上我们的目标就是要找到这个???x?,但是要找到这样一个全局最优解几乎是不可能的。首先这个??(??)f(x)是个黑盒子,我们没法直接进行优化求解。事实上,我们每次为了得到??(??)f(x),需要经过模型训练和评估,非常耗时,尤其对于一些深度学习模型,这个过程会特别漫长。我们只能在有限的计算资源和时间内,得到一些相对的局部最优解。
一般的调参方法有下面几种:
手动调参(Manual Search)
网格搜索(Grid Search)
随机搜索(Randomized Search)
贝叶斯优化(Bayesian Optimization)
1. 手动调参
对于手动调参,会对模型最重要的一些参数基于经验进行调节。比如lightgbm的叶num_leaves, learning_rate, feature_fraction, lambda_l1,lambda_l2, min_data_in_leaf等。
2. Randomized Search vs Grid Search
Grid Search会对定义的参数空间进行暴力搜索。网格搜索速度慢,但在搜索整个搜索空间方面效果很好。Randomized Search是从定义的参数空间中进行采样,然后训练。随机搜索很快,但可能会错过搜索空间中的重要点。
事实上,调参的时候,不需要遍历模型的所有参数。事实上,影响效果的往往只有其中的几个参数,一般对这些参数进行Randomized Search或者Grid Search即可。具体可以查看模型文档,或相关文献。
# Comparing randomized search and grid search for hyperparameter estimation
import numpy as np
from time import time
from scipy.stats import randint as sp_randint
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
# get some data
digits = load_digits()
X, y = digits.data, digits.target
# build a classifier
clf = RandomForestClassifier(n_estimators=20)
# Utility function to report best scores
def report(results, n_top=3):
for i in range(1, n_top + 1):
candidates = np.flatnonzero(results[‘rank_test_score‘] == i)
for candidate in candidates:
print("Model with rank: {0}".format(i))
print("Mean validation score: {0:.3f} (std: {1:.3f})".format(
results[‘mean_test_score‘][candidate],
results[‘std_test_score‘][candidate]))
print("Parameters: {0}".format(results[‘params‘][candidate]))
print("")
# specify parameters and distributions to sample from
param_dist = {"max_depth": [3, None],
"max_features": sp_randint(1, 11),
"min_samples_split": sp_randint(2, 11),
"bootstrap": [True, False],
"criterion": ["gini", "entropy"]}
# run randomized search
n_iter_search = 20
random_search = RandomizedSearchCV(clf, param_distributions=param_dist,
n_iter=n_iter_searc