Оценка уверенности Spacy 3 в признании именных организаций
Мне нужно получить оценку достоверности тегов, предсказанных моделью de_core_news_lg NER. В Spacy 2 было хорошо известное решение проблемы:
nlp = spacy.load('de_core_news_lg')
doc = nlp('ich möchte mit frau Mustermann in der Musterbank sprechen')
text = content
doc = nlp.make_doc(text)
beams = nlp.entity.beam_parse([doc], beam_width=16, beam_density=0.0001)
for score, ents in nlp.entity.moves.get_beam_parses(beams[0]):
print (score, ents)
entity_scores = defaultdict(float)
for start, end, label in ents:
# print ("here")
entity_scores[(start, end, label)] += score
print ('entity_scores', entity_scores)
Однако в Spacy 3 я получаю следующую ошибку:
AttributeError: 'German' object has no attribute 'entity'
Очевидно
language
объект не имеет
entity
атрибут больше. Кто-нибудь знает, как получить оценки уверенности в Spacy 3?
2 ответа
Суть ответа - «используйте компонент конвейера"beam_ner"и посмотрите на код EntityRecognizer.pyx. Затем есть модульный тест test_ner.py test_beam_ner_scores(), который в значительной степени показывает, как это сделать. Если вы хотите увидеть, как изменить вашу конфигурацию, cfg, сохраните модель (как это сделано в make_nlp() ниже) и посмотрите сохраненную модель config.cfg.
ПРОБЛЕМА в том, что он работает только для «модели», созданной модульным тестом. Это с треском проваливается для моих реальных моделей (5000 документов ~4k текста каждая, обучение NER f-score около 75%). Под «ужасно» я подразумеваю «жадный» поиск, который находит мои объекты, но «лучевой поиск» сообщает о сотнях токенов (даже пунктуации) с такими «баллами», как 0,013. И (на основе смещений) они обычно берутся из небольшого раздела документа.
Это расстраивает, потому что я считаю, что просторный поезд (для 'beam_ner') использует тот же код для 'проверки' итераций обучения, а результаты обучения почти приличные (ну, на 10% ниже Spacy 2, но это происходит с ботом для обучения с 'ner' и 'beam_ner').
Поэтому я публикую это в надежде, что кому-то повезет больше, ИЛИ он сможет указать, ЧТО я делаю не так.
До сих пор Spacy3 был для меня серьезной катастрофой: я не могу получить уверенность, больше не могу использовать графический процессор (у меня только 6 ГБ), распараллеливание на основе Ray не работает (в Windows = экспериментально) и с использованием модели на основе трансформатора NER моих тренировок на 10% хуже, чем в Spacy 2.
Код
import spacy
from spacy.lang.en import English
from spacy.language import Language
from spacy.tokens import Doc
from spacy.training import Example
# Based upon test_ner.py test_beam_ner_scores()
TRAIN_DATA = [
("Who is Shaka Khan?", {"entities": [(7, 17, "PERSON")]}),
("I like London and Berlin.", {"entities": [(7, 13, "LOC"), (18, 24, "LOC")]}),
("You like Paris and Prague.", {"entities": [(9, 14, "LOC"), (19, 25, "LOC")]}),
]
def make_nlp(model_dir):
# ORIGINALLY: Test that we can get confidence values out of the beam_ner pipe
nlp = English()
config = { "beam_width": 32, "beam_density": 0.001 }
ner = nlp.add_pipe("beam_ner", config=config)
train_examples = []
for text, annotations in TRAIN_DATA:
train_examples.append(Example.from_dict(nlp.make_doc(text), annotations))
for ent in annotations.get("entities"):
ner.add_label(ent[2])
optimizer = nlp.initialize()
# update once
losses = {}
nlp.update(train_examples, sgd=optimizer, losses=losses)
# save
#if not model_dir.exists():
#model_dir.mkdir()
nlp.to_disk(model_dir)
print("Saved model to", model_dir)
return nlp
def test_greedy(nlp, text):
# Report predicted entities using the default 'greedy' search (no confidences)
doc = nlp(text)
print("GREEDY search");
for ent in doc.ents:
print("Greedy offset=", ent.start_char, "-", ent.end_char, ent.label_, "text=", ent.text)
def test_beam(nlp, text):
# Report predicted entities using the beam search (beam_width 16 or higher)
ner = nlp.get_pipe("beam_ner")
# Get the prediction scores from the beam search
doc = nlp.make_doc(text)
docs = [doc]
# beams = StateClass returned from ner.predict(docs)
beams = ner.predict(docs)
print("BEAM search, labels", ner.labels);
# Show individual entities and their scores as reported
scores = ner.scored_ents(beams)[0]
for ent, sco in scores.items():
tok = doc[ent[0]]
lbl = ent[2]
spn = doc[ent[0]: ent[1]]
print('Beam-search', ent[0], ent[1], 'offset=', tok.idx, lbl, 'score=', sco,
'text=', spn.text.replace('\n', ' '))
MODEL_DIR = "./test_model"
TEST_TEXT = "I like London and Paris."
if __name__ == "__main__":
# You may have to repeat make_nlp() several times to produce a semi-decent 'model'
# nlp = make_nlp(MODEL_DIR)
nlp = spacy.load(MODEL_DIR)
test_greedy(nlp, TEST_TEXT)
test_beam (nlp, TEST_TEXT)
Результат должен выглядеть так (после повторения make_nlp для создания пригодной для использования «модели»):
GREEDY search
Greedy offset= 7 - 13 LOC text= London
Greedy offset= 18 - 23 LOC text= Paris
BEAM search, labels ('LOC', 'PERSON')
Beam-search 2 3 offset= 7 LOC score= 0.5315668466265199 text= London
Beam-search 4 5 offset= 18 LOC score= 0.7206478212662492 text= Paris
Beam-search 0 1 offset= 0 LOC score= 0.4679245513356703 text= I
Beam-search 3 4 offset= 14 LOC score= 0.4670399792743775 text= and
Beam-search 5 6 offset= 23 LOC score= 0.2799470367073933 text= .
Beam-search 1 2 offset= 2 LOC score= 0.21658368070744227 text= like
В настоящее время нет хорошего способа получить уверенность в оценках NER в spaCy v3. Однако в разработке находится компонент SpanCategorizer, который упростит это. Точно не известно, но мы надеемся выпустить его в следующей минорной версии. Вы можете следить за развитием этой функции в PR или читать об этом подробнее здесь.