Spacy 优化清单?

Jul*_* H. 7 optimization nlp micro-optimization spacy

很长一段时间以来,我一直在尝试了解如何系统地让 Spacy 尽可能快地运行,如果可能的话,我希望这篇文章成为维基风格的公共帖子。

以下是我目前所知道的,每个点都有一些附属问题:

1. 空间将在更快的硬件上运行得更快。例如,尝试使用具有更多 CPU 核心或更多 RAM/主内存的计算机。

我不知道的是:

  • Spacy 执行的哪些具体方面(尤其是实例化对象的主要方面 Doc )更多地依赖于 CPU 而非 RAM,为什么?
  • 对象的实例化是 Doc 一系列算术计算(神经网络的编译二进制文件)吗?CPU 核心越多,一次可以完成的计算就越多,因此速度就越快?这是否意味着增加 RAM 不会使这个过程更快?
  • 对于 Spacy 来说,除了内核之外,CPU 或 GPU 是否还有其他方面值得关注,从而使一款芯片优于另一款芯片?有人提到“超线程”。
  • 是否有相对于输入字符串长度的每个管道组件(例如解析器)的时间的标准数学估计?像解析器一样,秒=输入中的字符数?/ CPU 核心数

2. 您可以通过删除不需要的组件来使 Spacy 运行得更快,例如通过 nlp = spacy.load("en_core_web_sm", disable=['tagger', 'ner', 'lemmatizer', 'textcat'])

  • 仅加载 Spacy 模块本身会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.还有什么吗?

Kyl*_*erg 7

清单

\n

以下清单重点关注运行时性能优化而不是训练(即,当使用config.cfg通过便利包装器加载的现有文件时spacy.load(),而不是训练自己的模型并创建新config.cfg文件),但是,大多数要点仍然适用。这个列表并不全面:spaCy 库非常广泛,并且有很多方法可以构建管道和执行任务。因此,在这里包含所有案例是不切实际的,无论如何,这个列表旨在成为一个方便的参考和起点。

\n

概括

\n
    \n
  1. 如果有更强大的硬件可用,请使用它。
  2. \n
  3. 使用(最佳)小型模型/管道。
  4. \n
  5. 如果可能,请使用您的 GPU。
  6. \n
  7. 将大文本作为流处理并批量缓冲它们。
  8. \n
  9. 使用多处理(如果适用)。
  10. \n
  11. 仅使用必要的管道组件。
  12. \n
  13. 保存并加载进度以避免重新计算。
  14. \n
\n

1.如果有更强大的硬件,请使用它。

\n

中央处理器。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。

\n

图形处理器。如果您选择使用 GPU,则使用基于 GPU 的计算的管道的某些方面可以缩短处理时间。请参阅下面有关使用 GPU 的部分。与 CPU 相同的一般规则也适用于此:通常,具有更高频率、更多内存、更大内存总线宽度、更大带宽等的新型 GPU 将实现更快的 spaCy 处理时间。

\n

超频。如果您有超频经验并且拥有能够执行此操作的正确硬件(充足的电源、冷却、主板芯片组),那么在不更改硬件的情况下获得额外性能的另一种有效方法是对 CPU/GPU 进行超频。

\n

2.(最佳)使用小型模型/管道。

\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")\n
Run Code Online (Sandbox Code Playgroud)\n

作为差异的具体示例,在同一系统上,较小的en_core_web_lg管道每秒能够处理 10,014 个单词,而en_core_web_trf管道仅处理 684 个单词。请记住,速度和准确性之间通常需要权衡。

\n

3. 如果可能,请使用 GPU。

\n

由于基于神经网络的模型的性质,可以使用 GPU 有效地解决其计算,从而缩短处理时间。例如,en_core_web_lg当使用 CPU 和 GPU 时,管道每秒可以处理 10,014 个单词和 14,954 个单词。

\n

pip install -U spacy[cuda]可以通过在命令提示符中调用来为 CUDA 兼容 GPU(即 Nvidia GPU)安装 spaCy 。一旦启用了 GPU 的 spaCy 安装存在,就可以在加载任何管道之前调用程序中的spacy.prefer_gpu()或。spacy.require_gpu()请注意,require_gpu()如果没有可用的 GPU,将会引发错误。例如:

\n
spacy.prefer_gpu() # Or use spacy.require_gpu()\nnlp = spacy.load("en_core_web_sm")\n
Run Code Online (Sandbox Code Playgroud)\n

4. 将大文本作为流处理并批量缓冲。

\n

处理大量文本时,如果让统计模型处理批量文本(默认为 1000),并使用nlp.pipe(). 例如:

\n
texts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts, batch_size=1000))\n
Run Code Online (Sandbox Code Playgroud)\n

5. 使用多重处理(如果适用)。

\n

为了利用多个 CPU 核心,spaCy 内置了对多处理的支持,并nlp.pipe()使用n_process。例如,

\n
texts = ["One document.", "...", "Lots of documents"]\nnlp = spacy.load("en_core_web_sm")\ndocs = list(nlp.pipe(texts, n_process=4))\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,每个进程都需要自己的内存。这意味着每次新进程spawned(默认启动方法)时,都必须将模型数据复制到每个单独进程的内存中(因此,模型越大,生成进程的开销就越大)。因此,如果您只是执行小任务,建议您增加批处理大小并使用更少的进程。例如,

\n
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\n
Run Code Online (Sandbox Code Playgroud)\n

最后,由于 RAM 有限,通常不建议在 GPU 上进行多处理。

\n

6. 仅使用必要的管道组件。

\n

从管道中不需要的模型生成预测会不必要地降低性能。人们可以通过在加载管道时(即使用)或在处理期间(即使用)禁用或排除特定组件来防止这种情况。spacy.load()nlp.pipe()

\n

如果您的内存有限,则exclude不需要的组件,例如:

\n
# Load the pipeline without the entity recognizer\nnlp = spacy.load("en_core_web_sm", exclude=["ner"])\n
Run Code Online (Sandbox Code Playgroud)\n

如果您稍后可能在程序中需要特定组件,但仍希望提高临时不需要这些组件的任务的处理速度,请使用disable,例如:

\n
# 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")\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,对于多种语言,lemmatizer取决于tagger+attribute_ruler或。morphologizer如果禁用这些组件中的任何一个,您\xe2\x80\x99将看到词形还原器警告,除非词形还原器也被禁用。

\n

7. 保存和加载进度以避免重新计算。

\n

如果您一直在修改管道或词汇表、更新模型组件、处理文档等,那么保存进度以便稍后重新加载是有好处的。这需要将对象的内容/结构转换为可以保存的格式——这一过程称为serialization.

\n

序列化管道

\n
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")\n
Run Code Online (Sandbox Code Playgroud)\n

序列化多个Doc对象

\n

该类DocBin提供了一种简单的方法来序列化/反序列化多个Doc对象,这也比调用Doc.to_bytes()每个对象更有效Doc对象更有效。例如:

\n
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")\n
Run Code Online (Sandbox Code Playgroud)\n

脚注

\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