在docker容器之间共享gensim的KeyedVectors对象的内存

时间:2018-07-31 14:41:19

标签: python mmap gensim word2vec

related question solution之后,我创建了Docker容器,该容器将GoogleNews-vectors-negative300 KeyedVector加载到docker容器中,并将其全部加载到内存中

KeyedVectors.load(model_path, mmap='r')
word_vectors.most_similar('stuff')

我还有另一个Docker容器,该容器提供REST API,可使用

加载此模型
KeyedVectors.load(model_path, mmap='r')

我观察到,满载的容器占用了超过5GB的内存,每个gunicorn工作人员都占用了1.7GB的内存。

CONTAINER ID        NAME                        CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
acbfd080ab50        vectorizer_model_loader_1   0.00%               5.141GiB / 15.55GiB   33.07%              24.9kB / 0B         32.9MB / 0B         15
1a9ad3dfdb8d        vectorizer_vectorizer_1     0.94%               1.771GiB / 15.55GiB   11.39%              26.6kB / 0B         277MB / 0B          17

但是,我希望所有这些进程都为KeyedVector共享相同的内存,因此在所有容器之间仅需要5.4 GB共享。

有人试图实现这一目标并取得成功吗?

编辑: 我尝试了以下代码段,并且确实在不同容器之间共享相同的内存。

import mmap
from threading import Semaphore

with open("data/GoogleNews-vectors-negative300.bin", "rb") as f:
    # memory-map the file, size 0 means whole file
    fileno = f.fileno()
    mm = mmap.mmap(fileno, 0, access=mmap.ACCESS_READ)
    # read whole content
    mm.read()
    Semaphore(0).acquire()
    # close the map
    mm.close()

KeyedVectors.load(model_path, mmap='r')不共享内存的问题

edit2: 通过研究gensim的源代码,我看到调用np.load(subname(fname, attrib), mmap_mode=mmap)来打开内存映射文件。以下代码示例跨多个容器共享内存。

from threading import Semaphore

import numpy as np

data = np.load('data/native_format.bin.vectors.npy', mmap_mode='r')
print(data.shape)
# load whole file to memory
print(data.mean())
Semaphore(0).acquire()

2 个答案:

答案 0 :(得分:2)

经过广泛的调试,我发现mmap对于KeyedVectors对象中的numpy数组可以正常工作。

但是,KeyedVector具有其他属性,例如self.vocabself.index2wordself.index2entity,它们是不共享的,每个对象消耗约1.7 GB的内存。

答案 1 :(得分:0)

我不确定容器化是否允许容器共享相同的内存映射文件-但即使这样做,您用来衡量每个容器内存使用情况的任何实用程序都有可能将内存计数两次,即使共享。您正在使用哪种工具来监视内存使用情况,并且确定它会指示真正的共享吗? (如果在gensim之外,您尝试使用Python的mmap.mmap()在两个容器中打开相同的巨型文件,会发生什么情况?与gensim情况相比,您看到的内存使用量是相同,更多还是更少?)

但也:为了执行most_similar()KeyedVectors将在属性{{中创建一个 second 个单词向量数组,将其标准化为单位长度。 1}}。 (只需在第一次需要时执行一次。)此范数数组不会保存,因为它始终可以重新计算。因此,为了您的使用,每个容器都将创建自己的非共享vectors_norm数组-撤消共享内存映射文件中所有可能的内存节省。

您可以通过以下方法解决此问题:

  • 在加载模型之后但在触发自动归一化之前,使用一个特殊的参数自己明确强制它自己来替换原始原始向量。然后保存此预规范版本:

    vectors_norm
  • 稍后以内存映射的方式重新加载模型时,请手动将word_vectors = KeyedVectors.load(model_path) word_vectors.init_sims(replace=True) word_vectors.save(normed_model_path) 属性设置为与vectors_norm相同,以防止规范数组的冗余重新创建:

    vectors

如果是阻止您看到期望的内存节省的规范,则此方法可能会有所帮助。