Всем добрый день! Предлагаю рассмотреть архитектуру новой модели W2NER для решения задачи распознавания сущностей в текстах и обучить её работе с русским языком.

Задача распознавания сущностей (NER) постоянно возникает при машинной обработке документов, продолжается улучшение показателей качества и скорости работы алгоритмов для решения данной задачи. Я предлагаю рассмотреть модель W2NER – это классификатор попарных отношений слов в предложении. Затем я обучу модель на русскоязычном датасете и оценю качество её работы. Данные взяты из научной публикации: Unified Named Entity Recognition as Word-Word Relation Classification авторов Jingye Li и др.

Для начала рассмотрим виды именованных сущностей в разрезе их структуры (не имеем их достоверного перевода и приводим английские названия):

  1. Flat (Здесь находился мой любимый Макдональдс).

  2. Discontinuous (Автор — Исаак Антонович (наверняка Вам известный) Паульсен).

  3. Nested (Известнейшая фраза из романа Аркадия и Бориса Стругацких).

Наиболее популярные подходы, используемые для задачи нахождения именованных сущностей, основаны на sequence-to-sequence архитектуре или нахождении границ (span-based) и имеют свои недостатки, в частности, проблемы при нахождении более сложных по структуре именованных сущностей (discontinuous и nested).

В W2NER используется новый подход, основанный на построении двухмерной матрицы отношений слов между собой в рассматриваемом предложении (рис. 1).

Рис. 1: Пример двумерной матрицы отношений слов в предложении: I am having aching in legs and shoulders
Рис. 1: Пример двумерной матрицы отношений слов в предложении: I am having aching in legs and shoulders

На рисунке 1 заметим, что в некоторых ячейках, соответствующих пересечению строки и столбца, стоит аббревиатура для обозначения отношения между этими словами (NNW, THW-S).

Теперь подробнее об отношениях, предлагаемых в статье:

  • NONE: данная пара слов не является частью именованной сущности.

  • Next Neighbouring Word (NNW): обозначает что данное слово принадлежит некоторой именованной сущности и слово из соответствующей колонки является в этой именованной сущности следующим. Например: aching → in на Рис.1.

  • Tail-Head-Word-* (THW): означает, что данное слово является последним в некоторой именованной сущности и слово в соответствующей колонке это первый элемент этой именованной сущности данного типа (Location, Person, Organisation и т. д.). Например: Legs → THW-S → aching, здесь S от Symptom.

Модель использует предобученную BERT и двухстороннюю LSTM для получения представления входного предложения в виде тензора. Далее собственная свёрточная сеть преобразует этот тензор в двумерное представление попарных отношений слов в предложении.

Затем происходит классификация полученных результатов и извлечение предсказанных именованных сущностей из матрицы отношений. Доступен репозиторий с кодом модели W2NER и скриптом для её обучения.

Представленная модель была обучена на 14 различных датасетах английского и китайского языка. Я обучу её на русскоязычном датасете nerus, собранном из текстов новостей Lenta.ru, предобработанных моделью Razdel и размеченных Slovnet.

В приведённом датасете выделено три категории именованных сущностей:

LOC — для географических обозначений, PER — имена людей, ORG — названия организаций.

Для обозначения именованных сущностей в датасете используется IOB2 формат, где начало каждого NER объекта отмечается с префикса «B-»,  последующие элементы «I-» и не входящие в NER элементы отмечены «0» (рис. 2).

Рис. 2: пример разметки именованных сущностей по стандарту
Рис. 2: пример разметки именованных сущностей по стандарту

Nerus содержит более 2 гигабайт размеченных предложений и в целях ограничения времени обучения я не буду использовать все доступные данные, а только случайные 30 000 предложений.

Приведём данные в необходимый для обучения JSON-формат:

{‘sentence’: [лист токенов предложения], 
‘ner’: [{
‘index’: [индекс именованной сущности], 
‘type’: наименование именованной сущности}]}.

Код доступен по ссылке.

Затем разобьём выбранные предложения с именованными сущностями на тренировочный/валидационный/тестовый сеты в отношении 8/1/1.

Обучение производил на локальной машине (i7-8700K, 32mb CPU, GTX 1080) и оно заняло около 6 часов. Полученные метрики качества (рис.3, F1: 0.9019, precision: 0.8905, recall: 0.9138) согласуются с результатами на других датасетах и при этом могут быть легко улучшены расширением обучающей выборки. Учитывая скромные технические мощности и небольшой размер тренировочных данных, на мой взгляд, это очень хороший результат.

Рис.3: результаты обучения
Рис.3: результаты обучения

После обучения модель будет сохранена в файл model.pt в папке проекта.

Рассмотрим входное предложение: Жители Брянска устроили давку из-за дешевых продуктов на открытии магазина, сообщает интернет-газета «Брянские новости».

Данное предложение содержит 18 токенов (включая кавычки и точку) и две именованных сущности: Брянска (LOC, позиция 1) и Брянские новости (ORG, позиции 14, 15). Загрузим модель и получим результаты для этого предложения:

import torch as pt
model = pt.load('Документы/W2NER-main/model.pt')
# загрузим предложение в json-формате
with open("test.json", 'r', encoding='utf-8') as f:
    test_data = json.load(f)
# проведём токенизацию и разметку предложения
test_loader = data_loader.RelationDataset(*data_loader.process_bert
([test_data[0]], tokenizer, vocab))
# первод модели в режим инференса (без изменения собственных весов)
model.eval()
with torch.no_grad():
    for i, data_batch in enumerate(test_loader):
        entity_text = data_batch[-1]
        length = data_batch[-2]	
        data_batch = [data.cuda() for data in data_batch[:-1]]
# отправляем токенизированное предложение в модель
        outputs = model(*data_batch)
        outputs = torch.argmax(outputs, -1)
# получим разметку токенов предложения
result = decode(outputs.cpu().numpy(), entity_text, length.cpu().numpy())

Вывод нашей модели будет выглядеть так: {'1-#-2', '14-15-#-3'}. Здесь первые числа перед решеткой — это позиции именованной сущности, а число после — его код.

Посмотрим на словарь кодов именованных сущностей:

>> vocab.id2label
{0: '<pad>', 1: '<suc>', 2: 'loc', 3: 'org', 4: 'per'}

Соответственно токен 1 – это географический объект, а токены 14 и 15 — название организации.

Рассмотренная модель может быть легко дообучена на сравнительно небольшом корпусе текстов для различных задач не только нахождения имён людей и организаций, но также, например, в научных текстах по химии для нахождения названий соединений или в биологии для поиска упоминаний различных белков.

Каждый день публикуется несколько новых научных статей в области машинного обучения, многие с уже готовой реализацией в коде. Не забывайте знакомиться с публикациями и сможете найти как множество инструментов, так и просто свежих идей и подходов для решения своих задач. Одним из замечательных сайтов для слежения за научными публикациями со всего мира могу порекомендовать paperswithcode.com.

Спасибо за внимание. 

Комментарии (0)