繁体   English   中英

如何更快地将 Word2Vec 预训练的 model 加载到 Gensim 中?

[英]How can a Word2Vec pretrained model be loaded in Gensim faster?

我正在使用以下方法加载 model:

model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True) 

现在每次我在 Pycharm 中运行文件时,它都会再次加载 model。

那么,有没有一种方法可以加载一次,并且在我运行诸如model['king']model.doesnt_match("house garage store dog".split())之类的东西时可用

因为每当我要检查相似性或不匹配的单词时,都会花费很多时间。 当我运行model.most_similar('finance')时,它真的很慢,整个笔记本电脑冻结了大约 2 分钟。 那么,有没有办法让事情变得更快,因为我想在我的项目中使用它,但我不能让用户等待这么久。

有什么建议么?

这是一组在磁盘上大约 3.6GB 的词向量,加载时稍大一些 - 因此仅磁盘 IO 可能需要相当长的时间。

此外,至少在gensim-4.0.0 (现在可作为 beta 预览版)之前,Gensim 到 3.8.3 的版本需要在第一次使用.most_similar().doesnt_match()操作(及其他)。 此步骤也可能需要很长时间,然后立即需要几 GB 的 memory 才能获得完整的 model,例如GoogleNews - 在任何 RAM 少于 8GB 的机器上,使用较慢的虚拟内存甚至崩溃的风险内存错误。 (从gensim-4.0.0beta开始,一旦 model 加载,第一个.most_similar()将不需要任何额外的预计算/分配。)

避免这种烦人的延迟的主要方法是构建您的代码或服务,以便在每次计算之前单独重新加载它。 通常,这意味着保持一个已加载的交互式 Python 进程处于活动状态,为您的额外操作(或以后的用户请求,可能是 Web 部署服务的情况)做好准备。

听起来您可能正在开发单个 Python 脚本,例如mystuff.py ,并通过 PyCharm 的执行/调试/等实用程序运行它以启动 Python 文件。 不幸的是,在每次完成执行时,这将使整个 Python 进程结束,完全释放任何加载的数据/对象。 再次运行脚本必须再次执行所有加载/预计算。

如果您的主要兴趣是自己对一组词向量进行一些调查性检查和实验,那么一个很大的改进是转移到一个交互式环境,该环境可以保持单个 Python 运行并等待您的下一行代码。

例如,如果您在命令行中运行ipython解释器,在单独的 shell 中,您可以加载 model,执行一些查找/相似性操作以打印结果,然后让提示等待您的下一个代码。 在您选择退出解释器之前,该进程的满载 state 仍然可用。

同样,如果您在 Web 浏览器中使用 Jupyter Notebook,您将在不断增长的可重新运行的可编辑代码和结果“单元”中获得相同的解释器体验。 所有人都共享相同的后端解释器进程,并具有持久的 state - 除非您选择重新启动“内核”。

如果您为用户的调查工作提供脚本或库代码,他们也可以使用此类持久解释器。

但是,如果您正在构建 web 服务或其他持续运行的工具,您同样需要确保 model 在用户请求之间保持加载。 (具体如何操作取决于您的部署细节,包括 web 服务器软件,因此最好将其作为一个单独的问题询问/搜索,以提供更多详细信息。 )

还有另一个技巧可能有助于您不断重新启动的情况。 Gensim 可以以自己的本机格式保存和加载,这可以利用“内存映射”。 本质上,磁盘上的文件范围可以直接由操作系统的虚拟 memory 系统使用。 然后,当许多进程都在自己的内存空间中将相同的文件指定为他们想要的东西的规范版本时,操作系统知道他们可以重用该文件中已经在 memory 中的任何部分。

这种技术在 `gensim-4.0.0beta' 和更高版本中更简单,所以我只描述那里所需的步骤。 (如果您想在 Gensim 4.0 正式发布之前强制进行此预览安装,请参阅此消息。)

首先,加载原始格式的文件,然后以 Gensim 的格式重新保存它:

from gensim.models import KeyedVectors
kv_model = KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True) 
kv_model.save('GoogleNews-vectors-negative300.kv')

请注意,如果您将 model 移至其他位置,则会创建一个额外的.npv文件,该文件必须与GoogleNews-vectors-negative300.kv一起保存。 只需执行一次即可创建新文件。

其次,当您以后需要 model 时,使用 Gensim 的 .load .load()mmap选项:

kv_model = KeyedVectors.load('GoogleNews-vectors-negative300.kv', mmap='r')
# do your other operations

马上, .load()应该更快地完成。 但是,当您第一次尝试访问任何单词时——或.most_similar()中的所有单词——仍然需要从磁盘读取,只是将延迟转移到以后。 (如果您只进行单个单词查找或少量.doesnt_match()单词,您可能不会注意到任何长时间的滞后。)

此外,根据您的操作系统和 RAM 量,您甚至可以在运行一次脚本时获得一些加速,让它完成,然后很快再次运行它。 在某些情况下,即使操作系统已经结束了先前的进程,它的虚拟内存机制也可能会记住一些尚未清除的旧进程 memory 页面仍在 RAM 中,并且对应于内存映射文件。 因此,下一个内存映射将重用它们。 (我不确定这种效果,如果您处于记忆力低下的情况,那么从已完成内容中重复使用的机会可能会完全消失。

但是,您可以通过采取第三步来增加 model 文件保持内存驻留的机会:启动单独的 Python 进程以预加载 model 直到退出。 为此,请制作另一个 Python 脚本,例如preload.py

from gensim.models import KeyedVectors
from threading import Semaphore
model = KeyedVectors.load('GoogleNews-vectors-negative300.kv', mmap='r')
model.most_similar('stuff')  # any word will do: just to page all in
Semaphore(0).acquire()  # just hang until process killed

在单独的 shell: python preload.py中运行此脚本。 它将 map 将 model 转换为 memory,然后挂起直到您CTRL-C退出它。

现在,您在同一台机器上运行的任何其他内存映射同一文件的代码将自动重新使用来自此单独进程的任何已加载的 memory 页面。 (在内存不足的情况下,如果依赖任何其他虚拟内存,范围仍可能从 RAM 中清除。但如果您有充足的 RAM,这将确保每次新引用同一文件时磁盘 IO 最小。)

最后,可以与其中任何一个混合的另一个选项是仅加载完整的 300 万令牌、3.6GB 的GoogleNews集的子集。 不太常见的词在这个文件的末尾附近,跳过它们不会影响很多用途。 因此,您可以使用load_word2vec_format()limit参数仅加载一个子集 - 加载速度更快,使用更少的 memory,并更快地完成以后的全集搜索(如.most_similar() )。 例如,仅加载第一个 1,000,000 个字,从而节省大约 67% 的 RAM/加载时间/搜索时间:

from gensim.models import KeyedVectors
kv_model = KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin',  limit=1000000, binary=True) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM