使用textacy或spacy进行多进程处理

3

我正在尝试通过并行化textacy来加速处理大量文本列表的过程。当我使用multiprocessing中的Pool时,生成的textacy语料库为空。我不确定问题出在我使用textacy还是多进程编程模型上?以下是说明我的问题的示例:

import spacy
import textacy
from multiprocessing import Pool

texts_dict={
"key1":"First text 1."
,"key2":"Second text 2."
,"key3":"Third text 3."
,"key4":"Fourth text 4."
}

model=spacy.load('en_core_web_lg')

# this works

corpus = textacy.corpus.Corpus(lang=model)

corpus.add(tuple([value, {'key':key}],) for key,value in texts_dict.items())

print(corpus) # prints Corpus(4 docs, 8 tokens)
print([doc for doc in corpus])

# now the same thing with a worker pool returns empty corpus

corpus2 = textacy.corpus.Corpus(lang=model)

pool = Pool(processes=2) 
pool.map( corpus2.add, (tuple([value, {'key':key}],) for key,value in texts_dict.items()) )

print(corpus2) # prints Corpus(0 docs, 0 tokens)
print([doc for doc in corpus2])

# to make sure we get the right data into corpus.add
pool.map( print, (tuple([value, {'key':key}],) for key,value in texts_dict.items()) )

Textacy基于spaCy。SpaCy不支持多线程,但据说可以在多个进程中运行。

https://github.com/explosion/spaCy/issues/2075

根据@constt的建议https://dev59.com/Prbna4cB1Zd3GeqPg8oK#58317741,将结果收集到语料库中适用于数据集的大小最多为n_docs = 10273 n_sentences = 302510 n_tokens = 2053129。

对于更大的数据集(16000个文档3MM标记),我会得到以下错误:

result_corpus=corpus.get() 
  File "<string>", line 2, in get
  File "/usr/lib/python3.6/multiprocessing/managers.py", line 772, in _callmethod
    raise convert_to_error(kind, result)
multiprocessing.managers.RemoteError: 
---------------------------------------------------------------------------
Unserializable message: Traceback (most recent call last):
  File "/usr/lib/python3.6/multiprocessing/managers.py", line 283, in serve_client
    send(msg)
  File "/usr/lib/python3.6/multiprocessing/connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "/usr/lib/python3.6/multiprocessing/connection.py", line 393, in _send_bytes
    header = struct.pack("!i", n)
struct.error: 'i' format requires -2147483648 <= number <= 2147483647

我会调查,但如果您有直接的解决方案 - 非常感谢!

1个回答

4

由于Python进程在独立的内存空间中运行,因此您需要在池中的进程之间共享corpus对象。为了实现这一点,您需要将corpus对象封装到一个可共享的类中,并使用BaseManager类进行注册。以下是如何重构代码使其正常工作:

#!/usr/bin/python3
from multiprocessing import Pool
from multiprocessing.managers import BaseManager

import spacy
import textacy


texts = {
    'key1': 'First text 1.',
    'key2': 'Second text 2.',
    'key3': 'Third text 3.',
    'key4': 'Fourth text 4.',
}


class PoolCorpus(object):

    def __init__(self):
        model = spacy.load('en_core_web_sm')
        self.corpus = textacy.corpus.Corpus(lang=model)

    def add(self, data):
        self.corpus.add(data)

    def get(self):
        return self.corpus


BaseManager.register('PoolCorpus', PoolCorpus)


if __name__ == '__main__':

    with BaseManager() as manager:
        corpus = manager.PoolCorpus()

        with Pool(processes=2) as pool:
            pool.map(corpus.add, ((v, {'key': k}) for k, v in texts.items()))

        print(corpus.get())

输出:

Corpus(4 docs, 16 tokens)

非常感谢您提供如此清晰的建议!我已经在示例和较小的真实数据集(n_docs = 153,n_sentences = 953,n_tokens = 7600)上运行它,并且没有出现任何问题。但是,在一个包含16000个文档和约3百万个标记的数据集中,会出现错误。 我将把错误消息添加到问题中。 - Diego
n_docs=10273,n_sentences=302510,n_tokens=2053129也已经处理完成。 - Diego
@Diego,你尝试过将文档分成长度为10000的块,并使用相同的共享语料库在池中顺序处理它们吗? - constt
1
是的,我刚刚做到了,而且在相同的限制下运行得很好。 在计算机中,数字2,147,483,647(或十六进制7FFF,FFFF16)是32位有符号二进制整数的最大正值。我运行的是64位Python。看起来这是影响我的问题https://github.com/joblib/joblib/issues/731#issuecomment-409893849 但它必须已经被修复了(但在Python 3.8中?)阶段:已解决 组件:版本:Python 3.8 - Diego
我尝试安装Python 3.8,但是没有Scipy(OpenBlas,Lapack)的wheel,所以我暂时放弃了这个方法。无论如何,不幸的是,与单进程相比,上述并行执行并没有带来任何加速。我想知道是否应该在此发布我的发现或接受您的答案并开始另一个问题? - Diego

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接