【问题标题】:How to mock spacy models / Doc objects for unit tests?如何模拟空间模型/文档对象以进行单元测试?
【发布时间】:2019-06-23 22:43:20
【问题描述】:

加载 spacy 模型会减慢我的单元测试的运行速度。有没有办法模拟 spacy 模型或 Doc 对象来加速单元测试?

当前慢速测试示例

import spacy
nlp = spacy.load("en_core_web_sm")

def test_entities():
    text = u"Google is a company."
    doc = nlp(text)
    assert doc.ents[0].text == u"Google"

根据文档,我的方法是

手动构建 Vocab 和 Doc 并将实体设置为元组。

from spacy.vocab import Vocab
from spacy.tokens import Doc

def test()
    alphanum_words = u"Google Facebook are companies".split(" ")
    labels = [u"ORG"]
    words = alphanum_words + [u"."]
    spaces = len(words) * [True]
    spaces[-1] = False
    spaces[-2] = False
    vocab = Vocab(strings=(alphanum_words + labels))
    doc = Doc(vocab, words=words, spaces=spaces)

    def get_hash(text):
        return vocab.strings[text]

    entity_tuples = tuple([(get_hash(labels[0]), 0, 1)])
    doc.ents = entity_tuples
    assert doc.ents[0].text == u"Google"

是否有更简洁的 Pythonic 解决方案来模拟 spacy 对象以进行实体的单元测试?

【问题讨论】:

    标签: unit-testing spacy


    【解决方案1】:

    其实这是一个很好的问题!我想说你的直觉是绝对正确的:如果你只需要一个处于给定状态并带有给定注释的 Doc 对象,请始终尽可能手动创建它。除非您明确测试统计模型,否则请避免在单元测试中加载它。它使测试变慢,并且引入了太多不必要的差异。这也非常符合单元测试的理念:您希望为一次一件事编写独立测试(不是一件事加上一堆第三方库代码加上统计型号)。

    一些一般提示和想法:

    • 如果可能,请始终手动构造Doc。避免加载模型或Language 子类。
    • 除非您的应用程序或测试特别需要doc.text,否则您不必必须设置spaces。事实上,我在编写的大约 80% 的测试中都忽略了这一点,因为它只有在你将令牌重新组合在一起时才真正变得相关。
    • 如果您需要在您的测试套件中创建大量Doc 对象,您可以考虑使用一个实用函数,类似于我们在 spaCy 测试套件中使用的get_doc helper。 (该功能还会向您展示如何手动设置各个注释,以备不时之需。)
    • 为共享对象使用(会话范围的)固定装置,例如Vocab。根据您要测试的内容,您可能希望明确使用English 词汇。在 spaCy 测试套件中,我们通过在 conftest.py 中设置一个 en_vocab fixture 来做到这一点。
    • 除了将doc.ents 设置为元组列表之外,您还可以将其设置为Span 对象列表。这看起来更直接,更易于阅读,在 spaCy v2.1+ 中,您还可以将字符串作为标签传递:
    def test_entities(en_vocab):
        doc = Doc(en_vocab, words=["Hello", "world"])
        doc.ents = [Span(doc, 0, 1, label="ORG")]
        assert doc.ents[0].text == "Hello"
    
    • 如果您确实需要测试模型(例如,在确保您的自定义模型按预期加载和运行的测试套件中)或像 English 这样的语言类,请将它们放在会话范围的夹具中。这意味着它们只会在每个会话中加载一次,而不是在每个测试中加载一次。语言类是延迟加载的,也可能需要一些时间来加载,具体取决于它们包含的数据。所以你只想这样做一次。
    # Note: You probably don't have to do any of this, unless you're testing your
    # own custom models or language classes.
    
    @pytest.fixture(scope="session")
    def en_core_web_sm():
        return spacy.load("en_core_web_sm")
    
    @pytest.fixture(scope="session")
    def en_lang_class():
        lang_cls = spacy.util.get_lang_class("en")
        return lang_cls()
    
    def test(en_lang_class):
        doc = en_lang_class("Hello world")
    

    【讨论】:

      猜你喜欢
      • 2011-10-16
      • 2019-08-22
      • 2015-08-30
      • 2016-12-30
      • 2013-02-07
      • 1970-01-01
      • 2013-11-18
      • 2019-01-22
      • 2014-04-09
      相关资源
      最近更新 更多