Загрузка пространственных моделей замедляет выполнение моих модульных тестов. Есть ли способ имитировать пространственные модели или объекты 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 для имитации пространственных объектов для модульных тестов для сущностей?
На самом деле это отличный вопрос! Я бы сказал, что ваш инстинкт определенно прав: если все, что вам нужно, это объект Doc
в заданном состоянии и с заданными аннотациями, всегда создавайте его вручную, где это возможно. И если вы не тестируете статистическую модель явно, не загружайте ее в свои модульные тесты. Это делает тесты медленными и вносит слишком много ненужной дисперсии. Это также очень соответствует философии модульного тестирования: вы хотите писать независимые тесты для одна вещь за раз (а не что-то одно плюс куча кода сторонних библиотек плюс статистическая модель).
Несколько общих советов и идей:
Doc
вручную. Избегайте загрузки моделей или Language
подклассов.doc.text
, вы не устанавливаете придетсяspaces
. Фактически, я не учитываю это примерно в 80% тестов, которые я пишу, потому что это действительно становится актуальным только тогда, когда вы снова собираете токены.Doc
в своем наборе тестов, вы можете рассмотреть возможность использования служебной функции, подобной get_doc
помощник, которую мы используем в наборе тестов spaCy. (Эта функция также показывает вам, как отдельные аннотации устанавливаются вручную, если вам это нужно.)Vocab
. В зависимости от того, что вы тестируете, вы можете явно использовать словарь English
. В наборе тестов spaCy мы делаем это, настроив en_vocab
приспособление в файле conftest.py
.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")