通过 MongoDB 并行化搜索期间的评估

Hyperopt 设计用于支持不同类型的试验数据库。默认试验数据库(Trials)使用 Python 列表和字典实现。默认实现是参考实现,易于使用,但不支持并行评估试验所需的异步更新。对于并行搜索,hyperopt 包含一个支持异步更新的 MongoTrials 实现。

要运行并行化搜索,您需要执行以下操作(在安装 mongodb 之后)

  1. 在网络可见的地方启动一个 mongod 进程。

  2. 修改调用 hyperopt.fmin 的代码,使其使用连接到该 mongod 进程的 MongoTrials 后端。

  3. 启动一个或多个 hyperopt-mongo-worker 进程,这些进程也将连接到 mongod 进程,并在 fmin 阻塞时执行搜索。

启动一个 mongod 进程

安装 mongodb 后,启动数据库进程 (mongod) 就像输入例如:

mongod --dbpath . --port 1234
# or storing each db its own directory is nice:
mongod --dbpath . --port 1234 --directoryperdb --journal --nohttpinterface
# or consider starting mongod as a daemon:
mongod --dbpath . --port 1234 --directoryperdb --fork --journal --logpath log.log --nohttpinterface

Mongo 习惯预分配几 GB 空间(您可以使用 --noprealloc 禁用此功能)以获得更好的性能,因此请考虑一下您想在哪里创建此数据库。在网络文件系统上创建数据库可能会导致您自己的数据库和网络上其他人的性能都非常糟糕,请注意这一点。

此外,如果您的机器对互联网可见,那么要么绑定到环回接口并通过 ssh 连接,要么阅读 mongodb 关于密码保护的文档。

本教程的其余部分基于 mongo 在localhost端口 1234上运行。

使用 MongoTrials

假设,为了保持简单,您想使用 hyperopt 最小化 math.sin 函数。要在进程内(串行)运行,您可以像这样输入:

import math
from hyperopt import fmin, tpe, hp, Trials

trials = Trials()
best = fmin(math.sin, hp.uniform('x', -2, 2), trials=trials, algo=tpe.suggest, max_evals=10)

要使用 mongo 数据库作为实验的持久存储,请像这样使用 MongoTrials 对象代替 Trials

import math
from hyperopt import fmin, tpe, hp
from hyperopt.mongoexp import MongoTrials

trials = MongoTrials('mongo://localhost:1234/foo_db/jobs', exp_key='exp1')
best = fmin(math.sin, hp.uniform('x', -2, 2), trials=trials, algo=tpe.suggest, max_evals=10)

MongoTrials 的第一个参数告诉它使用哪个 mongod 进程,以及在该进程中使用的哪个 数据库(这里是 'foo_db')。第二个参数(exp_key='exp_1')对于在数据库内部标记特定试验集很有用。exp_key 参数技术上是可选的。

注意:当前有一个实现要求,数据库名称后面必须跟着 '/jobs'。

是始终将您的试验放在单独的数据库中,还是使用 exp_key 机制来区分它们,这取决于您。倾向于使用数据库的理由:它们可以从 shell 操作(它们显示为不同的文件),并且确保实验具有更大的独立性/隔离性。倾向于使用 exp_key 的理由:hyperopt-mongo-worker 进程(见下文)在数据库级别轮询,因此它们可以同时支持使用同一数据库的多个实验。

运行 hyperopt-mongo-worker

如果您运行上面的代码片段,您会看到它在调用 fmin 处阻塞(挂起)。MongoTrials 在 fmin 内部将自己描述为一个 异步 试验对象,因此当建议新的搜索点时,fmin 实际上不会评估目标函数。相反,它只是坐在那里,耐心等待另一个进程来完成这项工作并将结果更新到 mongodb。hyperopt 的 bin 目录中包含的 hyperopt-mongo-worker 脚本就是为此目的编写的。当您安装 hyperopt 时,它应该已经安装到您的 $PATH 中。

当上面的脚本中的 fmin 调用被阻塞时,打开一个新的 shell 并输入

hyperopt-mongo-worker --mongo=localhost:1234/foo_db --poll-interval=0.1

它将从 mongodb 中取出工作项,评估 math.sin 函数,并将结果存回数据库。在 fmin 函数尝试了足够多的点后,它将返回,上面的脚本也将终止。然后 hyperopt-mongo-worker 脚本将闲置几分钟,等待更多工作出现,然后也会终止。

在这种情况下,我们明确设置了轮询间隔,因为默认的计时设置是针对至少需要一两分钟才能完成的任务(搜索点评估)的。

MongoTrials 是一个持久对象

如果您第二次运行上面的示例,

best = fmin(math.sin, hp.uniform('x', -2, 2), trials=trials, algo=tpe.suggest, max_evals=10)

您会看到它立即返回,并且什么也没发生。这是因为您连接的数据库中已经有足够的试验;您在运行第一个实验时已经计算了它们。如果您想进行另一次搜索,可以更改数据库名称或 exp_key。如果您想扩展搜索,则可以调用 fmin 并设置更高的 max_evals 值。或者,您可以启动其他进程,这些进程专门创建 MongoTrials 来分析数据库中已有的结果。这些其他进程根本不需要调用 fmin。