Jul*_* H. 7 optimization nlp micro-optimization spacy
很长一段时间以来,我一直在尝试了解如何系统地让 Spacy 尽可能快地运行,如果可能的话,我希望这篇文章成为维基风格的公共帖子。
以下是我目前所知道的,每个点都有一些附属问题:
1. 空间将在更快的硬件上运行得更快。例如,尝试使用具有更多 CPU 核心或更多 RAM/主内存的计算机。
我不知道的是:
Doc )更多地依赖于 CPU 而非 RAM,为什么?Doc 一系列算术计算(神经网络的编译二进制文件)吗?CPU 核心越多,一次可以完成的计算就越多,因此速度就越快?这是否意味着增加 RAM 不会使这个过程更快?2. 您可以通过删除不需要的组件来使 Spacy 运行得更快,例如通过 nlp = spacy.load("en_core_web_sm", disable=['tagger', 'ner', 'lemmatizer', 'textcat'])
import spacy稍微慢一些。如果您还没有加载语言模型,那么除了向命名空间添加函数之外,这里加载的最重要的东西是什么?是否可以只加载您需要的部分模块?3. 您可以通过使用某些选项来使其运行得更快,从而使其运行得更快。
nlp.pipe、n_process、batch_size和的多重处理joblib,但那是针对多个文档的,而我现在只处理单个文档。4. 您可以通过最大限度地减少 Spacy 执行相同操作的次数来使其更快。
您可以让 Spacy 在服务器上保持活动状态,并在需要时向其传递处理命令
您可以序列化 a 以稍后重新加载它,并且可以使用或Doc 进一步排除不需要的属性 doc.to_bytes(exclude=["tensor"])doc.to_array([LOWER, POS, ENT_TYPE, IS_ALPHA])
5.还有什么吗?
以下清单重点关注运行时性能优化而不是训练(即,当使用config.cfg通过便利包装器加载的现有文件时spacy.load(),而不是训练自己的模型并创建新config.cfg文件),但是,大多数要点仍然适用。这个列表并不全面:spaCy 库非常广泛,并且有很多方法可以构建管道和执行任务。因此,在这里包含所有案例是不切实际的,无论如何,这个列表旨在成为一个方便的参考和起点。
中央处理器。spaCy 在运行时的大部分工作将使用 CPU 指令来分配内存、为内存赋值并执行计算,就速度而言,这将受 CPU 限制而不是 RAM,因此,性能主要取决于中央处理器。因此,在大多数情况下,选择更好的 CPU 而不是更多的 RAM 是更明智的选择。一般来说,具有更高频率、更多核心/线程、更多缓存等的新型 CPU 将实现更快的 spaCy 处理时间。然而,简单地比较不同 CPU 架构之间的这些数字是没有用的。相反,请查看cpu.userbenchmark.com等基准测试(例如i5-12600k 与 Ryzen 9 5900X),并比较潜在 CPU 的单核和多核性能,以找到可能提供更好性能的 CPU。请参阅有关超线程和核心/线程计数的脚注 (1)。
\n内存。RAM 的实际考虑因素是大小:较大的文本需要更多的内存容量,速度和延迟不太重要。如果您的 RAM 容量有限,请在创建大型输入文本(例如)时禁用NER和。如果您需要管道的这些部分,则一次只能处理大约几个字符,如果不需要,您将能够处理更多字符。请注意,默认的 spaCy 输入文本限制为 1,000,000 个字符,但是可以通过设置更改此限制parserDocdoc = nlp("My really long text", disable = [\'ner\', \'parser\'])100,000 * available_RAM_in_GBnlp.max_length = your_desired_length。
图形处理器。如果您选择使用 GPU,则使用基于 GPU 的计算的管道的某些方面可以缩短处理时间。请参阅下面有关使用 GPU 的部分。与 CPU 相同的一般规则也适用于此:通常,具有更高频率、更多内存、更大内存总线宽度、更大带宽等的新型 GPU 将实现更快的 spaCy 处理时间。
\n超频。如果您有超频经验并且拥有能够执行此操作的正确硬件(充足的电源、冷却、主板芯片组),那么在不更改硬件的情况下获得额外性能的另一种有效方法是对 CPU/GPU 进行超频。
\n当计算资源有限和/或不太关心准确性时(例如,在实验或测试想法时),加载注重效率的 spaCy 管道(即具有较小模型的管道)。例如:
\n# Load a "smaller" pipeline for faster processing\nnlp = spacy.load("en_core_web_sm")\n# Load a "larger" pipeline for more accuracy\nnlp = spacy.load("en_core_web_trf")\nRun Code Online (Sandbox Code Playgroud)\n作为差异的具体示例,在同一系统上,较小的en_core_web_lg管道每秒能够处理 10,014 个单词,而en_core_web_trf管道仅处理 684 个单词。请记住,速度和准确性之间通常需要权衡。
由于基于神经网络的模型的性质,可以使用 GPU 有效地解决其计算,从而缩短处理时间。例如,en_core_web_lg当使用 CPU 和 GPU 时,管道每秒可以处理 10,014 个单词和 14,954 个单词。
pip install -U spacy[cuda]可以通过在命令提示符中调用来为 CUDA 兼容 GPU(即 Nvidia GPU)安装 spaCy 。一旦启用了 GPU 的 spaCy 安装存在,就可以在加载任何管道之前调用程序中的spacy.prefer_gpu()或。spacy.require_gpu()请注意,require_gpu()如果没有可用的 GPU,将会引发错误。例如:
spacy.prefer_gpu() # Or use spacy.require_gpu()\nnlp = spacy.load("en_core_web_sm")\nRun Code Online (Sandbox Code Playgroud)\n处理大量文本时,如果让统计模型处理批量文本(默认为 1000),并使用nlp.pipe(). 例如:
texts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts, batch_size=1000))\nRun Code Online (Sandbox Code Playgroud)\n为了利用多个 CPU 核心,spaCy 内置了对多处理的支持,并nlp.pipe()使用n_process。例如,
texts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts, n_process=4))\nRun Code Online (Sandbox Code Playgroud)\n请注意,每个进程都需要自己的内存。这意味着每次新进程spawned(默认启动方法)时,都必须将模型数据复制到每个单独进程的内存中(因此,模型越大,生成进程的开销就越大)。因此,如果您只是执行小任务,建议您增加批处理大小并使用更少的进程。例如,
texts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts, n_process=2, batch_size=2000)) # default batch_size = 1000\nRun Code Online (Sandbox Code Playgroud)\n最后,由于 RAM 有限,通常不建议在 GPU 上进行多处理。
\n从管道中不需要的模型生成预测会不必要地降低性能。人们可以通过在加载管道时(即使用)或在处理期间(即使用)禁用或排除特定组件来防止这种情况。spacy.load()nlp.pipe()
如果您的内存有限,则exclude不需要的组件,例如:
# Load the pipeline without the entity recognizer\nnlp = spacy.load("en_core_web_sm", exclude=["ner"])\nRun Code Online (Sandbox Code Playgroud)\n如果您稍后可能在程序中需要特定组件,但仍希望提高临时不需要这些组件的任务的处理速度,请使用disable,例如:
# Load the tagger but don\'t enable it\nnlp = spacy.load("en_core_web_sm", disable=["tagger"])\n# ... perform some tasks with the pipeline that don\'t require the tagger\n# Eventually enable the tagger\nnlp.enable_pipe("tagger")\nRun Code Online (Sandbox Code Playgroud)\n请注意,对于多种语言,lemmatizer取决于tagger+attribute_ruler或。morphologizer如果禁用这些组件中的任何一个,您\xe2\x80\x99将看到词形还原器警告,除非词形还原器也被禁用。
如果您一直在修改管道或词汇表、更新模型组件、处理文档等,那么保存进度以便稍后重新加载是有好处的。这需要将对象的内容/结构转换为可以保存的格式——这一过程称为serialization.
nlp = spacy.load("en_core_web_sm")\n# ... some changes to pipeline\n# Save serialized pipeline\nnlp.to_disk("./en_my_pipeline")\n# Load serialized pipeline\nnlp.from_disk("./en_my_pipeline")\nRun Code Online (Sandbox Code Playgroud)\nDoc对象该类DocBin提供了一种简单的方法来序列化/反序列化多个Doc对象,这也比调用Doc.to_bytes()每个对象更有效Doc对象更有效。例如:
from spacy.tokens import DocBin\ntexts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts))\ndoc_bin = DocBin(docs=docs)\n# Save the serialized DocBin to a file\ndoc_bin.to_disk("./data.spacy")\n# Load a serialized DocBin from a file\ndoc_bin = DocBin().from_disk("./data.spacy")\nRun Code Online (Sandbox Code Playgroud)\n(1) “超线程”是英特尔的商标术语,用于指代其专有的同步多线程 (SMT) 实现,该实现可提高计算的并行性(即一次执行多个任务)。AMD 也有 SMT,只是没有一个花哨的名字。简而言之,具有 2 路 SMT (SMT-2) 的处理器允许操作系统 (OS) 将处理器上的每个物理内核视为两个内核(称为“虚拟内核”)。采用 SMT 的处理器在可以利用这些多个“核心”(有时称为“线程”)的任务上将表现得更好(例如,Ryzen 5600X 是 6 核/12 线程处理器(即 6 个物理核心,但采用 SMT-2) ,它有 12 个“虚拟核心”或“线程”))。请注意,英特尔最近发布了带有 e 核心的 CPU 架构,这些核心没有超线程,尽管处理器上的其他核心(即 p 核心)拥有超线程,因此您会看到一些芯片,例如i5-12600k有10个超线程核心,但它有16个线程而不是20个。这是因为只有6个p核有超线程,而4个e核没有,因此总共有16个线程。
\n