选自中等
机器学习算法的性能高度依赖于超参数的选择,优化机器学习的超参数是一项繁琐而关键的任务。介绍了一个利用Hyperopt库实现梯度提升机贝叶斯超参数优化的完整实例,并重点介绍了其实现过程。
由于机器学习算法的性能高度依赖于超参数的选择,因此优化机器学习的超参数是一项繁琐但至关重要的任务。人工调整占用了机器学习算法过程中的一些关键步骤,如特征工程和结果解释。网格搜索和随机搜索不会干扰这些步骤,但是需要大量的运行时间,因为浪费时间去评估搜索空,不太可能找到最佳区域。如今,越来越多的超参数整定过程是通过自动化方法来完成的,其目的是通过使用带有策略的启发式搜索在更短的时间内找到最优超参数,除了初始设置之外,不需要额外的手动操作。
贝叶斯优化是一种基于模型的寻找函数最小值的方法。最近,贝叶斯优化被应用于机器学习超参数优化。结果表明,该方法在测试集上表现较好,但需要的迭代次数比随机搜索少。此外,一些Python库的出现,使得任何机器学习模型都更容易实现贝叶斯超参数调优。
本文介绍了一个梯度提升机贝叶斯超参数整定的完整实例。在前面的一篇文章中,作者已经概述了这个方法背后的概念,因此本文将重点关注实现过程。类似于大多数机器学习主题,读者不需要了解所有细节,但是了解基本原理可以帮助读者更有效地使用这项技术!
本文的所有代码都可以在GitHub上以Jupyter Notebook(https://GitHub . com/WillKoehrsen/hyperparameter-optimization)的形式获得。
本文内容:
贝叶斯优化方法优化问题的四个组成部分目标函数域空间优化算法结果的历史数据优化搜索结果搜索结果的可视化搜索的演化过程继续搜索结语贝叶斯优化方法
简单来说,贝叶斯优化是基于过去对目标的评价结果,通过建立代理函数(概率模型)来寻找目标函数的最小值。代理函数比目标函数更容易优化,因此要评估的下一个输入值是通过对代理函数应用一些标准(通常是预期的提升)来选择的。贝叶斯方法不同于随机搜索或网格搜索,两者都是利用过去的评估结果来选择下一个要评估的值。他们的想法是通过根据过去表现良好的值选择下一个输入值来限制评估目标函数的高成本。
对于超参数优化,目标函数是使用一组超参数的机器学习模型的验证误差。其目标是找出验证集中产生最小误差的超参数,并希望将这些结果推广到测试集。评估目标函数的成本是巨大的,因为它需要用一组特定的超参数来训练机器学习模型。理想情况下,我们希望找到这样一种方法,既能探索搜索空,又能限制耗时的超参数求值。贝叶斯超参数优化使用不断更新的概率模型,使得搜索过程“聚焦”于通过从过去的结果进行推理来达到最优超参数。
Python环境下有一些贝叶斯优化库,它们的目标函数代理算法是不同的。本文将使用“Hyperopt”库,该库使用tree Parzen赋值器(TPE,https://papers . nips . cc/paper/4443-algorithms-for-hyper-parameter-optimization . pdf)作为搜索算法,其他Python库也包括“Spearmint”目前这方面有很多有趣的研究,所以如果你对某个库不满意,可以尝试其他选项!一个问题的一般结构(本文要用到的结构)可以在不同的库之间转换,其句法差异非常小。
优化问题的四个组成部分
贝叶斯优化问题有四个组成部分:
1.目标函数:我们希望最小化的对象,它是指具有超参数的机器学习模型的验证误差
2.domain 空之间:要搜索的超参数值
3.优化算法:构建代理模型并选择下一个要评估的超参数值的方法
4.结果的历史数据:存储的目标函数评估结果,包括超参数和验证损失
通过以上四个步骤,我们可以优化任意实函数(求最小值)。这是一个强大的抽象过程,可以帮助我们解决机器学习超参数整定之外的很多其他问题。
数据集
在这个例子中,我们将使用房车保险数据集(https://www . kaggle . com/ucml/Caravan-Insurance-challenge),其目标是预测客户是否会购买保险产品。这是一个有5800个训练观察值和4000个测试点的监督分类问题。由于这是一个不平衡的分类问题,本文中用于评估性能的指标是接收机工作特性曲线(ROCAC)下的面积。ROCAC值越高越好。值为1表示模型是完美的。数据集如下:
一个数据集(CARAVAN)被标记
由于超点是为了得到最小值,我们将从目标函数返回“1-ROC AUC”来提高ROC AUC。
梯度提升模型
在本文中,我们不会过多讨论梯度提升机的细节。以下是我们需要了解的基础知识:GBM是基于使用顺序训练的弱学习者(多为决策树)来构建强学习者的综合增强方法。GBM中有许多超参数,它们控制着整个集成结构和单个决策树。选择这里使用的决策树(称为评估器)数量的最有效方法之一是提前停止。LightGBM在Python环境中提供了一个快速简单的GBM实现。
想了解更多 GBM 的细节,这里有一篇高屋建瓴的文章:https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d一篇技术论文:https://brage.bibsys.no/xmlui/bitstream/handle/11250/2433761/16128_FULLTEXT.pdf除了必要的背景知识,让我们列出超参数优化贝叶斯优化问题的四个组成部分。
目标函数
我们试图最小化目标函数。它的输入是一组值——在这种情况下是GBM的超参数,它的输出是需要最小化的实值——交叉验证损失。Hyperopt将目标函数视为一个黑盒,因为这个库只关心输入和输出是什么。为了找到使损失最小的输入值,算法不需要知道目标函数的内部细节!从高度抽象的层面(以伪代码的形式),我们的目标函数可以表示为:
散焦(超参数):
"""从超参数返回验证分数" " "
模型=分类器(超参数)
验证_损失=交叉验证(模型,训练_数据)
returnvalidation_loss
在评估最终模型时,要注意不要使用测试集上的损失,因为我们只能使用一次测试集。相反,我们评估验证集上的超参数。此外,我们使用K倍交叉验证,而不是将数据分成独立的验证集。这种验证方法不仅保留了有价值的训练数据,而且使我们能够在测试集上获得偏差较小的误差估计。
不同模型的目标函数的基本结构是相同的:函数接收超参数作为输入,并使用这些超参数返回交叉验证错误。虽然本文的例子是针对GBM的,但是这种结构也可以应用到其他方法中。
下图显示了GBM的完整目标函数,它使用10倍交叉验证和早期停止机制:
importlightgbm aslgb
fromhyperopt导入状态_确定
N_FOLDS = 10
#创建数据集
train_set = lgb。数据集(列车要素、列车标签)
散焦(参数,n_folds = N_FOLDS):
" " "梯度增强机器超参数调整的目标函数"/>
现在让我们定义整个领域:
#定义搜索空间
space = {
class _ weight ':HP . choice(' class _ weight ',[ None,' balanced']),
boosting _ type ':HP . choice(' boosting _ type ',
[{ 'boosting_type': 'gbdt ',
subsample ':HP . uniform(' gdbt _ subsample ',0.5,1)},
{ 'boosting_type': 'dart ',
子样本':hp.uniform( 'dart_subsample ',0.5,1)},
{ 'boosting_type': 'goss'}]),
num _ leaves ':HP . qun iform(' num _ leaves ',30,150,1),
learning _ rate ':HP . loguniform(' learning _ rate ',np.log( 0.01),np.log( 0.2)),
sub sample _ for _ bin ':HP . qun iform(' sub sample _ for _ bin ',20000,300000,20000),
min _ child _ samples ':HP . qun iform(' min _ child _ samples ',20,500,5),
reg _ alpha ':HP . uniform(' reg _ alpha ',0.0,1.0),
reg _ lambda ':HP . uniform(' reg _ lambda ',0.0,1.0),
col sample _ bytree:' HP . uniform(' col sample _ by _ tree ',0.6,1.0)
}
这里我们使用许多不同种类的域分布:
choice:类别变量quniform:离散均匀分布(在整数空间上均匀分布)uniform:连续均匀分布(在浮点数空间上均匀分布)loguniform:连续对数均匀分布(在浮点数空间中的对数尺度上均匀分布)在定义增压类型时,有一个要点需要我们注意:
# boosting类型域
boosting _ type = { ' boosting _ type ':HP . choice(' boosting _ type ',
[{ 'boosting_type': 'gbdt ',
子样本':hp.uniform('子样本',0.5,1)},
{ 'boosting_type': 'dart ',
子样本':hp.uniform('子样本',0.5,1)},
{ 'boosting_type': 'goss ',
子样本':1.0}])}
这里,我们使用一个条件字段,这意味着一个超参数的值依赖于另一个超参数的值。对于“高斯”型提升算法,GBM不能使用下采样技术(为每次迭代选择训练观察数据的子样本部分)。因此,如果升级类型为“goss”,则下采样速率设置为1.0(不使用下采样),否则设置为0.5-1.0。这个过程是使用嵌套域实现的。
当我们使用参数完全不同的机器学习模型时,条件嵌套通常是有用的。条件嵌套允许我们根据“选择”的不同值使用不同的超参数集。
现在已经定义了域空,我们可以从中提取一个样本来查看典型样本的形式。当我们采样时,因为子样本最初是嵌套的,所以我们需要将其分配给顶层关键字。这个操作是通过Python字典的“get”方法实现的,默认值为1.0。
#从整个空间取样
示例=样本(空间)
#默认字典获取方法
sub sample = example[' boosting _ type ']。get('子样本',1.0)
#分配顶级密钥
示例[ 'boosting_type'] =示例[' boosting _ type '][' boosting _ type ']
示例['子样本'] =子样本
例子
有必要重新分配嵌套的关键字,因为梯度电梯无法处理嵌套的超参数字典。
最优化算法
虽然从概念上来说,这是贝叶斯优化中最困难的部分,但是在Hyperopt中创建一个优化算法只需要一行代码。使用树Parzen估计器(TPE)的代码如下:
fromhyperopt importtpe
#算法
tpe_algorithm = tpe .建议
这都是优化算法的代码!Hyperopt目前只支持TPE和随机搜索,虽然其GitHub主页声称还会开发其他方法。在优化过程中,TPE算法根据过去的搜索结果构建概率模型,并通过最大化期望提升(EI)来确定下一组目标函数中要评估的超参数。
结果历史数据
跟踪这些结果不是绝对必要的,因为Hyperopt在算法内部会这样做。然而,如果我们想知道这背后发生了什么,我们可以使用“试验”对象,它将存储基本的训练信息,还可以使用目标函数返回的字典(包括损失“loss”和参数“params”)。创建“试验”对象也只需要一行代码:
来自hyperopt导入试验
#试验对象跟踪进度
贝叶斯试验=试验()
我们监控长期培训进度的另一种方法是在每次迭代中向csv文件写入一行。这样,所有搜索结果都存储在磁盘上,以防止我们因意外事件(根据经验)而丢失“踪迹”对象。我们可以使用“csv”库来做到这一点。在开始培训之前,我们会打开一个新的csv文件,并将其写入hearder:
importcsv
#保存第一个结果的文件
out _ file = ' GBM _ tritions . CSV '
of_connection = open(out_file,' w ')
writer = CSV . writer(of _ connection)
#将标题写入文件
writer . writer row([' loss ',' params ',' iteration ',' estimators ',' train_time'])
of_connection.close()
然后在目标函数中,我们可以添加几行代码,在每次迭代中编写csv文件(完整的目标函数可以在笔记本中获得。
#写入csv文件(' a '表示追加)
of_connection = open(out_file,' a ')
writer = CSV . writer(of _ connection)
writer . writerrow([损失,参数,迭代,n _ estimators,运行时间)
of_connection.close()
写csv文件意味着我们可以通过在培训时打开文件来检查进度(不是在Excel文件中,因为Excel在Python环境中会产生错误。使用bash中的“tail out_file.csv”操作查看文档的最后一行。)
优化
当我们完成以上四个部分后,我们可以通过“fmin”来优化它们:
fromhyperopt importfmin
MAX_EVALS = 500
#优化
best = fmin(fn = objective,space = space,algo = TPE . advise,
max_evals = MAX_EVALS,trials = bayes _ trials)
在每次迭代中,优化算法从基于先前结果构建的代理函数中选择新的超参数值,并在目标函数中计算这些值。然后用“MAX_EVALS”对目标函数求值,代理函数根据新的结果不断更新。
结果
从“fmin”返回的最佳对象包含对目标函数产生最小损失的超参数:
有了这些超参数,我们就可以用它们在完整的训练数据上训练模型,然后对测试数据进行评估(记住我们在评估最终模型时只能使用测试集一次)。至于评价者的数量,我们可以用交叉验证中早期停止时返回损失最小的评价者的数量。最终结果如下:
作为参考,500轮随机搜索返回的模型在测试集中的ROC AUC得分为0.7232,在交叉验证中的得分为0.76850。测试集上未优化默认模型的ROC AUC分数为0.7143。
当我们查看结果时,我们需要记住以下要点:
最优的超参数在交叉验证中表现最好,但并不一定在测试数据上表现最好。当我们使用交叉验证时,我们希望这些结果能够泛化至测试数据上。即使使用 10 折交叉验证,超参数调优还是会对训练数据过度拟合。交叉验证取得的最佳得分远远高于在测试数据上的得分。随机搜索可能由于运气好而返回更好的超参数(重新运行 notebook 就可能改变搜索结果)。贝叶斯优化不能保证找到更好的超参数,并且可能陷入目标函数的局部最小值。虽然贝叶斯优化非常有效,但它不能解决我们所有的调优问题。随着搜索的进行,算法将从探索-尝试新的超参数值变为开发-使用超参数值来最小化目标函数的损失。如果算法找到目标函数的局部最小值,它可以集中于搜索接近局部最小值的超参数值,并且不会尝试域空中远离局部最小值的其他值。随机搜索不会受到这个问题的影响,因为它不会专注于搜索任何值!
还有一点很重要,超参数优化的效果会随着数据集的变化而变化。本文使用了一个相对较小的数据集(约6000个训练观测数据),所以调优超参数的回报很小(得到更多的数据会更好的利用时间!考虑到所有这些因素,在这种情况下,我们可以得到:
在测试集上更好的性能更少的超参数调优迭代次数贝叶斯方法可以(虽然不总是)获得比随机搜索更好的调整结果。在接下来的几节中,我们将看看贝叶斯超参数搜索的演化过程,并与随机搜索进行比较,从而了解贝叶斯优化的工作原理。
搜索结果的可视化
通过绘制结果,我们可以直观地了解超参数搜索过程中发生了什么。此外,将贝叶斯优化与随机搜索进行比较有助于我们看到这些方法之间的差异。想知道这些图是怎么画出来的,随机搜索是怎么实现的,可以参考项目笔记本。但是在这里我们将直接展示结果。(请注意,实际结果会随着迭代次数的增加而改变,所以如果你运行这个笔记本,你不应该惊讶于得到不同的图形。本节所有图像均经过500次迭代后获得)。
首先,我们可以画出随机搜索和贝叶斯优化中采样的学习率“learning_rate”的核密度估计图。作为参考,我们也可以展示样本的分布。垂直虚线表示学习率的最佳值(根据交叉验证获得)。
我们将学习率定义为0.005-0.2之间的对数正态分布,贝叶斯优化的结果与抽样分布的结果相似。这说明我们定义的分布似乎适合这个任务,虽然最优值略高于我们放概率最大的位置。该结果可用于通知域之间的进一步搜索空。
另一个超级参数是推广类型。下图显示了随机搜索和贝叶斯优化过程中评估的每种类型的直方图。因为随机搜索并不关心以往的搜索结果,所以我们期望每种推广类型的使用次数大致相同。
根据贝叶斯算法评估结果的直方图,“gbdt”比“dart”或“goss”更容易找到最优值。同样,这有助于为进一步的搜索提供信息,无论是贝叶斯方法还是网格搜索。如果我们想进行更精确的网格搜索,我们可以使用这些结果来定义一个更小的网格,重点关注最有可能找到最佳超参数的值。
现在我们有了这些结果,我们可以在贝叶斯优化中查看所有参考分布、随机搜索和数值超参数。垂直虚线表示每次搜索都是超参数的最佳值:
在大多数情况下(除了“子样本_for_bin”),贝叶斯优化搜索往往侧重于搜索(设置更高的概率)在交叉验证中可以获得最小损失的超参数值附近的值。这反映了使用贝叶斯方法进行超参数整定的基本思想:花更多的时间评估更有可能达到最优值的超参数值。
有些结果很有趣,可能有助于我们在未来定义一个搜索域空。例如,“reg_alpha”和“reg_lambda”似乎是互补的:如果其中一个值为高(接近1.0),另一个值将变低。我们不能保证这适用于不同的问题,但是通过研究这些结果,我们可以得到一些可能用于未来机器学习问题的思路!
搜索的进化过程
随着优化的进展,我们希望贝叶斯方法关注更有可能达到最佳超参数的值:在交叉验证中产生最低误差的值。我们可以画一个超参数域的迭代次数图,看看是否有明显的趋势。
黑星代表最好的价值。“colsample_bytree”和“learning_rate”随着时间的推移而减少,这可以为我们今后的搜索提供指导。
最后,如果贝叶斯优化是有效的,我们期望平均验证分数会随着时间越来越高(相反,损失会越来越小):
随着时间的推移,贝叶斯超参数优化的验证分数会越来越高,这说明这种方法是在试图获得更好的超参数值(值得注意的是,这些值只是根据验证分数就更好)。随机搜索并没有随着迭代次数的增加而表现出性能的提高。
继续搜索
如果对模型的性能不满意,可以使用Hyperopt从上次结束的地方继续搜索。我们只需要传入同一个“Trials”对象,算法就会继续搜索。
随着算法的运行,它将进行更多的“利用”操作——选择过去表现良好的值,而较少的“探索”操作——选择新值。所以,不如从头开始找,而不是从最后一个地方开始找。如果在第一次搜索中找到的最佳超参数真的是“最优值”,我们期望下一次搜索会收敛到相同的值。考虑到这个高维问题和超参数之间复杂的相互作用,另一个搜索不太可能产生类似的超参数集。
经过500轮迭代训练,最终模型在测试集上的ROC AUC评分为0.72736。(我们真的不应该评价测试集上的第一个模型,只以验证分数为依据。理想情况下,测试集应该只使用一次,以测试算法在新数据上部署时的性能)。同样,由于数据集的规模较小,这个问题在未来的超参数优化中可能会得到一个逐渐减小的返回值,并最终在验证误差中达到一个稳定的值(任何模型对数据集的性能都有一个固有的局限性,因为隐藏变量是不可测量的,并且存在噪声数据,这种情况称为贝叶斯误差)。
标签
我们可以利用贝叶斯优化来完成机器学习模型的自动超参数整定。与随机搜索方法不同,贝叶斯优化通过启发式方法选择下一个超级参数,因此可以花费更多的时间来评估可能的最优值。最终的结果可能是,与随机搜索或网格搜索相比,贝叶斯优化对目标函数的评估次数更少,对测试集的泛化能力更强。
本文利用Hyperopt在Python环境下逐步实现贝叶斯超参数优化。虽然我们需要更加注意训练数据的过拟合,但是我们在测试集上改进了梯度提升机的性能,超过了比较基线和随机搜索方法。此外,我们还通过查看结果示意图,看到了随机搜索和贝叶斯优化的区别,说明贝叶斯方法在交叉验证中会给损失较低的超参数值以较高的概率。
通过使用优化问题的四个组成部分,我们可以使用Hyperopt来解决各种问题。贝叶斯优化的基本组件也适用于大量实现其他算法的Python库。从手动调优到随机搜索或者网格搜索只是一个很小的进步,但是如果你想把你的机器学习技术提升到一个新的水平,就需要自动超参数调优。贝叶斯优化是一种可以在Python环境下使用的方法,比随机搜索能返回更好的结果。希望你能有信心的开始把这种强大的技术应用到你的机器学习问题上!
原地址:https://towards data ience . com/automated-machine-learning-hyperparameter-tuning-in-python-dfda 59 b 72 f 8a
这篇文章是为机器的核心编写的。请联系本微信官方账号进行授权。
1.《超参数 资源 | Python 环境下的自动化机器学习超参数调优》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《超参数 资源 | Python 环境下的自动化机器学习超参数调优》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/guoji/1580090.html