超参数优化
我们支持不同的搜索空间下的黑盒超参数优化。
搜索空间
我们支持三种类型的搜索空间,请使用python字典``dict``来定义你的搜索空间。 对于数字列表形式的搜索空间,你可以为列表指定一个固定的长度,如果是这样,你不需要提供``cutPara``和``cutFunc``。 或者你可以把列表切成一个特定的长度,这个长度取决于参数``cutPara``和``cutFunc``。你应该在``cutPara``中提供参数名并在``cutFunc``中提供计算剪切长度的函数。
# 数值搜索空间:
{
"parameterName": "xxx",
"type": "DOUBLE" / "INTEGER",
"minValue": xx,
"maxValue": xx,
"scalingType": "LINEAR" / "LOG"
}
# 数值列表搜索空间:
{
"parameterName": "xxx",
"type": "NUMERICAL_LIST",
"numericalType": "DOUBLE" / "INTEGER",
"length": 3,
"cutPara": ("para_a", "para_b"),
"cutFunc": lambda x: x[0] - 1,
"minValue": [xx,xx,xx],
"maxValue": [xx,xx,xx],
"scalingType": "LINEAR" / "LOG"
}
# 类别搜索空间:
{
"parameterName": xxx,
"type": "CATEGORICAL"
"feasiblePoints": [a,b,c]
}
# 固定参数作为搜索空间:
{
"parameterName": xxx,
"type": "FIXED",
"value": xxx
}
下表列出了超参数优化算法所支持的搜索空间形式:
添加你自己的超参数优化器(HPOptimizer)
如果你想添加你自己的 HPOptimizer, 你只需要完成 HPOptimizer 中的``optimize`` 函数:
# 例如,创建一个随机超参数优化算法
import random
from autogl.module.hpo.base import BaseHPOptimizer
class RandomOptimizer(BaseHPOptimizer):
# 在初始化时获取基本参数
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.max_evals = kwargs.get("max_evals", 2)
# 你应该做的最重要的事情是完成优化函数
def optimize(self, trainer, dataset, time_limit=None, memory_limit=None):
# 1. 从训练器得到搜索空间。
space = trainer.hyper_parameter_space + trainer.model.hyper_parameter_space
# 可选的:使用 self._encode_para (在 BaseOptimizer) 来对搜索空间进行预处理
# 如果使用 _encode_para, NUMERICAL_LIST 将扩展为 双精度浮点数 或 整数,LOG尺度类型将改为线性,CATEGORICAL中的可行点将改为离散数。
# 您还应该使用_decode_para将参数类型转换回来。
current_space = self._encode_para(space)
# 2. 定义你自己的性能函数。
def fn(dset, para):
current_trainer = trainer.duplicate_from_hyper_parameter(para)
current_trainer.train(dset)
loss, self.is_higher_better = current_trainer.get_valid_score(dset)
# 为了方便起见,损失分数越高越好;如果是负数,那么我们就应该把损失分数降到最低。
if self.is_higher_better:
loss = -loss
return current_trainer, loss
# 3. 定义如何获得超参数建议,它应该返回一个参数字典。你可以使用历史实验来得到新的建议。
def get_random(history_trials):
hps = {}
for para in current_space:
# 因为我们之前使用了_encode_para函数,所以我们应该只处理DOUBLE、INTEGER和DISCRETE函数
if para["type"] == "DOUBLE" or para["type"] == "INTEGER":
hp = random.random() * (para["maxValue"] - para["minValue"]) + para["minValue"]
if para["type"] == "INTEGER":
hp = round(hp)
hps[para["parameterName"]] = hp
elif para["type"] == "DISCRETE":
feasible_points = para["feasiblePoints"].split(",")
hps[para["parameterName"]] = random.choice(feasible_points)
return hps
# 4. 运行算法。对于每个回合,根据历史信息获得一组参数并进行评估。
best_trainer, best_para, best_perf = None, None, None
self.trials = []
for i in range(self.max_evals):
# 在这个例子中,我们不需要历史追踪。因此我们为history_trails传入None
new_hp = get_random(None)
# 可选的:如果你使用参数 _encode_para,也要提供参数 _decode_para 。 para_for_trainer 撤销 _encode_para 中的所有转换,并在需要时将双精度浮点数转换为整数。para_for_hpo 只将双精度浮点数转换为整数。
para_for_trainer, para_for_hpo = self._decode_para(new_hp)
current_trainer, perf = fn(dataset, para_for_trainer)
self.trials.append((para_for_hpo, perf))
if not best_perf or perf < best_perf:
best_perf = perf
best_trainer = current_trainer
best_para = para_for_trainer
# 5. 返回最优训练器和参数。
return best_trainer, best_para
[1] | Bergstra, James S., et al. “Algorithms for hyper-parameter optimization.” Advances in neural information processing systems. 2011. |
[2] | Arnold, Dirk V., and Nikolaus Hansen. “Active covariance matrix adaptation for the (1+ 1)-CMA-ES.” Proceedings of the 12th annual conference on Genetic and evolutionary computation. 2010. |
[3] | Voß, Thomas, Nikolaus Hansen, and Christian Igel. “Improved step size adaptation for the MO-CMA-ES.” Proceedings of the 12th annual conference on Genetic and evolutionary computation. 2010. |
[4] | Bratley, Paul, Bennett L. Fox, and Harald Niederreiter. “Programs to generate Niederreiter’s low-discrepancy sequences.” ACM Transactions on Mathematical Software (TOMS) 20.4 (1994): 494-495. |
[5] | Tu, Ke, et al. “Autone: Hyperparameter optimization for massive network embedding.” Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. 2019. |