复杂搜索空间的问题定义¶
在快速示例中,我们已经展示了如何在搜索空间中定义独立变量。 然而,现实世界中的搜索空间通常很复杂,可能包含空间内条件、禁止条款等。 在本教程中,我们将展示OpenBox如何支持复杂的搜索空间。
分层条件¶
在OpenBox中的搜索空间目前是基于ConfigSpace包构建的。 虽然ConfigSpace支持分层条件,但我们可以直接使用ConfigSpace提供的高级API。
在以下示例中,我们提供了一个使用Conditions构建分层搜索空间的示例:
from openbox import space as sp
from ConfigSpace import EqualsCondition, InCondition
space = sp.Space()
x1 = sp.Categorical("x1", choices=["c1", "c2", "c3", "c4"])
x2 = sp.Real("x2", -5, 10, default_value=0)
x3 = sp.Real("x3", 0, 15, default_value=0)
equal_condition = EqualsCondition(x2, x1, "c1") # x2 is active when x1 = c1
in_condition = InCondition(x3, x1, ["c2", "c3"]) # x3 is active when x1 = c2 or x1 = c3
space.add_variables([x1, x2, x3])
space.add_conditions([equal_condition, in_condition])
print(space.sample_configuration(5))
示例输出可以如下所示,
[Configuration(values={
'x1': 'c4',
})
, Configuration(values={
'x1': 'c1',
'x2': -4.246561408224157,
})
, Configuration(values={
'x1': 'c3',
'x3': 1.7213163807467695,
})
, Configuration(values={
'x1': 'c3',
'x3': 13.8469881579991,
})
, Configuration(values={
'x1': 'c2',
'x3': 2.9833423891692763,
})
]
在这个例子中,当x1的值为c1时,变量x2是激活的。
当x1的值为c2或c3时,变量x3是激活的。
当x1的值为c4时,x2和x3都不激活。
非激活变量的值默认设置为np.nan。
在优化过程中,无效的变量组合不会被采样,
因此不会为无效配置花费评估时间。
通过利用Conditions,用户可以构建具有层次结构的复杂搜索空间。
有关Conditions的更多详细信息,请参阅ConfigSpace文档以获取更多详细信息。
空间变量约束¶
为了支持变量之间的约束(例如,a 或 a+b<10),我们建议添加一个采样条件,如下例所示,
from openbox import space as sp
def sample_condition(config):
# require x1 <= x2 and x1 * x2 < 100
if config['x1'] > config['x2']:
return False
if config['x1'] * config['x2'] >= 100:
return False
return True
# return config['x1'] <= config['x2'] and config['x1'] * config['x2'] < 100
cs = sp.ConditionedSpace()
cs.add_variables([...])
cs.set_sample_condition(sample_condition) # set the sample condition after all variables are added
API set_sample_condition 需要一个函数,该函数以配置作为输入并输出一个布尔值,
该值表示配置是否有效。
在优化过程中,只有满足样本条件(返回值为 True)的配置才会被采样。
请注意,空间变量约束是可以直接检查而不需要运行目标函数的约束,这与约束问题中的黑盒约束不同。