Как стать автором
Обновить

Что такое NER, зачем он нужен и когда не поможет

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров1K

Про NER написано немало, но этот материал носит прикладной характер. Статья будет полезна тем, кто интересуется NLP и ищет разные подходы для решения узкопрофильных задач, требующих извлечения сущностей из текста.

Для джунов это возможность пройти весь путь — от разметки данных до обучения собственной кастомной NER-модели, попутно понять типичные сложности и ограничения.

Привет, меня зовут Александр Агеев, на протяжении года я занимался NER-моделями для определения сущностей на этикетках продуктов питания. Несмотря на мою любовь к NER, у этой технологии есть свои границы — кейсы, которые она не может решить хорошо, поэтому надо подключать другие инструменты. В статье я дам критерии применимости NER для решения практических задач.

Краткий экскурс

Named Entity Recognition (NER) — это технология извлечения именованных сущностей из текста: значимых фрагментов вроде имен, организаций, городов, дат, медицинских кодов и т. д.

Пример: «Илон Маск анонсировал запуск Starship в Техасе весной 2025 года».

NER выделит:

  • Илон Маск → персона (PER)

  • Starship → продукт / проект (PRODUCT)

  • Техас → гео (LOC)

  • весна 2025 года → дата (DATA)

NER широко используется в:

  • банках и страховых для выделения названий компаний, ИНН, адресов, сумм, реквизитов;

  • юридических документах для поиска дат, номеров договоров, участников;

  • чат‑ботах и техподдержке для извлечения имен, аккаунтов, заявок, местоположения;

  • медицине — извлекает коды диагнозов, названия препаратов, даты процедур;

  • логистике: выделение адресов, номеров накладных, получателей, грузов.

Звучит просто, но за этим стоит довольно сложная инженерия.

На практике я столкнулся с рядом проблем. Например, название организации может быть связано с географией — ООО «Москва». Также одно словосочетание порой содержит в себе две сущности — эта задача не решаема в рамках spaCy, так как сущности не могут накладываться друг на друга и определяться к двум разным категориям. Нередки случаи слипания слов друг с другом или с предлогами (решается постпроцессингом). И, наконец, данные могут попадать из многошумовых каналов, тогда проблем будет сразу несколько: «Клиент ООО АльфаБизнесСнаб прислал счет из Питера. Не уверен, что юр. лицо корректно, уточнить по ИНН 7 812 345 678» — тут и слитные слова, и пропущенные кавычки, и обрывки сущностей.

На чем основан NER

Исторически NER развивался в несколько этапов:

  1. Правила и регулярные выражения

    • Быстро, дешево, работает только если данные строго формализованы.

    • Подходит исключительно для строго формализованных сущностей: email'ов, номеров телефонов, паспортов.

  2. Классическое машинное обучение

    • Conditional Random Fields, SVM.

    • Требуют ручной инженерии признаков (features), работают лучше, чем регулярки.

  3. Глубокое обучение

    • BiLSTM‑CRF, Transformer‑модели (BERT и пр.)

    • Дает лучшие результаты, особенно при обучении на больших объемах данных.

Следующим этапом решении задач можно назвать применение LLM. Но в реальности из практических соображений обычно применяется золотая середина — что‑то лучше регулярки, но не требующее GPU. Именно здесь и приходит на помощь практичный NER на CPU.

Когда NER — хорошее решение

Использовать NER стоит, если:

  • у вас структурированный или полуформализованный текст (новости, документы, соцсети),

  • требуется извлекать сущности вроде имен людей, компаний, дат, локаций,

  • вы не хотите или не можете использовать глубокие модели,

  • нужно решение, работающее быстро на CPU,

  • нет возможности использовать любую LLM.

Также можно быстро протестировать применимость — разметьте до 100 примеров одного класса, и уже станет понятно, можно ли строить модель или нет.

Когда NER не подходит

NER‑модели, особенно на базе spaCy или других легковесных фреймворков, плохо справляются с сущностями с высокой вариативностью и длинным хвостом, например, названиями товаров, адресами, описаниями или целыми предложениями.

Причина проста — нет ярко выраженных паттернов, нет повторяемости, нет контекста для обобщения. Модель не понимает, что объединяет эти сущности, особенно при маленьком датасете.

В этих случаях целесообразнее использовать классификацию текста, классификацию эмбеддингов, семантический поиск, LLM.

Аннотаторы для NER

Разметка данных — самая трудозатратная часть NER. К счастью, есть удобные инструменты.

Мне больше всего нравится NER Annotator

  • Прост в использовании

  • Позволяет разметить текст вручную, выбрать тип сущности

  • Можно экспортировать данные в JSON / IOB

Важные нюансы:

  1. Можно выбрать разделители, чтобы исходный текст был разбросан на задания.

  2. Слова выделяются целиком, то есть если у нас будет два слипшихся слова, то их нельзя будет разделить. Обязательно проверяйте пробелы, поэтому так важна предобработка исходника.

  3. Работать командой неудобно — нельзя сохранить прогресс и выйти.

Пример разметки в NER Annotator
Пример разметки в NER Annotator

Еще несколько хороших аннотаторов:

  • Label Studio — open‑source аннотация

  • Prodigy — коммерческий, но очень быстрый

  • doccano — легкий веб‑аннотатор

Проблемы spaCy в контексте NER

spaCy популярен благодаря простоте и скорости — удобная вещь из коробки, запустить можно демо за 30 минут.

Дока по установке https://spacy.io/usage

Генерация конфига под GPU/CPU https://spacy.io/usage/training

Внимательно проверьте пути, подстройте под свои!

spaCy имеет ограничения:

  • Нет оценки вероятности. Нельзя узнать, насколько модель уверена в том, что фраза — это, например, организация. В коробке метрики отсутствуют, следовательно, сложно строить аналитику качества. Если вы хотите понимать, где модель ошибается, и на каких типах данных — потребуются внешние метрики.

  • Проблемы с кастомными сущностями, особенно если сущность длинная или переменная по структуре.

Аналоги spaCy

https://medium.com/ubiai‑nlp/mastering‑named‑entity‑recognition‑with‑bert‑ca8d04b67b18 — BERT

https://colab.research.google.com/github/NielsRogge/Transformers‑Tutorials/blob/master/BERT/Custom_Named_Entity_Recognition_with_BERT_only_first_wordpiece.ipynb — BERT

https://github.com/flairNLP/flair — FLAIR

https://stanfordnlp.github.io/CoreNLP/ner.html — StanfordCoreNLP

Давайте обучим свою первую NER-модель

Обучение модели NER из spaCy

Eстановим все необходимые либы:

!pip install -U pip setuptools wheel
!pip install -U 'spacy[cuda11x,transformers,lookups]'
!python3 -m spacy download ru_core_news_lg


import spacy
from spacy.tokens import DocBin
from tqdm import tqdm
import json



cv_data = json.load(open('path to your json','r'))

Если не создан базовый конфиг - создаем (но у меня он уже есть, поэтому этот пункт пропускаем):

!python3 -m spacy init fill-config /home/alex/ner/base_config.cfg /home/alex/ner/config.cfg

Функция, которая обрабатывает аннотации в формат библиотеки spaCy:

# Define a function to create spaCy DocBin objects from the annotated data
def get_spacy_doc(file, data):
  # Create a blank spaCy pipeline
  nlp = spacy.blank('ru')
  db = DocBin()

  # Iterate through the data
  for text, annot in tqdm(data):
    doc = nlp.make_doc(text)
    annot = annot['entities']
    print(annot)
    ents = []
    entity_indices = []

    # Extract entities from the annotations
    for start, end, label in annot:
      skip_entity = False
      for idx in range(start, end):
        if idx in entity_indices:
          skip_entity = True
          break
      if skip_entity:
        continue

      entity_indices = entity_indices + list(range(start, end))
      try:
        span = doc.char_span(start, end, label=label, alignment_mode='strict')
      except:
        continue

      if span is None:
        # Log errors for annotations that couldn't be processed
        err_data = str([start, end]) + "    " + str(text) + "\n"
        file.write(err_data)
      else:
        ents.append(span)

    try:
      doc.ents = ents
      db.add(doc)
    except:
      pass

  return db

Делим датасет на треин и тест 80/20:

from sklearn.model_selection import train_test_split
train, test = train_test_split(cv_data, test_size=0.2)

Избавляемся от пустых строк:

train = [x for x in train if x is not None]
test = [x for x in test if x is not None]
file = open('/home/alex/ner/train_file.txt','w')

Cоздаем spaCy DocBin объект для тренировочного и тестового датасета:

db = get_spacy_doc(file, train)
db.to_disk('/home/alex/ner/trained_models/train_data.spacy')

db = get_spacy_doc(file, test)
db.to_disk('/home/Ageev/ner/trained_models/test_data.spacy')

# Close the error log file
file.close()

Обучение модели подтягивает конфиг, указываем место для обученной модели, а также берем тренировочный и валидационный экземпляры, созданные ранее:

!python3 -m spacy train /home/Ageev/ner/config.cfg  --output /home/Ageev/ner/trained_models/dir  --paths.train /home/Ageev/ner/trained_models/train_data.spacy  --paths.dev /home/Ageev/ner/trained_models/test_data.spacy --gpu-id 0

Что дальше?

Оцените качество на тестовом наборе, при необходимости — добавьте данные и улучшите разметку. При обучении должны получить примерно такую табличку с метриками:

В случае ошибок — дебаггер:

!python3 -m spacy debug data /home/alex/ner/config.cfg --paths.train /home/Ageev/ner/trained_models/train_data.spacy  --paths.dev /home/Ageev/ner/trained_models/test_data.spacy

Проверка модели:

text =”тут ВАШ текст для проверки ВАШЕЙ модели”



import spacy

# Load the trained spaCy NER model from the specified path
nlp = spacy.load('/home/alex/ner/model-last') 
#
# /home/Ageev/ner/trained_models/15000epochs/model-last
doc = nlp(text)

# Iterate through the named entities (entities) recognized by the model
for ent in doc.ents:
  # Print the recognized text and its corresponding label
  print(ent.text, "  ->>>>  ", ent.label_)

Постобработка

Постобработка под каждую задачу будет своя. Важно понимать бизнес-цель, глобальные метрики и где применяется модель. Постобработка может быть следующей:

  1. Очистка мусора (лишние символы, цифры и тд).

  2. Правильная обрезка границ сущности.

  3. Выправление слов до начальных форм (через тот же GPT или LLM).

  4. Нормализация (например, приведение к строчным буквам).

  5. Фильтрация по длине.

  6. Удаление дубликатов.


Спасибо всем, кто дочитал до конца. Приглашаю всех начинающих специалистов, интересующихся AI и ML, в мой телеграм-канал.

Теги:
Хабы:
+5
Комментарии1

Публикации

Работа

Data Scientist
70 вакансий

Ближайшие события