赞
踩
SMAC
(Sequential Model-based Algorithm Configuration),即基于序列模型的算法配置,被广泛应用在各个自动机器学习框架上,如微软的nni
(https://github.com/microsoft/nni),auto-sklearn等。其中auto-sklearn的超参搜索模块完全由smac
算法构建。要想理解auto-sklearn,首先就要理解smac
。
下面介绍smac的应用场景:AutoML
,应用主体:auto-sklearn
随着最近人工智能技术的大热,机器学习、深度学习逐渐进入了人们的视野,在各种工具(如Tensorflow,sklearn)开源的加持下,机器学习技术逐渐有普及化、全民化的趋势。但是,以普通的表格数据(行为样本点,列为特征)为例,要找到一个表现最好的Pipeline(即从数据处理,特征处理,最后到estimator判别),需要花费人们大量的时间去尝试。一般来说,数据科学家需要获取数据的一些基本统计量,做一些图表来判断数据的模式,再根据自己的经验挑选数据处理,特征处理的方法,最后选择一个estimator(在分类任务中为分类器classifier,在回归任务中为回归器regressor)。可是这个过程一个是耗时,还有更加依赖数据科学家的经验,提升了机器学习的门槛。
人们注意到了这一矛盾,提出了自动机器学习(AutoML)的概念。在2015年一个AutoML框架auto-sklearn
横空出世,引来人们争相关注:
paper | http://papers.nips.cc/paper/5872-efficient-and-robust-automated-machine-learning.pdf |
---|---|
code | https://github.com/automl/auto-sklearn |
最近笔者在调研AutoML,于是对auto-sklearn
进行了调研。笔者发现,auto-sklearn是用automl团队(https://www.automl.org)编写,这个团队在构建这个自动机器学习框架时使用了大量自己开发的库,库与库之间功能内聚,相互隔离,调用关系为一个有向无环图:
橙色字体标记的smac
就是我们今天的主角。在分析清楚auto-sklearn的项目架构后,我下载了smac的源代码(https://github.com/automl/SMAC3),开始对其进行分析。
在AutoML系统中,最为关键的就是根据当前的多组超参数组合(如svm核函数的选择,惩罚系数C的选择)与模型表现(如分类任务中的准确率),给出一个在当前条件下预计最优的超参数,这就是贝叶斯优化(Bayesian Optimizer)。与网格搜索与随机搜索不同,贝叶斯优化能在更短的时间内找到更好的超参数。
smac
),基于TPE算法代理的序列超参优化。
在终端中执行以下命令,开启第一个例子
git clone https://github.com/automl/SMAC3
cd SMAC3 && pip install .
cd examples
python SMAC4HPO_svm.py
让我们看到SMAC4HPO_svm.py
这个样例代码。
首先定义了一个输入为cfg(超参配置),输出为模型表现的函数svm_from_cfg
def svm_from_cfg(cfg): """ 创建一个基于配置的SVM模型,并且通过交叉验证在鸢尾花数据集上评价该模型 Parameters: ----------- cfg: 超参配置 (ConfigSpace.ConfigurationSpace.Configuration) Returns: -------- A crossvalidated mean score for the svm on the loaded data-set. svm在数据集上交叉验证的平均值 """ # 通过字典解析过滤掉值为None的键值对 cfg = {k : cfg[k] for k in cfg if cfg[k]} # We translate boolean values: cfg["shrinking"] = True if cfg["shrinking"] == "true" else False # And for gamma, we set it to a fixed value or to "auto" (if used) if "gamma" in cfg: cfg["gamma"] = cfg["gamma_value"] if cfg["gamma"] == "value" else "auto" cfg.pop("gamma_value", None) # Remove "gamma_value" clf = svm.SVC(**cfg, random_state=42) scores = cross_val_score(clf, iris.data, iris.target, cv=5) return 1-np.mean(scores) # Minimize!
接下来是配置超参空间
# Build Configuration Space which defines all parameters and their ranges cs = ConfigurationSpace() # We define a few possible types of SVM-kernels and add them as "kernel" to our cs kernel = CategoricalHyperparameter("kernel", ["linear", "rbf", "poly", "sigmoid"], default_value="poly") cs.add_hyperparameter(kernel) # There are some hyperparameters shared by all kernels C = UniformFloatHyperparameter("C", 0.001, 1000.0, default_value=1.0) shrinking = CategoricalHyperparameter("shrinking", ["true", "false"], default_value="true") cs.add_hyperparameters([C, shrinking]) # Others are kernel-specific, so we can add conditions to limit the searchspace degree = UniformIntegerHyperparameter("degree", 1, 5, default_value=3) # Only used by kernel poly coef0 = UniformFloatHyperparameter("coef0", 0.0, 10.0, default_value=0.0) # poly, sigmoid cs.add_hyperparameters([degree, coef0]) use_degree = InCondition(child=degree, parent=kernel, values=["poly"]) use_coef0 = InCondition(child=coef0, parent=kernel, values=["poly", "sigmoid"]) cs.add_conditions([use_degree, use_coef0]) # This also works for parameters that are a mix of categorical and values from a range of numbers # For example, gamma can be either "auto" or a fixed float gamma = CategoricalHyperparameter("gamma", ["auto", "value"], default_value="auto") # only rbf, poly, sigmoid gamma_value = UniformFloatHyperparameter("gamma_value", 0.0001, 8, default_value=1) cs.add_hyperparameters([gamma, gamma_value]) # We only activate gamma_value if gamma is set to "value" cs.add_condition(InCondition(child=gamma_value, parent=gamma, values=["value"])) # And again we can restrict the use of gamma in general to the choice of the kernel cs.add_condition(InCondition(child=gamma, parent=kernel, values=["rbf", "poly", "sigmoid"]))
可以看到在配置超参空间时除了可以配置超参的默认值、值域之外,还能配置超参的Condition
,即条件。例如,svm有["linear", "rbf", "poly", "sigmoid"]
四种核函数,但只有["rbf", "poly", "sigmoid"]
这三种核函数含有gamma参数。
# Scenario object (方案对象) scenario = Scenario({"run_obj": "quality", # 有{runtime,quality}两种选项 "runcount-limit": 50, # max. number of function evaluations; for this example set to a low number "cs": cs, # configuration space "deterministic": "true" }) # Example call of the function # It returns: Status, Cost, Runtime, Additional Infos def_value = svm_from_cfg(cs.get_default_configuration()) print("Default Value: %.2f" % (def_value)) # Optimize, using a SMAC-object print("Optimizing! Depending on your machine, this might take a few minutes.") smac = SMAC4HPO(scenario=scenario, rng=np.random.RandomState(42), tae_runner=svm_from_cfg) # incumbent(现任者,与挑战者challenger相对),表示能让模型表现最优的配置 incumbent = smac.optimize() # 最优的模型表现 inc_value = svm_from_cfg(incumbent) print("Optimized Value: %.2f" % (inc_value)) # We can also validate our results (though this makes a lot more sense with instances) smac.validate(config_mode='inc', # We can choose which configurations to evaluate #instance_mode='train+test', # Defines what instances to validate repetitions=100, # Ignored, unless you set "deterministic" to "false" in line 95 n_jobs=1) # How many cores to use in parallel for optimization
我们看到最后这几行代码,先是构建一个方案对象(Scenario
)表示搜索配置,然后将scenario
与目标函数作为参数传入SMAC4HPO
返回一个smac对象,调用optimize()
得到一个最优超参。
$ tree smac -L 1
.
├── configspace/
├── epm/
├── facade/
├── initial_design/
├── intensification/
├── optimizer/
├── runhistory/
├── scenario/
├── stats/
├── tae/
└── utils/
目录名 | 释义 |
---|---|
configspace | 超参空间 |
epm | 随机森林代理模型 |
facade | 一些装饰类 |
initial_design | 搜索空间的初始化方法 |
intensification | 在challenger中选出最优配置 |
optimizer | 优化器,包含acquisition,smbo多个重要文件 |
runhistory | 对运行历史的记录 |
scenario | 搜索方案配置 |
tae | Target Algorithm Evaluator,目标算法评价器 |
在下一期推送中,笔者将继续为大家分析smac源码,探究smac是如何用随机森林代理模型对超参空间进行优化的。
在下一期推送中,笔者将继续为大家分析smac源码,探究smac是如何用随机森林代理模型对超参空间进行优化的。
欢迎关注公众号"人工智能源码阅读"(aicodereview
)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。