首页 > 解决方案 > 在 spaCy 管道中对自定义组件进行基准测试的最佳方法是什么?

问题描述

我最近重构了 spaCy 管道中的一些组件,因此,管道运行速度比重构之前慢了 7 倍。我不确定我的 spaCy 管道中的哪个组件是减速的罪魁祸首,并且无法弄清楚如何在文本流经每个组件所需的时间方面获得一些透明度。如果我知道是哪个组件导致了速度变慢,那么识别有问题的代码会简单得多。

我曾考虑为每个 Doc 对象添加自定义扩展,并让每个管道组件添加处理所需的时间,但这似乎有问题。

是否有任何 spaCy 推荐的方法可以做到这一点,或者有其他人以聪明的方式解决了这个问题吗?

标签: pythonspacy

解决方案


这是一个很好的问题,扩展属性的想法其实很聪明!唯一的缺点是您必须将调试代码添加到所有现有组件中(如果它们是第三方代码,它们的效果也会较差)。但是,如果您知道有问题的代码是您的代码库的一部分,那么这应该不是问题。

另一种选择是将每个管道组件包装在一个函数中,该函数记录时间戳以及您需要并返回的任何其他内容pipe(doc)。然后,您可以nlp.pipeline用这些包装的组件覆盖:

def wrap_pipe(name, pipe):
    def wrapped(doc):
        print(f"Started '{name}'", datetime.datetime.now())
        return pipe(doc)
    return wrapped

def debug_wrap_pipeline(nlp):
    nlp.pipeline = [(name, wrap_pipe(name, pipe)) for name, pipe in nlp.pipeline]
    return nlp

debug_nlp = debug_wrap_pipeline(nlp)

但是,这里的缺点是您还需要包装每个组件的.pipe方法(如果可用),以便您可以nlp.pipe在相同的条件下运行和调试。如果您要进行基准测试,您通常希望在更大范围内执行此操作并使用nlp.pipe.

为了避免这种情况,一个稍微冗长的选项可能是在管道中的每个现有组件之前添加一个“调试组件”。基本上,是这样的:

def make_debug_component(name):
    def debug_component(doc):
        print(f"Before '{name}'", datetime.datetime.now())
        return doc
    return debug_component

def debug_wrap_pipeline(nlp):
    pipeline = list(nlp.pipeline)  # we don't want to modify this while we're looping over it
    for name, pipe in pipeline:
        debug_component = make_debug_component(name)
        nlp.add_pipe(debug_component, before=name, name=f"debug_{name}")
    return nlp

免责声明:我只是将这些想法整合在一起,还没有对它们进行广泛的测试。但它们似乎确实有效。如果你最终探索这个,我会很想知道什么最有效。它也可能是 spaCy 可以开箱即用的一个特性,它可以很好地与建议的管道组件静态分析配对。

另外,为了完整性:在调试这样的文本处理管道时,始终使用您处理一次的单个语料库进行更大规模的基准测试(而不是循环单个示例 1000 次或类似的东西)。缓存效果(在 spaCy 中,还有 CPU 中)、内存分配的差异等都会产生影响,并使小规模测试的可靠性降低。当然,在这种情况下,您会遇到巨大的差异,即使处理单个文本也可能会为您提供足够的线索以及进一步调试代码所需的一切。


推荐阅读