通过 MongoDB 并行化搜索期间的评估
Hyperopt 旨在支持不同类型的试验数据库。默认的试验数据库(Trials)使用 Python 列表和字典实现。默认实现是一个参考实现,易于使用,但不支持并行评估试验所需的异步更新。对于并行搜索,hyperopt 包含一个支持异步更新的 MongoTrials 实现。
要运行并行搜索,您需要执行以下操作(在安装 MongoDB 之后):
-
在网络可见的某个地方启动一个 mongod 进程。
-
修改对
hyperopt.fmin的调用,以使用连接到该 mongod 进程的 MongoTrials 后端。 -
启动一个或多个
hyperopt-mongo-worker进程,这些进程也将连接到 mongod 进程,并在fmin阻塞时执行搜索。
启动 mongod 进程
一旦安装了 MongoDB,启动数据库进程(mongod)就像输入以下命令一样简单:
mongod --dbpath . --port 1234
# 或者将每个数据库存储在其自己的目录中是很好的:
mongod --dbpath . --port 1234 --directoryperdb --journal --nohttpinterface
# 或者考虑将 mongod 作为守护进程启动:
mongod --dbpath . --port 1234 --directoryperdb --fork --journal --logpath log.log --nohttpinterface
Mongo 习惯于预分配几个 GB 的空间(您可以使用 --noprealloc 禁用此功能)以获得更好的性能,因此请考虑一下您希望在何处创建此数据库。在网络文件系统上创建数据库可能会给您的数据库以及网络上的其他人带来糟糕的性能,请小心处理。
此外,如果您的机器对互联网可见,则要么绑定到环回接口并通过 ssh 连接,要么阅读 MongoDB 关于密码保护的文档。
本教程的其余部分基于在 localhost 的 端口 1234 上运行的 mongo。
使用 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-mongo-worker 脚本包含在 hyperopt 的 bin 目录中,正是为此目的而编写的。当您安装 hyperopt 时,它应该已经安装在您的 $PATH 上。
在上述脚本中的 fmin 调用阻塞时,打开一个新的 shell 并输入
hyperopt-mongo-worker --mongo=localhost:1234/foo_db --poll-interval=0.1
它将从 mongodb 中出队一个工作项,评估 math.sin 函数,并将结果存储回数据库。在 fmin 函数尝试了足够的点之后,它将返回,上面的脚本将终止。hyperopt-mongo-worker 脚本将等待几分钟,等待更多工作出现,然后也会终止。
我们在此显式设置轮询间隔,因为默认的时间设置适用于至少需要一两分钟才能完成的作业(搜索点评估)。 如果你再次运行上面的示例,
best = fmin(math.sin, hp.uniform('x', -2, 2), trials=trials, algo=tpe.suggest, max_evals=10)
你会发现它立即返回,没有任何反应。
这是因为你所连接的数据库中已经有足够的试验记录;当你第一次运行实验时,这些试验已经计算过了。
如果你想进行另一次搜索,可以更改数据库名称或exp_key。
如果你想扩展搜索,那么可以调用fmin时将max_evals设置为更大的数值。
或者,你可以启动其他进程,专门创建MongoTrials来分析数据库中已有的结果。这些其他进程根本不需要调用fmin。