spacy v3 en_core_web_trf管道与en_core_web_lg管道的区别

9

我正在使用Spacy 3版本进行性能测试,以便在生产中调整我的实例大小。我观察到以下情况:

观察结果:

模型名称 不带NER的时间 带NER的时间 备注
en_core_web_lg 4.89秒 21.9秒 NER将原始时间增加了350%
en_core_web_trf 43.64秒 52.83秒 在transformer模型的情况下,为什么带NER不带NER场景之间没有显着差异?在en_core_web_trf的情况下,是NER在POS标记之后的一个增量任务吗?

为什么在transformer模型的情况下,带NER不带NER场景之间没有显着差异?在en_core_web_trf的情况下,是NER在POS标记之后的一个增量任务吗?

测试环境:GPU实例

测试代码:

import spacy

assert(spacy.__version__ == '3.0.3')
spacy.require_gpu()
texts = load_sample_texts()  # loads 10,000 texts from a file
assert(len(texts) == 10000)

def get_execution_time(nlp, texts, N):
    return timeit.timeit(stmt="[nlp(text) for text in texts]", 
                           globals={'nlp': nlp, 'texts': texts}, number=N) / N


#  load models
nlp_lg_pos = spacy.load('en_core_web_lg', disable=['ner', 'parser'])
nlp_lg_all = spacy.load('en_core_web_lg')
nlp_trf_pos = spacy.load('en_core_web_trf', disable=['ner', 'parser'])
nlp_trf_all = spacy.load('en_core_web_trf')

#  get execution time
print(f'nlp_lg_pos = {get_execution_time(nlp_lg_pos, texts, N=1)}')
print(f'nlp_lg_all = {get_execution_time(nlp_lg_all, texts, N=1)}')
print(f'nlp_trf_pos = {get_execution_time(nlp_trf_pos, texts, N=1)}')
print(f'nlp_trf_all = {get_execution_time(nlp_trf_all, texts, N=1)}')
1个回答

1
不是专家,但我认为这可能是由于管道的设计所致。 训练好的管道设计 sm/md/lg模型的文档中提到:

ner组件是独立的,具有自己的内部tok2vec层。 sm/md/lg pipeline design

trf模型的文档中提到:

在transformer(trf)模型中,taggerparserner(如果存在)都依赖于transformer组件。

共享嵌入层

在组件之间重用tok2vec层可以使您的流水线运行速度更快,模型更小。然而,这可能会使流水线的模块化程度降低,并且更难以交换组件或重新训练流水线的部分。 共享 vs 独立

共享 独立
更小:模型只需要包含一个嵌入的副本 更大:模型需要包含每个组件的嵌入
更快:一次为整个流程嵌入文档 更慢:为每个组件重新运行嵌入
不太可组合:所有组件在流程中都需要相同的嵌入组件 模块化:组件可以自由移动和交换

实验

  • 注意 1:我正在使用20个新闻组文本数据集,并且我没有GPU,所以时间可能有所不同,但结果指向同一个方向。

  • 注意 2:我正在使用:

    • spacy 3.5.4
    • en_core_web_lg 3.5.0
    • en_core_web_trf 3.5.0
    • scikit-learn 1.3.0
    • Python 3.11.4。
"""Replicating code as much as possible."""

import timeit

from sklearn.datasets import fetch_20newsgroups
import spacy  # 3.5.4


# spacy.require_gpu()  # I don't have a GPU available
bunch = fetch_20newsgroups(random_state=0)
texts = bunch.data

def get_execution_time(nlp, texts, N):
    return timeit.timeit(
        stmt="[nlp(text) for text in texts]",
        globals={'nlp': nlp, 'texts': texts},
        number=N
    ) / N

#  load models
nlp_lg_pos = spacy.load('en_core_web_lg', disable=['ner', 'parser'])
nlp_lg_all = spacy.load('en_core_web_lg')
nlp_trf_pos = spacy.load('en_core_web_trf', disable=['ner', 'parser'])
nlp_trf_all = spacy.load('en_core_web_trf')

#  get execution time
print(f'nlp_lg_pos = {get_execution_time(nlp_lg_pos, texts, N=1)}')
print(f'nlp_lg_all = {get_execution_time(nlp_lg_all, texts, N=1)}')
print(f'nlp_trf_pos = {get_execution_time(nlp_trf_pos, texts, N=1)}')
print(f'nlp_trf_all = {get_execution_time(nlp_trf_all, texts, N=1)}')
模型名称 无 NER 或 Parser 的时间 有 NER 和 Parser 的时间 备注
en_core_web_lg 8.48 秒 13.98 秒 NER 和 Parser 增加了原始时间的 65%
en_core_web_trf 387.67 秒 382.84 秒 NER 和 Parser 减少了 1% 的时间(可以忽略不计)

修改现有组件并使其侦听共享的tok2vectransformer层十分困难,而无需重新训练。因此,我将替换en_core_web_trfnerparser组件监听器,并使用它们自己的转换器层副本。如果文档正确,这应导致“具有(独立)NER和(独立)解析器的时间”结果比先前的任何一个en_core_web_trf结果慢得多

nlp_trf_all_independent = spacy.load('en_core_web_trf')

# make `ner` and `parser` components independent
nlp_trf_all_independent.replace_listeners("transformer", "ner", ["model.tok2vec"])
nlp_trf_all_independent.replace_listeners("transformer", "parser", ["model.tok2vec"])

print(f'nlp_trf_all_independent = {get_execution_time(nlp_trf_all_independent, texts, N=1)}')
模型名称 无 NER 或 Parser 的时间 带有(独立)NER 和(独立)Parser 的时间 备注
en_core_web_trf 387.67 秒 1125.31 秒 (独立)NER 和(独立)Parser 增加了原始时间的 190%

正如您所见,使组件独立,即不共享/监听 tok2vec/transformer 层,会导致更慢(但更模块化)的流程。我相信这就是为什么当您添加 ner 组件时,en_core_web_lg 模型明显变慢的原因,因为它默认是独立的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接