Hyperopt 是否支持选择的子集?

Does Hyperopt support subset of choices?

我有一组选择A。我想取回一部分选择 A。这可以用 Hyperopt 实现吗?

输入:

{
    'A': hp.choice('A', [0, 1, 2, 3])
}

输出:

{
    'A': [0, 2]
}

否,但如果您特别需要该功能,可以通过多种方式实现。

  1. 您可以定义一个新表达式并将其添加到 the documentation 中给出的现有 hyperopt 参数表达式中。例如,在你的情况下,你可以这样做:

    import hyperopt.pyll
    from hyperopt.pyll import scope
    from hyperopt.pyll.stochastic import sample
    
    # Add a new method as you want
    @scope.define
    def foo(choices, num_choices):
        return np.random.choice(choices, size=num_choices, replace=False)
    
    choices = [1,2,3,4]
    
    # Define the space like below and use in fmin
    space = scope.foo(choices, 2)
    
    # Call this multiple times to see how space behaves
    print(sample(space))   
    

    查看 documention of numpy.random.choice 了解其工作原理。

    注意:

    • foo 方法将 return 选择的子集(在 numpy 数组中)。因此,请确保在您的 objective 函数中,您使用的是内部多个值,例如 x[0], x[1], ...
    • 在代码末尾添加 scope.undefine(foo),否则每次在 运行 代码之前,您都必须重新启动终端/内核。
    • hyperopt wiki specifically prohibits 定义新类型的参数搜索空间,就像我们上面所做的那样,因为这可能会影响搜索策略或执行非最佳。
  2. 如果允许您选择两个值进行替换(这意味着有时子集中的两个值将相同。这就是我们使用的原因replace=False 在第 1 点),则可以进行以下操作:

    choices = [1,2,3,4]
    space = [hp.choice('c1', choices), 
             hp.choice('c2', choices)]
    

    然后在你的 objective 函数中,你可以访问你的两个值 x[0], x[1].

    但从你的问题来看,你似乎想要子选项,这意味着没有替换,所以 [1,1][2,2] 等的子集是无效的。在那种情况下,您应该使用 Trials object to define status

第 2 点的示例程序如下:

from hyperopt import fmin, tpe, hp, STATUS_OK, STATUS_FAIL, Trials

def objective(x):
    # Check if the supplied choices are valid or not
    x1 = x[0]
    x2 = x[1]
    if x1 == x2:
        # If invalid, only return the status and hyperopt will understand
        return {'status': STATUS_FAIL} 


    # Normal flow of objective
    # Do your coding here

    # In the end, return this  
    return {
        'loss': actual_loss,  # Fill the actual loss here
        'status': STATUS_OK
        }

choices = [1,2,3,4]
space = [hp.choice('c1', choices), 
         hp.choice('c2', choices)]

trials = Trials()   
best = fmin(objective, space=space, algo=tpe.suggest, max_evals=100, trials=trials)

from hyperopt import space_eval
print(space_eval(space, best))

希望对您有所帮助。

是的,虽然代码有点繁琐。分别定义 A 的每个元素作为包含和排除之间的选择。例如:

space = {
    "A0": hp.choice("A0", [False, True]),
    "A1": hp.choice("A1", [False, True]),
    "A2": hp.choice("A2", [False, True]),
    ...
}

在您的 objective 函数中解释它的代码也非常简单:

A = [i for i in range(num_choices) if space["A"+str(i)]]
# A = [0, 2] for example

这将 return A 的真正随机子集(从空集到整个 A 的任何地方)。