热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一文汇总机器学习超参自动优化方法(附Python代码)

文章目录一、网格搜索(GridSearch)技术提升二、随机搜索(RandomizedSearch)三、贝叶斯优化(BayesianOptimization)四、Hyperband

文章目录

    • 一、网格搜索(Grid Search)
    • 技术提升
    • 二、随机搜索(Randomized Search)
    • 三、贝叶斯优化(Bayesian Optimization)
    • 四、Hyperband
    • 五、总结


一、网格搜索(Grid Search)

网格搜索是暴力搜索,在给定超参搜索空间内,尝试所有超参组合,最后搜索出最优的超参组合。sklearn已实现该方法,使用样例如下:

from sklearn import svm, datasets
from sklearn.model_selection import GridSearchCV
import pandas as pd# 导入数据
iris = datasets.load_iris()
# 定义超参搜索空间
parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
# 初始化模型
svc = svm.SVC()
# 网格搜索
clf = GridSearchCV(estimator = svc,param_grid = parameters,scoring = 'accuracy',n_jobs = -1,cv = 5)
clf.fit(iris.data, iris.target)
返回:GridSearchCV(cv=5, estimator=SVC(), n_jobs=-1,param_grid={'C': [1, 10], 'kernel': ('linear', 'rbf')},scoring='accuracy')# 打印结果
print('详细结果:\n', pd.DataFrame.from_dict(clf.cv_results_))
print('最佳分类器:\n', clf.best_estimator_)
print('最佳分数:\n', clf.best_score_)
print('最佳参数:\n', clf.best_params_).
返回:
详细结果:mean_fit_time std_fit_time mean_score_time std_score_time param_C ... split3_test_score split4_test_score mean_test_score std_test_score rank_test_score
0 0.000788 0.000394 0.000194 0.000389 1 ... 0.966667 1.0 0.980000 0.016330 1
1 0.000804 0.000402 0.000199 0.000399 1 ... 0.933333 1.0 0.966667 0.021082 4
2 0.000593 0.000484 0.000593 0.000484 10 ... 0.966667 1.0 0.973333 0.038873 3
3 0.000593 0.000484 0.000399 0.000489 10 ... 0.966667 1.0 0.980000 0.016330 1
[4 rows x 15 columns]
最佳分类器:SVC(C=1, kernel='linear')
最佳分数:
0.9800000000000001
最佳参数:{'C': 1, 'kernel': 'linear'}

sklearn.model_selection.GridSearchCV[1]的重要参数说明:

  • estimator: scikit-learn模型。

  • param_grid: 超参搜索空间,即超参数字典。

  • scoring: 在交叉验证中使用的评估策略。

  • n_jobs: 并行任务数,-1为使用所有CPU。

  • cv: 决定采用几折交叉验证。


技术提升

本文来自群小伙伴分享,代码、数据、技术提升,可以加入目前我们已开通了技术交流群,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友

方式1、微信搜索公众号:机器学习社区,后台回复:加群;
方式2、可以直接加微信号:mlc2060。加的时候备注一下:研究方向+CSDN,即可。然后就可以拉你进群了。


二、随机搜索(Randomized Search)

随机搜索是在搜索空间中采样出超参组合,然后选出采样组合中最优的超参组合。随机搜索的好处如下图所示:

图片

图1: 网格搜索和随机搜索的对比[2]

解释图1,如果目前我们要搜索两个参数,但参数A重要而另一个参数B并没有想象中重要,网格搜索9个参数组合(A, B),而由于模型更依赖于重要参数A,所以只有3个参数值是真正参与到最优参数的搜索工作中。反观随机搜索,随机采样9种超参组合,在重要参数A上会有9个参数值参与到搜索工作中,所以,在某些参数对模型影响较小时,使用随机搜索能让我们有更多的探索空间

同样地,sklearn实现了随机搜索[3],样例代码如下:

from sklearn import svm, datasets
from sklearn.model_selection import RandomizedSearchCV
import pandas as pd
from scipy.stats import uniform# 导入数据
iris = datasets.load_iris()
# 定义超参搜索空间
distributions = {'kernel':['linear', 'rbf'], 'C':uniform(loc=1, scale=9)}
# 初始化模型
svc = svm.SVC()
# 网格搜索
clf = RandomizedSearchCV(estimator = svc,param_distributions = distributions,n_iter = 4,scoring = 'accuracy',cv = 5,n_jobs = -1,random_state = 2021)
clf.fit(iris.data, iris.target)
返回&#xff1a;RandomizedSearchCV(cv&#61;5, estimator&#61;SVC(), n_iter&#61;4, n_jobs&#61;-1,param_distributions&#61;{&#39;C&#39;: <scipy.stats._distn_infrastructure.rv_frozen object at 0x000001F372F9A190>,&#39;kernel&#39;: [&#39;linear&#39;, &#39;rbf&#39;]},random_state&#61;2021, scoring&#61;&#39;accuracy&#39;)# 打印结果
print(&#39;详细结果:\n&#39;, pd.DataFrame.from_dict(clf.cv_results_))
print(&#39;最佳分类器:\n&#39;, clf.best_estimator_)
print(&#39;最佳分数:\n&#39;, clf.best_score_)
print(&#39;最佳参数:\n&#39;, clf.best_params_)
返回&#xff1a;
详细结果:mean_fit_time std_fit_time mean_score_time std_score_time param_C ... split3_test_score split4_test_score mean_test_score std_test_score rank_test_score
0 0.000598 0.000489 0.000200 0.000400 6.4538 ... 0.966667 1.0 0.986667 0.016330 1
1 0.000997 0.000002 0.000000 0.000000 4.99782 ... 0.966667 1.0 0.980000 0.026667 3
2 0.000798 0.000399 0.000399 0.000488 3.81406 ... 0.966667 1.0 0.980000 0.016330 3
3 0.000598 0.000488 0.000200 0.000399 5.36286 ... 0.966667 1.0 0.986667 0.016330 1
[4 rows x 15 columns]
最佳分类器:SVC(C&#61;6.453804509266643)
最佳分数:
0.9866666666666667
最佳参数:{&#39;C&#39;: 6.453804509266643, &#39;kernel&#39;: &#39;rbf&#39;}

相比于网格搜索&#xff0c;sklearn随机搜索中主要改变的参数是param_distributions&#xff0c;负责提供超参值分布范围。

三、贝叶斯优化(Bayesian Optimization)

我写本文的目的主要是冲着贝叶斯优化来的&#xff0c;一直有所耳闻却未深入了解&#xff0c;所以我就来查漏补缺了。以下内容主要基于Duane Rich在《How does Bayesian optimization work?》[4]的回答。

调优的目的是要找到一组最优的超参组合&#xff0c;能使目标函数f达到全局最小值。

举个例子&#xff0c;若学习率设置过大&#xff0c;模型可能会在代价函数的全局最优点附近不断来回震荡&#xff0c;甚至跳出全局最优点&#xff0c;而设置过小&#xff0c;又可能会陷入局部最优&#xff0c;因此调学习率这一参数&#xff0c;是为了让模型能收敛到代价函数的全局最小值。可是在机器学习中&#xff0c;目标函数 常是被称作 expensive blackbox function&#xff0c;计算开销大且不一定为凸函数。为此&#xff0c;贝叶斯优化出现了&#xff0c;它特别适合针对expensive blackbox function找到全局最优。

假设我们的真实的目标函数长下图这样&#xff1a;

图片

图2: 目标函数f(x)[4]

图片

图3: 随机采样10个点的目标函数f(x)[4]

图3里确实有个点挺靠近全局最优点的&#xff0c;那是不是在它附近再采样几个点&#xff0c;不断重复就行了&#xff1f;没那么简单&#xff0c;万一起始采样点在局部最小值附近&#xff0c;那这种方法会很容易陷入局部最优。关于“如何找到下一个合适的点”这个问题&#xff0c;我们先放一放&#xff0c;因为我们漏掉一个重点&#xff1a;每次尝试一种超参值&#xff0c;计算的代价是昂贵的&#xff0c;为了减轻开销&#xff0c;贝叶斯优化采用了代理模型(surrogate model)&#xff0c;代理模型可以被看作是一个简单模型去拟合原本复杂且不好理解的模型&#xff0c;简单来说&#xff0c;就是计算太昂贵了&#xff0c;我们就用代理模型去代替它。

贝叶斯优化使用了高斯过程(gasussian processes, GP) 去构建代理模型&#xff0c;高斯过程的细节这里暂时不讲&#xff0c;有兴趣的小伙伴可以自行查阅资料了解。基于给定的输入和输出&#xff0c;GP会推断出一个模型(这里为代理模型)。假设我们从昂贵的采样了4个点&#xff0c;然后我们把这4个点交给GP&#xff0c;它会返回一个代理模型&#xff0c;如下图所示&#xff1a;

图片

图4: 目标函数f(x)和代理模型[4]

绿色实线就是GP猜的代理模型&#xff0c;绿色条带是输出分布的标准差(即为Uncertainty) 。我们有了代理模型&#xff0c;后续我们去找下一个合适的超参值&#xff0c;就能带入到计算开销相对较小的代理模型中&#xff0c;评估给定超参值的情况。

现在&#xff0c;我们来思考回之前提到的问题:“如何找到下一个合适的点?”&#xff0c;这个问题本质是在问:“哪里有全局最小的点&#xff1f;”&#xff0c;为了解决这个问题&#xff0c;我们要关注两个地方:

(1) 已开发区域: 在绿色实线上最低的超参点。因为很可能它附近存在全局最优点。

(2) 未探索区域: 绿色实线上还未被探索的区域。比如图4&#xff0c;相比于0.15-0.25区间&#xff0c;0.65-0.75区间更具有探索价值(即该区间Uncertainty更大)。探索该区域有利于减少我们猜测的方差。

为了实现以上探索和开发的平衡(exploration-exploitation trade-off) &#xff0c;贝叶斯优化使用了采集函数(acquisition function) &#xff0c;它能平衡好全局最小值的探索和开发。采集函数有很多选择&#xff0c;其中最常见的是expectated of improvement(EI)[5] &#xff0c;我们先看一个utility function:

是目前观察到的最小值, 是超参值, 我们希望上述utility function输出越大越好(即找到的 能获得比当前最小值还小), 基于 , EI采集函数如下所示:

具有最高的EI的超参值 会被选择。EI有两部分&#xff1a;(1) 减少均值函数 , 提高EI。(2) 增加方差 , 提高EI。

所以EI的提高是建立在均值和方差的trade-off&#xff0c;也是exploration和exploitation的trade-off。

图片

图5: 采集函数A(x)

图5我们可以看到, 时티最大, 所以我们下一个超参值 应该选1。

讲到这里&#xff0c;我们来看下完整的贝叶斯优化步骤是怎样的&#xff1a;

图片

图6: 贝叶斯优化-SMBO

SMBO是简洁版的贝叶斯优化&#xff0c;伪代码如图6所示&#xff0c;具体如下&#xff1a;

(1) 准备输入: expensive blackbox function , 超参搜索空间 , 采样数据集 (超参组合 , 对应 输出值), 采集函数 和用数据集 拟合的代理模型M。(2) 基于 和 , 采样得到数据集 。(3) 循环选 次参数:

  1. 用当前数据集 拟合代理模型 , 实现模型更新。

  2. 选择使采集函数 最大的超参组合 。

  3. 将 带入 中, 得到输出值 。(注意这里 的计算开销大)

  4. 将新的 加入到现有数据集 中。

目前, Hyperopt[6] 开源代码库已实现基于TPE(Tree-structured Parzen Estimator Approach) 的贝叶斯优化, 图6我们能看到GP构建的概率模型是 , 而TPE是 和 , 关于TPE和 GP的对比讨论, 建议阅读论文 [7]。TPE样例代码如下:

from sklearn import svm, datasets
from sklearn.model_selection import cross_val_score
from hyperopt import hp, fmin, tpe, space_eval
import pandas as pd# 导入数据
iris &#61; datasets.load_iris()# step1: 定义目标函数
def objective(params):# 初始化模型并交叉验证svc &#61; svm.SVC(**params)cv_scores &#61; cross_val_score(svc, iris.data, iris.target, cv&#61;5)# 返回loss &#61; 1 - accuracy (loss必须被最小化)loss &#61; 1 - cv_scores.mean()return loss# step2: 定义超参搜索空间
space &#61; {&#39;kernel&#39;:hp.choice(&#39;kernel&#39;, [&#39;linear&#39;, &#39;rbf&#39;]),&#39;C&#39;:hp.uniform(&#39;C&#39;, 1, 10)}# step3: 在给定超参搜索空间下&#xff0c;最小化目标函数
best &#61; fmin(objective, space, algo&#61;tpe.suggest, max_evals&#61;100)
返回: best_loss: 0.013333333333333308(即accuracy为0.9866666666666667)# step4: 打印结果
print(best)
返回:{&#39;C&#39;: 6.136181888987526, &#39;kernel&#39;: 1}(PS:kernel为0-based index,这里1指rbf)

四、Hyperband

除了格子搜索、随机搜索和贝叶斯优化&#xff0c;还有其它自动调参方式。例如Hyperband optimization[8]&#xff0c;Hyperband本质上是随机搜索的一种变种&#xff0c;它使用早停策略和Sccessive Halving算法去分配资源&#xff0c;结果是Hyperband能评估更多的超参组合&#xff0c;同时在给定的资源预算下&#xff0c;比贝叶斯方法收敛更快&#xff0c;下图展示了Hyperband的早停和资源分配:

图片

图7: Hyperband的超参选择和评估

在Hyperband之后&#xff0c;还出现了BOHB&#xff0c;它混合了贝叶斯优化和Hyperband。Hyperband和BOHB的开源代码可参考HpBandSter库[9]&#xff0c;这里不展开细讲。

五、总结

上面我们用Iris鸢尾花数据集试了不同的超参自动调优方法&#xff0c;发现贝叶斯优化和随机搜索都比格子搜索好。从一些论文反映&#xff0c;贝叶斯优化是更香的&#xff0c;但是贝叶斯优化好像在实践中用的不是那么多&#xff0c;网上也有很多分享者&#xff0c;像Nagesh Singh Chauhan&#xff0c;说的那样&#xff1a;

As a general rule of thumb, any time you want to optimize tuning hyperparameters, think Grid Search and Randomized Search! [10]

Hyperparameter Optimization for Machine Learning Models - Nagesh Singh Chauhan

为什么呢&#xff1f;我想原因是贝叶斯的开销太大了&#xff0c;前面有提到&#xff0c;在每次循环选超参值的时候&#xff0c;贝叶斯优化都需要将 带入昂贵的目标函数 中&#xff0c;去得到输出值y&#xff0c;当目标函数特别复杂时&#xff0c;这种情况的评估开销是很大的&#xff0c;更何况随着搜索空间和搜索次数的变大&#xff0c;计算会越发昂贵。在知乎《为什么基于贝叶斯优化的自动调参没有大范围使用&#xff1f;》[11]中&#xff0c;很多知乎主也给出了很认真的回复&#xff0c;建议有兴趣的朋友移步阅读。

写这篇文章的过程中&#xff0c;我主要学到了2点&#xff0c;一是随机搜索在某些时候会比格子搜索好&#xff0c;二是了解贝叶斯优化的机理。这里&#xff0c;谈谈我比赛和个人实践中的体会&#xff0c;我很少会花过多时间在超参的调优上&#xff0c;因为它带来的收益是有限的&#xff0c;很多时候比起压榨模型来说&#xff0c;思考和挖掘数据特征能带来更多的收益&#xff0c;所以我想这也是为什么上面说&#xff1a;在任何想要调优超参时&#xff0c;先用格子搜索或随机搜索吧。

参考资料

[1] sklearn.model_selection.GridSearchCV, 官方文档: https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV

[2] Bergstra, J., & Bengio, Y. (2012). Random search for hyper-parameter optimization. Journal of machine learning research, 13(2).

[3] sklearn.model_selection.RandomizedSearchCV, 官方文档: https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html#sklearn.model_selection.RandomizedSearchCV

[4] Quora: How does Bayesian optimization work? - Duane Rich, 回答: https://www.quora.com/How-does-Bayesian-optimization-work

[5] Bayesian Optimization (2018). - Cse.wustl.edu. 课程Note: https://www.cse.wustl.edu/~garnett/cse515t/spring_2015/files/lecture_notes/12.pdf

[6] Hyperopt: Distributed Hyperparameter Optimization, 代码: https://github.com/hyperopt/hyperopt#getting-started

[7] Bergstra, J., Bardenet, R., Bengio, Y., & Kégl, B. (2011, December). Algorithms for hyper-parameter optimization. In 25th annual conference on neural information processing systems (NIPS 2011) (Vol. 24). Neural Information Processing Systems Foundation.

[8] Li, L., Jamieson, K., DeSalvo, G., Rostamizadeh, A., & Talwalkar, A. (2017). Hyperband: A novel bandit-based approach to hyperparameter optimization. The Journal of Machine Learning Research, 18(1), 6765-6816.

[9] HpBandSter开源代码库, 代码: https://github.com/automl/HpBandSte

[10] Hyperparameter Optimization for Machine Learning Models - Nagesh Singh Chauhan, 文章: [https://www.kdnuggets.com/2020/05/hyperparameter-optimization-machine-learning-models.html

[11] 为什么基于贝叶斯优化的自动调参没有大范围使用&#xff1f;- 知乎, 问答: https://www.zhihu.com/question/33711002


推荐阅读
  • 在本教程中,我们将看到如何使用FLASK制作第一个用于机器学习模型的RESTAPI。我们将从创建机器学习模型开始。然后,我们将看到使用Flask创建AP ... [详细]
  • 前言:拿到一个案例,去分析:它该是做分类还是做回归,哪部分该做分类,哪部分该做回归,哪部分该做优化,它们的目标值分别是什么。再挑影响因素,哪些和分类有关的影响因素,哪些和回归有关的 ... [详细]
  • 本文介绍了在Python张量流中使用make_merged_spec()方法合并设备规格对象的方法和语法,以及参数和返回值的说明,并提供了一个示例代码。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 我用Tkinter制作了一个图形用户界面,有两个主按钮:“开始”和“停止”。请您就如何使用“停止”按钮终止“开始”按钮为以下代码调用的已运行功能提供建议 ... [详细]
author-avatar
呀yuan-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有