0

我正在使用多处理池来训练机器学习者。

每个 LearnerRun 对象都有一个学习者、一个超参数字典、一个名称、另一个选项字典中的更多选项、要写入结果的目录的名称、一组要训练的示例 ID(切片或 numpy 数组) ,以及一组要测试的示例 ID(也是切片或 numpy 数组)。重要的是,尚未读取训练和测试数据:ID 集相对较小,并指导后续函数的数据库读取行为。

我打电话self.pool.apply_async(learner_run.run),以前工作得很好。现在池似乎已加载完毕,但 run() 函数顶部的打印语句从未打印,因此进程实际上并没有运行。

我已经跟踪了一些关于此的其他线程,发现我可以更详细地看到问题,handler = self.pool.apply_async(learner_run.run)然后是handler.get(). 这将打印“SystemError: NULL result without error in PyObject_Call”。

太好了,我可以谷歌。但是我在 Multiprocessing 的这个问题上所能找到的只是它可能是在将太大而无法腌制的参数传递给子进程时引起的。但是,我显然没有向我的子进程传递任何参数。那么给了什么?

除了超过分配的内存大小的参数(我有理由确定这不是这里的问题)之外,还有什么可以导致 apply_async 给出空结果?

同样,这在我去度假之前有效并且没有改变。对其他代码进行哪些类型的更改可能会导致它停止工作?

在此处输入图像描述

如果我不尝试get()从处理程序中执行,那么执行不会因错误而停止,内存使用会遵循这种奇怪的模式。

4

1 回答 1

0

好的,我发现了问题。事实上,我的 LearnerRun太大,Multiprocessing 无法处理。但是它的方式非常微妙,所以我会描述一下。

显然,需要腌制的不仅仅是论据;该函数也被腌制,包括LearnerRun其执行将依赖的对象(self)。

LearnerRun 的构造函数获取传递给它的选项字典中的所有内容,并使用 setattr 将所有键和值转换为具有值的成员变量。仅此一项就可以了,但是我的同事意识到这会留下几个字符串,这些字符串需要作为数据库引用并设置self.trainDatabase = LarData(self.trainDatabase)and self.coverageDatabase = LarData(self.coverageDatabase),这通常会很好。

除了这意味着要腌制课程,您必须腌制整个数据库!我在进行健全性检查时发现了这一点,其中只是对 LearnerRun 本身进行了序列化,以查看pickle.dumps(learner_run). 我的记忆被淹没了,swap 开始以惊人的速度填满,直到stackoverflow

那么酸洗到磁盘呢?pickle.dump(learner_run, filename)也炸了。在我终止之前它达到了 14.3 GiB!

以后需要时删除这些引用并调用 LarData 构造函数怎么样?巴姆。固定的。一切正常。多处理不再给出神秘的 SystemError。

这是最近泡菜第二次给我带来很大的痛苦。

于 2017-11-27T21:13:52.747 回答