暴力调参——GridSearchCV、RandomizedSearchCV、贝叶斯优化
https://blog.csdn.net/juezhanangle/article/details/80051256
http://www.360doc.com/content/18/0707/15/7669533_768542933.shtml
常用的暴力调参方法,我记得提到过GridSearchCV方法,它是基于网格搜索+交叉验证的,好像也没有怎么提到过其他的方法,今天就把他们补全好了。
在这里你将得到以下信息:
GridSearchCV的温习使用
如何自定义loss,应用于搜索中
RandomizedSearchCV的使用及注意事项
贝叶斯优化原理
贝叶斯优化GBDT实例
GridSearchCV
网格搜索,搜索的是参数,即在指定的参数范围内,按步长依次调整参数,利用调整的参数训练学习器,从所有的参数中找到在验证集上精度最高的参数,这其实是一个循环和比较的过程。
GridSearchCV可以保证在指定的参数范围内找到精度最高的参数,但是这也是网格搜索的缺陷所在,它要求遍历所有可能参数的组合,在面对大数据集和多参数的情况下,非常耗时。这也是我通常不会使用GridSearchCV的原因,一般会采用后一种RandomizedSearchCV随机参数搜索的方法。
交叉验证的概念也很简单
· 将训练数据集划分为K份,K一般为10
· 依次取其中一份为验证集,其余为训练集训练分类器,测试分类器在验证集上的精度
· 取K次实验的平均精度为该分类器的平均精度
网格搜索就是利用交叉验证的形式比较每一个参数下训练器的精度的,但是交叉验证也要求大量的计算资源,加重了网格搜索的搜索时间
接下来以阿里IJCAI广告推荐数据集与XGBoostClassifier分类器为例,用代码的形式说明sklearn中GridSearchCV的使用方法
import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.grid_search import GridSearchCV#导入训练数据
traindata = pd.read_csv("/traindata_4_3.txt",sep = ',')
traindata = traindata.set_index('instance_id')
trainlabel = traindata['is_trade']
del traindata['is_trade']
print(traindata.shape,trainlabel.shape)#分类器使用 xgboost
clf1 = xgb.XGBClassifier()#设定网格搜索的xgboost参数搜索范围,值搜索XGBoost的主要6个参数
param_dist = {'n_estimators':range(80,200,4),'max_depth':range(2,15,1),'learning_rate':np.linspace(0.01,2,20),'subsample':np.linspace(0.7,0.9,20),'colsample_bytree':np.linspace(0.5,0.98,10),'min_child_weight':range(1,9,1)}#GridSearchCV参数说明,clf1设置训练的学习器
#param_dist字典类型,放入参数搜索范围
#scoring = 'neg_log_loss',精度评价方式设定为“neg_log_loss“
#n_iter=300,训练300次,数值越大,获得的参数精度越大,但是搜索时间越长
#n_jobs = -1,使用所有的CPU进行训练,默认为1,使用1个CPU
grid = GridSearchCV(clf1,param_dist,cv = 3,scoring = 'neg_log_loss',n_iter=300,n_jobs = -1)#在训练集上训练
grid.fit(traindata.values,np.ravel(trainlabel.values))
#返回最优的训练器
best_estimator = grid.best_estimator_
print(best_estimator)
#输出最优训练器的精度
print(grid.best_score_)
这里关于网格搜索的几个参数再说明一下,评分参数“scoring“,需要根据实际的评价标准设定,阿里的IJCAI的标准是’neg_log_loss’,所以这里设定的是’neg_log_loss’,sklearn中备选的评价标准有:
如何自定义评价函数
在一些情况下,sklearn中没有现成的评价函数,sklearn是允许我们自己的定义的,但需要注意格式,接下来给个例子
import numpy as np
from sklearn.metrics import make_scorerdef logloss(act, pred):epsilon = 1e-15pred = sp.maximum(epsilon, pred)pred = sp.minimum(1-epsilon, pred)ll = sum(act*sp.log(pred) + sp.subtract(1, act)*sp.log(sp.subtract(1, pred)))ll = ll * -1.0/len(act)return ll#这里的greater_is_better参数决定了自定义的评价指标是越大越好还是越小越好
loss = make_scorer(logloss, greater_is_better=False)
score = make_scorer(logloss, greater_is_better=True)
定义好以后,再将其代入GridSearchCV函数就好
这里再贴一下常用的集成学习算法比较重要的需要调参的参数,供大家参考
RandomizedSearchCV
RandomizedSearchCV的使用方法其实是和GridSearchCV一致的,但它以随机在参数空间中采样的方式代替了GridSearchCV对于参数的网格搜索,在对于有连续变量的参数时,RandomizedSearchCV会将其当作一个分布进行采样这是网格搜索做不到的,它的搜索能力取决于设定的n_iter参数,同样的给出代码
import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.grid_search import RandomizedSearchCV#导入训练数据
traindata = pd.read_csv("/traindata.txt",sep = ',')
traindata = traindata.set_index('instance_id')
trainlabel = traindata['is_trade']
del traindata['is_trade']
print(traindata.shape,trainlabel.shape)#分类器使用 xgboost
clf1 = xgb.XGBClassifier()#设定搜索的xgboost参数搜索范围,值搜索XGBoost的主要6个参数
param_dist = {'n_estimators':range(80,200,4),'max_depth':range(2,15,1),'learning_rate':np.linspace(0.01,2,20),'subsample':np.linspace(0.7,0.9,20),'colsample_bytree':np.linspace(0.5,0.98,10),'min_child_weight':range(1,9,1)}#RandomizedSearchCV参数说明,clf1设置训练的学习器
#param_dist字典类型,放入参数搜索范围
#scoring = 'neg_log_loss',精度评价方式设定为“neg_log_loss“
#n_iter=300,训练300次,数值越大,获得的参数精度越大,但是搜索时间越长
#n_jobs = -1,使用所有的CPU进行训练,默认为1,使用1个CPU
grid = RandomizedSearchCV(clf1,param_dist,cv = 3,scoring = 'neg_log_loss',n_iter=300,n_jobs = -1)#在训练集上训练
grid.fit(traindata.values,np.ravel(trainlabel.values))
#返回最优的训练器
best_estimator = grid.best_estimator_
print(best_estimator)
#输出最优训练器的精度
print(grid.best_score_)
之前笔者犯了个错误,使用错误的scoring评价,导致RandomizedSearchCV不能用于回归搜索,记住scoring很重要的。predict_proba函数用于分类预测概率。
如回归可以采用neg_mean_squared_error,分类可以采用neg_log_loss。具体的scoring方式有很多,推荐看这份博客
https://www.cnblogs.com/jin-liang/p/9539622.html
还有参数的交叉选择与验证参数 推荐看这个
https://blog.csdn.net/u014248127/article/details/78899195
不过建议还是使用随机的搜索。
贝叶斯优化原理
https://www.jianshu.com/p/35eed1567463
网格搜索速度慢,但在搜索整个搜索空间方面效果很好,而随机搜索很快,但可能会错过搜索空间中的重要点。幸运的是,还有第三种选择:贝叶斯优化。本文我们将重点介绍贝叶斯优化的一个实现,一个名为hyperopt
的 Python 模块。
使用贝叶斯优化进行调参可以让我们获得给定模型的最佳参数,例如逻辑回归模型。这也使我们能够执行最佳的模型选择。通常机器学习工程师或数据科学家将为少数模型(如决策树,支持向量机和 K 近邻)执行某种形式(网格搜索或随机搜索)的手动调参,然后比较准确率并选择最佳的一个来使用。该方法可能比较的是次优模型。也许数据科学家找到了决策树的最优参数,但却错过了 SVM 的最优参数。这意味着他们的模型比较是有缺陷的。如果 SVM 参数调整得很差,K 近邻可能每次都会击败 SVM。贝叶斯优化允许数据科学家找到所有模型的最佳参数,并因此比较最佳模型。这会得到更好的模型选择,因为你比较的是最佳的 k 近邻和最佳的决策树。只有这样你才能非常自信地进行模型选择,确保选择并使用的是实际最佳的模型。
假设你有一个定义在某个范围内的函数,并且想把它最小化。也就是说,你想找到产生最低输出值的输入值。下面的简单例子找到x
的值用于最小化线性函数y(x) = x
from hyperopt import fmin, tpe, hp
best = fmin(fn=lambda x: x,space=hp.uniform('x', 0, 1),algo=tpe.suggest,max_evals=100)
print best
我们来分解一下这个例子。
函数fmin
首先接受一个函数来最小化,记为fn
,在这里用一个匿名函数lambda x: x
来指定。该函数可以是任何有效的值返回函数,例如回归中的平均绝对误差。
下一个参数指定搜索空间,在本例中,它是0到1之间的连续数字范围,由hp.uniform('x', 0, 1)
指定。hp.uniform
是一个内置的hyperopt
函数,它有三个参数:名称x
,范围的下限和上限0
和1
。
algo
参数指定搜索算法,本例中tpe
表示 tree of Parzen estimators。该主题超出了本文的范围,但有数学背景的读者可以细读这篇文章。algo
参数也可以设置为hyperopt.random
,但是这里我们没有涉及,因为它是众所周知的搜索策略。但在未来的文章中我们可能会涉及。
最后,我们指定fmin
函数将执行的最大评估次数max_evals
。这个fmin
函数将返回一个python字典。
上述函数的一个输出示例是{'x': 0.000269455723739237}
。
以下是该函数的图。红点是我们试图找到的点。
一个复杂的例子
这有一个更复杂的目标函数:lambda x: (x-1)**2
。这次我们试图最小化一个二次方程y(x)=(x-1)**2
。所以我们改变搜索空间以包括我们已知的最优值(x=1
)加上两边的一些次优范围:hp.uniform('x', -2, 2)
。
现在我们有:
best = fmin(fn=lambda x: (x-1)**2,space=hp.uniform('x', -2, 2),algo=tpe.suggest,max_evals=100)
print best
输出应该看起来像这样:
{'x': 0.997369045274755}
这是函数图。
有时也许我们想要最大化目标函数,而不是最小化它。为此,我们只需要返回函数的负数。例如,我们有函数y(x) = -(x**2)
:
我们如何解决这个问题?我们采用目标函数lambda x: -(x**2)
并返回负值,只需给出lambda x: -1*-(x**2)
或者lambda x: (x**2)
即可。
这里有一个和例子1类似,但我们不是最小化,而是试图最大化。
这里有许多(无限多且无限范围)局部最小值的函数,我们也试图将其最大化:
搜索空间
hyperopt
模块包含一些方便的函数来指定输入参数的范围。我们已经见过hp.uniform
。最初,这些是随机搜索空间,但随着hyperopt
更多的学习(因为它从目标函数获得更多反馈),通过它认为提供给它最有意义的反馈,会调整并采样初始搜索空间的不同部分。
以下内容将在本文中使用:
hp.choice(label, options)
其中options
应是 python 列表或元组。hp.normal(label, mu, sigma)
其中mu
和sigma
分别是均值和标准差。hp.uniform(label, low, high)
其中low
和high
是范围的下限和上限。
其他也是可用的,例如hp.normal
,hp.lognormal
,hp.quniform
,但我们不会在这里使用它们。
为了查看搜索空间的一些例子,我们应该导入另一个函数,同时定义搜索空间。
import hyperopt.pyll.stochasticspace = {'x': hp.uniform('x', 0, 1),'y': hp.normal('y', 0, 1),'name': hp.choice('name', ['alice', 'bob']),
}print hyperopt.pyll.stochastic.sample(space)
一个示例输出是:
{'y': -1.4012610048810574, 'x': 0.7258615424906184, 'name': 'alice'}
尝试运行几次并查看不同的样本。
通过 Trials 捕获信息
如果能看到hyperopt
黑匣子内发生了什么是极好的。Trials
对象使我们能够做到这一点。我们只需要导入一些东西。
from hyperopt import fmin, tpe, hp, STATUS_OK, Trialsfspace = {'x': hp.uniform('x', -5, 5)
}def f(params):x = params['x']val = x**2return {'loss': val, 'status': STATUS_OK}trials = Trials()best = fmin(fn=f, space=fspace, algo=tpe.suggest, max_evals=50, trials=trials)print 'best:', bestprint 'trials:'
for trial in trials.trials[:2]:print trial
STATUS_OK
和Trials
是新导入的。Trials
对象允许我们在每个时间步存储信息。然后我们可以将它们打印出来,并在给定的时间步查看给定参数的函数评估值。
这是上面代码的一个输出示例:
best: {'x': 0.014420181637303776}
trials:
{'refresh_time': None, 'book_time': None, 'misc': {'tid': 0, 'idxs': {'x': [0]}, 'cmd': ('domain_attachment', 'FMinIter_Domain'), 'vals': {'x': [1.9646918559786162]}, 'workdir': None}, 'state': 2, 'tid': 0, 'exp_key': None, 'version': 0, 'result': {'status': 'ok', 'loss': 3.8600140889486996}, 'owner': None, 'spec': None}
{'refresh_time': None, 'book_time': None, 'misc': {'tid': 1, 'idxs': {'x': [1]}, 'cmd': ('domain_attachment', 'FMinIter_Domain'), 'vals': {'x': [-3.9393509404526728]}, 'workdir': None}, 'state': 2, 'tid': 1, 'exp_key': None, 'version': 0, 'result': {'status': 'ok', 'loss': 15.518485832045357}, 'owner': None, 'spec': None}
Trials
对象将数据存储为BSON
对象,其工作方式与JSON对象
相同。BSON
来自pymongo
模块。我们不会在这里讨论细节,这是对于需要使用MongoDB
进行分布式计算的hyperopt
的高级选项,因此需要导入pymongo。回到上面的输出。tid
是时间 id,即时间步,其值从0到max_evals-1
。它随着迭代次数递增。'x'
是键'vals'
的值,其中存储的是每次迭代参数的值。'loss'
是键'result'
的值,其给出了该次迭代目标函数的值。
我们用另一种方式来看看。
可视化
我们将在这里讨论两种类型的可视化:值 vs. 时间与损失 vs. 值。首先是值 vs. 时间。以下是绘制上述Trial.trials
数据的代码和示例输出。
f, ax = plt.subplots(1)
xs = [t['tid'] for t in trials.trials]
ys = [t['misc']['vals']['x'] for t in trials.trials]
ax.set_xlim(xs[0]-10, xs[-1]+10)
ax.scatter(xs, ys, s=20, linewidth=0.01, alpha=0.75)
ax.set_title('$x$ $vs$ $t$ ', fontsize=18)
ax.set_xlabel('$t$', fontsize=16)
ax.set_ylabel('$x$', fontsize=16)
我们可以看到,最初算法从整个范围中均匀地选择值,但随着时间的推移以及参数对目标函数的影响了解越来越多,该算法越来越聚焦于它认为会取得最大收益的区域-一个接近零的范围。它仍然探索整个解空间,但频率有所下降。
现在让我们看看损失 vs. 值的图。
f, ax = plt.subplots(1)
xs = [t['misc']['vals']['x'] for t in trials.trials]
ys = [t['result']['loss'] for t in trials.trials]
ax.scatter(xs, ys, s=20, linewidth=0.01, alpha=0.75)
ax.set_title('$val$ $vs$ $x$ ', fontsize=18)
ax.set_xlabel('$x$', fontsize=16)
ax.set_ylabel('$val$', fontsize=16)
它给了我们所期望的,因为函数y(x)=x**2
是确定的。
总结一下,尝试更复杂的例子,伴随更多的随机性和参数
贝叶斯优化问题有四个部分:
目标函数 objective():我们想要最小化的内容,在这里,目标函数是机器学习模型使用该组超参数通过交叉验证计算损失值。
域空间 space:要搜索的超参数的取值范围。
优化算法 algo:构造替代函数并选择下一个超参数值进行评估的方法。
结果历史记录 result:来自目标函数评估的存储结果,包括超参数和验证集上的损失。
机器学习小demo——iris data + KNN
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.targetdef hyperopt_train_test(params):clf = KNeighborsClassifier(**params)return cross_val_score(clf, X, y).mean()space4knn = {'n_neighbors': hp.choice('n_neighbors', range(1,100))
}def f(params):acc = hyperopt_train_test(params)return {'loss': -acc, 'status': STATUS_OK}trials = Trials()
best = fmin(f, space4knn, algo=tpe.suggest, max_evals=100, trials=trials)
print 'best:'
print best
贝叶斯的GBDT参数寻优
def gbdt_cv(params):#返回参数的lossnfold=5seed=2018val_loss_sum=0kfolder = KFold(n_splits=nfold, shuffle=True, random_state=seed)for fold_id, (trn_idx, val_idx) in enumerate(kfolder.split(train)):print('\nFold_%d Training ================================' % fold_id)traindata=train.iloc[trn_idx][feature_names]trainlabel=train.iloc[trn_idx][ycol]validdata=train.iloc[val_idx][feature_names]validlabel=train.iloc[val_idx][ycol]# 开始训练gbdt_reg=GradientBoostingRegressor(**params)gbdt_reg.fit(traindata, trainlabel)# 验证集预测结果val_pred = gbdt_reg.predict(validdata)val_loss = compute_loss(validlabel.values.ravel(), val_pred)val_loss_sum = val_loss_sum+val_lossprint("gbdt each_cross loss:", val_loss) # 其实是验证集的预测误差val_loss = val_loss_sum / nfoldreturn val_lossdef gbdt_op():print('gbdt_op')# 定义参数列表param_list={'n_estimators': hp.choice('n_estimators', np.arange(80,250,5, dtype=int)),'max_depth': hp.choice('max_depth', np.arange(2,15,1, dtype=int)),'learning_rate':hp.quniform('learning_rate', 0.01,2,0.01),'subsample': hp.uniform('subsample', 0.7,1),'alpha': hp.uniform('alpha', 0.5,1),'min_samples_split': hp.choice('min_samples_split', np.arange(2,10,1, dtype=int))}bayes_trials = Trials()best = fmin(gbdt_cv, param_list, algo=tpe.suggest, max_evals=500, trials=bayes_trials)return best
但是对于choice返回的是索引,需要重新定义choice的搜索列表,根据得到的最佳索引得到相应的最佳数值。
_best=gbdt_op()
n_estimators=np.arange(80,250,5, dtype=int)
max_depth=np.arange(2,15,1, dtype=int)
min_samples_split=np.arange(2,10,1, dtype=int)_best['n_estimators']=n_estimators[ _best['n_estimators'] ]
_best['max_depth']=max_depth[ _best['max_depth'] ]
_best['min_samples_split']=min_samples_split[ _best['min_samples_split'] ]print('GBDT--best params:',_best)
quniform得到的是float类型,对于只能是int的变量,推荐用choice,如采用
hp.choice('n_estimators', np.arange(80,250,5, dtype=int)) 函数
暴力调参——GridSearchCV、RandomizedSearchCV、贝叶斯优化相关推荐
- 比xgboost强大的LightGBM:调参指南(带贝叶斯优化代码)
向AI转型的程序员都关注了这个号??? 大数据挖掘DT数据分析 公众号: datadw xgboost的出现,让数据民工们告别了传统的机器学习算法们:RF.GBM.SVM.LASSO........ ...
- python代码设置超参数_超参数调优总结,贝叶斯优化Python代码示例
本文介绍超参数(hyperparameter)的调优方法. 神经网络模型的参数可以分为两类,模型参数,在训练中通过梯度下降算法更新: 超参数,在训练中一般是固定数值或者以预设规则变化,比如批大小(ba ...
- 使用贝叶斯优化工具实践XGBoost回归模型调参
0. 关于调参 0.1. 超参数 在机器学习的上下文中,超参数(hyper parameters)是在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据.通常情况下,需要对超参数进行优化,给学 ...
- LESSON 10.410.510.6 贝叶斯优化的基本流程BayesOpt vs HyperOpt vs Optuna batch基于BayesOpt实现高斯过程gp优化
超参数优化 - 贝叶斯优化方法 import numpy as np import pandas as pd import sklearn import matplotlib as mlp impor ...
- 贝叶斯优化 Bayesian Optimization
一.介绍 在机器学习的许多模型中,包括决策树.支持向量机.神经网络,都存在着大量的超参数需要凭经验设定(学习率.决策树深度.神经元个数等),也可以使用grid search或者random sea ...
- 随机森林、LGBM基于贝叶斯优化调参
前言 本文基于孕妇吸烟与胎儿问题中数据集与前期处理 针对随机森林与LGBM模型网格搜索效率低,使用贝叶斯调参提高效率 有关于贝叶斯优化包相关参数说明详解可以看GitHub地址 将处理好的数据用dill ...
- 几种机器学习常用调参方式对比(网格搜索,随机搜索,贝叶斯优化)
网格搜索(GridSearchCV): grid search就是穷举,穷举所有得超参组合 Ex:当对决策树调参,若只对一个超参优化,如树的最大深度,尝试[3,5,7],则可表示为 若还想对分裂标准进 ...
- python贝叶斯优化算法_自动调参——贝叶斯优化算法hyperopt
注:转载请注明出处. 本篇文章主要记录了贝叶斯优化算法hyperopt的学习笔记,如果想看自动化调参中的网格调参和遗传优化算法TPOT,请查看我另外两篇文章:网格搜索gridSearchCV和遗传优化 ...
- 随机森林算法及贝叶斯优化调参Python实践
1. 随机森林算法 1.1. 集成模型简介 集成学习模型使用一系列弱学习器(也称为基础模型或基模型)进行学习,并将各个弱学习器的结果进行整合,从而获得比单个学习器更好的学习效果. 集成学习模型的常见算 ...
最新文章
- 编译器设计-代码生成
- 合成孔径成像算法与实现_声呐二维成像技术
- MSSQL数据库C#操作类(SQLHELPER类的修改版)
- Git使用出错:Couldn‘t reserve space for cygwin‘s heap, Win32
- 网络编程知识预备(3) ——SOCKET、TCP、HTTP之间的区别与联系
- Vue 导入文件import、路径@和.的区别
- Python学习5 元组基础知识和常用函数
- Mac osx 下配置ANT
- VUE自学日志01-MVC和MVVM
- 初步学习nodejs,业余用node写个一个自动创建目录和文件的小脚本,希望对需要的人有所帮助...
- [C语言] 插入排序之希尔(shell)排序的特性及实现
- C++ placement new使用
- ESET NOD32 升级 激活码 用户名和密码~MF111
- 勉强算是面经——1.诺瓦科技
- 外设驱动库开发笔记41:ADS1256 ADC驱动
- v-model中修饰符lazy,number, trim的作用
- 六套苹果CMSv10首涂手机视频站模板高端主题代码精简优化SEO
- 全网火爆高颜值蓝牙耳机,低延迟游戏党必备蓝牙耳机推荐
- 【揭秘】美团外卖日单量破1600万背后的“超级大脑”之订单分配
- 三菱ST言语编程梳理
热门文章
- 数据库常规体检说明教程(运维)
- 奥运英语[5] 很高兴再次见到你 Good to see you again.
- ACE: Ally Complementary Experts for Solving Long-Tailed Recognition in One-Shot(2022.5.27)
- 磊科路由器dns服务器无响应,磊科MG1200AC的DNS抽风问题
- 灵感:从想法的天空到现实的地面
- Unity涂鸦【1】——基于Vectrosity的屏幕涂鸦和白板涂鸦的简单实现
- 如何运营京东店铺 京东店铺运营注意事项有哪些
- 笔记:模电-1.3三极管(晶体管)
- 阿里云 龙珠机器学习训练营Task1:机器学习算法(一): 基于逻辑回归的分类预测
- form 表单中action是用来干什么的