与非多处理情况相比,使用 AllenNLP 解码的多处理是缓慢的

Posted

技术标签:

【中文标题】与非多处理情况相比,使用 AllenNLP 解码的多处理是缓慢的【英文标题】:Using multiprocessing with AllenNLP decoding is sluggish compared to non-multiprocessing case 【发布时间】:2021-12-28 16:19:35 【问题描述】:

我正在使用 AllenNLP(2.6 版)语义角色标注模型来处理一大堆句子。我的 Python 版本是 3.7.9。我在 MacOS 11.6.1 上。我的目标是使用multiprocessing.Pool 来并行化工作,但是通过池进行的调用比在父进程中花费的时间要长,有时甚至相当长。

在父进程中,我已将模型显式放置在共享内存中,如下所示:

from allennlp.predictors import Predictor            
from allennlp.models.archival import load_archive
import allennlp_models.structured_prediction.predictors.srl
PREDICTOR_PATH = "...<srl model path>..."

archive = load_archive(PREDICTOR_PATH)
archive.model.share_memory()
PREDICTOR = Predictor.from_archive(archive)

我知道模型只在父进程中加载​​一次。无论我是否要使用池,我都会将模型放在共享内存中。我正在使用torch.multiprocessing,正如许多人推荐的那样,我正在使用spawn 启动方法。

我正在使用Pool.apply_async 调用池中的预测器,并且我正在为子进程中的调用计时。我知道池正在使用可用的 CPU(我有六个内核),而且我的物理内存还远未耗尽,因此没有理由将子进程交换到磁盘。

对于一组 395 个句子,情况如下:

没有多重处理:638 总处理秒数(以及经过的时间)。 使用 4 进程池:经过时间 293 秒,总处理时间为 915 秒。 使用 12 个进程池:经过时间 263 秒,总处理时间为 2024 秒。

进程越多,AllenNLP 的总处理时间越差 - 即使模型显式位于共享内存中,并且在调用期间跨越进程边界的唯一内容是输入文本和输出 JSON。

我已经进行了一些分析,首先让我感到震惊的是函数torch._C._nn.linear 在多处理情况下花费的时间要长得多。这个函数接受两个张量作为参数——但是没有张量通过进程边界,我正在解码,而不是训练,所以模型应该是完全只读的。似乎它必须是共享模型资源的锁定或竞争问题,但我完全不明白为什么会这样。而且我不是torch 程序员,所以我对正在发生的事情的理解有限。

任何指针或建议将不胜感激。

【问题讨论】:

我还尝试使用copy.deepcopy 将预测器中的模型复制为池元素的初始化代码的一部分,但这只会增加创建池元素的时间,并且没有显着减少 AllenNLP 处理时间。 【参考方案1】:

原来我没有比较完全正确的东西。这个线程:https://github.com/allenai/allennlp/discussions/5471 详细介绍了所有细节。简而言之,因为pytorch 可以在后台使用额外的资源,所以当并行运行两个实例时,我没有多处理的基线测试并没有给我的计算机带来足够的负担;我必须运行 4 个实例才能看到惩罚,在这种情况下,4 个并行非多处理调用或一个具有 4 个子进程的多处理案例的总处理时间基本相同。

【讨论】:

以上是关于与非多处理情况相比,使用 AllenNLP 解码的多处理是缓慢的的主要内容,如果未能解决你的问题,请参考以下文章

Scrapy-Redis非多网址采集的使用

开发 | 艾伦人工智能研究院开源AllenNLP,基于PyTorch轻松构建NLP模型

Allennlp coref 模型最新版本

setTimeout()和setInterval() 何时被调用执行(非多线程).RP

将 AllenNLP 解释与 HuggingFace 模型一起使用

在 allennlp 中使用 Transformer QA 预训练模型进行阅读理解的通过限制