如何将 gensim 的 KeyedVectors 对象存储在 Redis 队列工作线程内的全局变量中



我正在尝试将数据存储在 Redis 队列 (RQ) 工作线程内的全局变量中,以便此数据保持预加载状态,即不需要为每个 RQ 作业加载它。

具体来说,我正在使用Word2Vec向量并使用gensim的KeyedVectors加载它们。

我的应用程序在Python Flask中,运行在Linux服务器上,使用Docker进行容器化。

我的目标是通过始终在内存中加载少量大型矢量文件来减少处理时间。

我首先尝试将它们存储在 Flask 的全局变量中,但随后我的 8 个 gunicorn 工人中的每一个都加载了向量,这占用了大量 RAM。

我只需要一个工人来存储特定的矢量文件。

有人告诉我,一种解决方案是让一定数量的 RQ 工作线程在全局变量中保存向量,这样我就可以控制哪些工作线程获取加载哪些向量文件。

这是我到目前为止所拥有的:

RQ_worker.py

from rq import Worker, Connection
from gensim.models.keyedvectors import KeyedVectors
from my_common_methods import get_redis
W2V = KeyedVectors.load_word2vec_format('some_path/vectors.bin', binary=True)
def rq_task(some_args):
# use some_args and W2V to do some processing, e.g.:
with open(some_args_filename, 'w') as f_out:
f_out.write(str(W2V['word']))
if __name__ == '__main__':
with Connection(get_redis()):
worker = Worker(['default'])
worker.work()

app.py

from rq import Queue, Connection
from RQ_worker import rq_task
@app.route("/someroute", methods=['POST'])
def some_route():
# test Redis Queue
with Connection(get_redis()):
q = Queue()
task = q.enqueue(rq_task, some_args)

docker-stack.yml

version: '3.7'
services:
nginx:
image: nginx:mainline-alpine
deploy: ...
configs: ...
networks: ...
flask:
image: ...
deploy: ...
environment: ...
networks: ...
volumes: ...
worker:
image: ...
command: python2.7 RQ_worker.py
deploy:
replicas: 1
networks: ...
volumes:
- /some_path/data:/some_path/data
configs:
nginx.conf:
external: true
name: nginx.conf
networks:
external:
external: true
database:
external: true

(我从 Docker 中编辑了一堆东西,但如果相关,可以提供更多详细信息。

上述方法通常有效,除了RQ worker 似乎每次获得新作业时都会从头开始加载 W2V,这违背了整个目的。它应该将存储在 W2V 中的向量作为全局变量,这样就不需要每次都重新加载它们。

我错过了什么吗?我应该以不同的方式设置它吗?

有人告诉我,可以使用 mmap 将向量文件加载到 RQ worker 所在的全局变量中,但我不确定这将如何与 KeyedVector 一起使用。

任何建议将不胜感激!

如果你使用load_word2vec_format(),代码将始终解析(非原生到gensim 或 Python)词向量格式,并分配新的对象/内存来存储结果。

您可以改用 gensim 的本机.save()以更友好的格式存储,以便以后进行本机.load()操作。大型矢量数组将存储在单独的内存映射就绪文件中。然后,当您.load(..., mmap='r')这些文件时,即使从同一容器中的不同线程或进程多次,它们也将共享相同的 RAM。

(请注意,这甚至不需要任何共享全局变量。操作系统会注意到每个进程都在请求相同的只读内存映射文件,并自动共享这些 RAM 页。唯一的重复将是冗余的 Pythondict帮助每个单独的.load()知道共享数组中的索引。

在对模型想要重复单位范数的向量进行相似性操作时,需要考虑一些额外的皱纹 - 有关如何解决此问题的更多详细信息,请参阅此旧答案:

如何加快Gensim Word2vec模型加载时间?

(请注意,syn0syn0_norm已在最近的gensim版本中重命名为vectorsvectors_norm,但旧名称可能仍适用于弃用警告一段时间。

最新更新