Python和HyperOpt:如何进行多进程网格搜索?

Python和HyperOpt:如何进行多进程网格搜索?,python,pandas,machine-learning,grid-search,hyperparameters,Python,Pandas,Machine Learning,Grid Search,Hyperparameters,我正在尝试调整一些参数,搜索空间非常大。到目前为止,我有5个维度,它可能会增加到10个左右。问题是,我认为如果我能想出如何对其进行多处理,我可以获得显著的加速,但我找不到任何好的方法。我使用的是hyperopt,我不知道如何让它使用多个核心。下面是我的代码,没有任何不相关的东西: from numpy import random from pandas import DataFrame from hyperopt import fmin, tpe, hp, Trials de

我正在尝试调整一些参数,搜索空间非常大。到目前为止,我有5个维度,它可能会增加到10个左右。问题是,我认为如果我能想出如何对其进行多处理,我可以获得显著的加速,但我找不到任何好的方法。我使用的是
hyperopt
,我不知道如何让它使用多个核心。下面是我的代码,没有任何不相关的东西:

from numpy    import random
from pandas   import DataFrame
from hyperopt import fmin, tpe, hp, Trials





def calc_result(x):

    huge_df = DataFrame(random.randn(100000, 5), columns=['A', 'B', 'C', 'D', 'E'])

    total = 0

    # Assume that I MUST iterate
    for idx_and_row in huge_df.iterrows():
        idx = idx_and_row[0]
        row = idx_and_row[1]


        # Assume there is no way to optimize here
        curr_sum = row['A'] * x['adjustment_1'] + \
                   row['B'] * x['adjustment_2'] + \
                   row['C'] * x['adjustment_3'] + \
                   row['D'] * x['adjustment_4'] + \
                   row['E'] * x['adjustment_5']


        total += curr_sum

    # In real life I want the total as high as possible, but for the minimizer, it has to negative a negative value
    total_as_neg = total * -1

    print(total_as_neg)

    return total_as_neg


space = {'adjustment_1': hp.quniform('adjustment_1', 0, 1, 0.001),
         'adjustment_2': hp.quniform('adjustment_2', 0, 1, 0.001),
         'adjustment_3': hp.quniform('adjustment_3', 0, 1, 0.001),
         'adjustment_4': hp.quniform('adjustment_4', 0, 1, 0.001),
         'adjustment_5': hp.quniform('adjustment_5', 0, 1, 0.001)}

trials = Trials()

best = fmin(fn        = calc_result,
            space     = space,
            algo      = tpe.suggest,
            max_evals = 20000,
            trials    = trials)

到目前为止,我有4个内核,但我基本上可以得到我需要的任何数量。我怎样才能让hyperopt使用一个以上的内核,或者有一个可以进行多处理的库呢?

只是你问题的一些旁注。我最近也在进行超参数搜索,如果你有自己的原因,请不要理我

问题是你应该更喜欢随机搜索而不是网格搜索。

这是他们提出这个建议的地方

这里有一些解释:基本上随机搜索更好地分布在子特征上,网格搜索更好地分布在整个特征空间上,这就是为什么感觉这是一种方式


图像来自

您可以使用多处理来运行任务,通过绕过Python的全局解释器锁,这些任务可以在可用的多个处理器中有效地并发运行

要运行多处理任务,必须实例化
,并让此对象在iterable对象上执行
映射
函数

函数
map
只是将一个函数应用于iterable的每个元素,就像列表一样,然后返回另一个包含元素的列表

以搜索为例,这将从列表中获取大于5的所有项目:

from multiprocessing import Pool

def filter_gt_5(x):
   for i in x:
       if i > 5
           return i

if __name__ == '__main__':
    p = Pool(4)
    a_list = [6, 5, 4, 3, 7, 8, 10, 9, 2]
    #find a better way to split your list.
    lists = p.map(filter_gt_5, [a_list[:3], a_list[3:6], a_list[6:])
    #this will join the lists in one.
    filtered_list = list(chain(*lists))

在您的情况下,您必须拆分搜索库。

如果您有Mac或Linux(或Windows Linux子系统),您可以添加大约10行代码,与
ray
并行执行此操作。如果通过安装ray,则可以运行脚本,只需进行少量修改(如下所示),即可使用HyperOpt执行并行/分布式网格搜索。在较高级别上,它使用tpe.suggest运行
fmin
,并以并行方式在内部创建一个Trials对象

from numpy    import random
from pandas   import DataFrame
from hyperopt import fmin, tpe, hp, Trials


def calc_result(x, reporter):  # add a reporter param here

    huge_df = DataFrame(random.randn(100000, 5), columns=['A', 'B', 'C', 'D', 'E'])

    total = 0

    # Assume that I MUST iterate
    for idx_and_row in huge_df.iterrows():
        idx = idx_and_row[0]
        row = idx_and_row[1]


        # Assume there is no way to optimize here
        curr_sum = row['A'] * x['adjustment_1'] + \
                   row['B'] * x['adjustment_2'] + \
                   row['C'] * x['adjustment_3'] + \
                   row['D'] * x['adjustment_4'] + \
                   row['E'] * x['adjustment_5']


        total += curr_sum

    # In real life I want the total as high as possible, but for the minimizer, it has to negative a negative value
    # total_as_neg = total * -1

    # print(total_as_neg)

    # Ray will negate this by itself to feed into HyperOpt
    reporter(timesteps_total=1, episode_reward_mean=total)

    return total_as_neg


space = {'adjustment_1': hp.quniform('adjustment_1', 0, 1, 0.001),
         'adjustment_2': hp.quniform('adjustment_2', 0, 1, 0.001),
         'adjustment_3': hp.quniform('adjustment_3', 0, 1, 0.001),
         'adjustment_4': hp.quniform('adjustment_4', 0, 1, 0.001),
         'adjustment_5': hp.quniform('adjustment_5', 0, 1, 0.001)}

import ray
import ray.tune as tune
from ray.tune.hpo_scheduler import HyperOptScheduler

ray.init()
tune.register_trainable("calc_result", calc_result)
tune.run_experiments({"experiment": {
    "run": "calc_result",
    "repeat": 20000,
    "config": {"space": space}}}, scheduler=HyperOptScheduler())

可以使用SparkTrials()而不是hyperopt中的Trials()来实现您的要求

请参阅文件

SparkTrials API:
SparkTrial可以通过3个参数进行配置,所有参数都是可选的:

并行性

同时评估的最大试验次数。更大的并行性允许扩展测试更多的超参数设置。默认为火花执行器的数量

权衡:并行度
参数可以与
fmin()
中的
max\u evals
参数一起设置。Hyperopt将测试hyperparameters的
max_evals
总设置,以批量大小
并行度
。如果
parallelism=max_evals
,则Hyperopt将执行随机搜索:它将选择所有hyperparameter设置进行独立测试,然后并行评估它们。如果
parallelism=1
,则Hyperopt可以充分利用自适应算法,如Parzen估计器树(TPE),该算法迭代探索超参数空间:将根据先前的结果选择测试的每个新超参数设置。在
1
max_evals
之间设置
parallelism
允许您权衡可伸缩性(更快地获得结果)和适应性(有时获得更好的模型)。

限制:目前,并行度有一个128的硬上限
SparkTrials
还将检查集群的配置,以查看Spark将允许多少并发任务;如果并行度超过此最大值,
SparkTrials
会将并行度降低到此最大值

代码片段:

from hyperopt import SparkTrials, fmin, hp, tpe, STATUS_OK

spark_trials = SparkTrials(parallelism= no. of cores)

best_hyperparameters = fmin(
  fn=train,
  space=search_space,
  algo=algo,
  max_evals=32)

问题在于
hyperopt
跟踪参数的最佳组合,并使用最佳组合作为下一步搜索位置的建议,因此如果我按照您的建议进行搜索,则每个线程不会引用相同的最佳组合,而是引用不同的最佳组合。它需要处理共享对象,这是你的建议没有考虑到的,我在技术上不够胜任写作。我真的不知道如何并发运行它(因为它将使用
空间
作为共享对象,我怀疑这是不可能的)。唯一的方法是获取此搜索函数的源代码并修改以使用多处理运行任务。但是实际工作需要多少呢?生成的工作负载是否繁重?它肯定可以被划分。这个特殊的例子很容易需要几天才能找到答案。我刚刚尝试了ray(0.6.0),不幸的是它需要tensorflow。你得到的错误消息是什么?它可能是良性的(TF记录器没有正确启动,但Ray Tune继续运行)。我记不清了(从那时起我删除了我脚本的Ray版本),但它正在中止导入tensorflow的尝试。我明白了-如果您再次访问它,请告诉我;我有兴趣解决您的问题。这仍然是将
hyperopt
试验与
ray
并行化的正确方法吗?我无法让这个例子起作用,而且在中我找不到并行化的参考。Hyperopt在大多数情况下比随机搜索更好,因为它根据您当时的所有评分结果选择下一个参数组合。它只是对参数做出了更明智的选择。