Программирование

Как сделать нечеткое сопоставление строк в Rasa

Учебник о том, как интегрировать библиотеку fuzzywuzzy в конвейер Rasa NLU

Введение

В этой статье я расскажу, как создать пользовательский компонент в rasa, чтобы сделать извлечение сущностей более устойчивым к опечаткам. В частности, мы будем использовать библиотеку fuzzywuzzy, чтобы выполнить нечеткое сопоставление строк для автокоррекции объекта на основе его оценки сходства.

Код для воспроизведения бота, описанного в этой статье, можно найти здесь.

Постановка задачи

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

Таким образом, фраза типа «Я из Соединенных Штатов» будет обрабатываться конвейером NLU как:

Однако, если пользователь сделал опечатку, например. «Я из Соединенных Штатов Америки», результаты такие:

Мы видим, что этому классификатору DIET удается распознать united states of amercia как объект страны, но, поскольку в предоставленном списке синонимов нет точного соответствия, он не получил сопоставление с usa, в отличие от высказывания на рисунке 2. Это действительно раздражает, потому что это обычная опечатка и невозможность привести ее к какой-либо канонической форме будут мешать последующим задачам, которые полагаются на извлечение правильного объекта страны.

Одно из возможных решений — включить в список синонимов все возможные опечатки (или хотя бы распространенные). Это не идеально, потому что список будет не только излишне длинным и сложным в обслуживании, но и нам придется предвидеть возможные ошибки, которые могут совершить наши пользователи!

Лучшим решением является создание пользовательского компонента, который просматривает извлеченные сущности и нечетко сопоставляет их со списком известных сущностей. Если сходство между извлеченным объектом и элементом в этом списке превышает определенный порог, мы делаем вывод, что, вероятно, в извлеченном объекте есть опечатка, и автоматически исправляем его на этот элемент. В следующем разделе будет описано, как построить это решение.

Решение: создание пользовательского компонента

Шаг 1. Определитесь с полным именем класса пользовательского компонента.

Мы реализуем наш пользовательский компонент в классе с именем EntityTypoFixer в файле с именем my_custom_components.py, который сохраняется в папке с именем addons относительно корневого каталога проекта.

Поэтому, если вы запустите python в корневом каталоге проекта, полное имя класса компонента будет addons.my_custom_components.EntityTypoFixer.

Шаг 2: Реализуйте параметры для пользовательского компонента

Было бы удобно, чтобы пороговая оценка была параметром пользовательского компонента, чтобы мы могли сравнивать эффекты разных порогов с rasa test . Мы назовем этот параметр score_cutoff и присвоим ему значение по умолчанию 80.

Первое, что нам нужно сделать, это определить свойство класса с именем defaults, которое будет хранить словарь значений параметров по умолчанию:

Далее мы определяем, как использовать параметр score_cutoff по умолчанию в методе __init__ EntityTypoFixer:

Шаг 3: Определите, что происходит во время обучения

Когда конвейер NLU обучен, мы хотели бы собрать все сущности, перечисленные во всех синонимах, в список, чтобы мы могли искать их во время вывода:

Шаг 4: Определите, что происходит во время логического вывода

Получив сообщение во время вывода, мы извлечем все сущности в список и пройдемся по каждому элементу, чтобы нечетко сопоставить их с сущностями в self.entities :

Фактическое нечеткое сопоставление выполняется при вызове self.fix_entity_typo и определяется следующим образом:

На рисунке 8 показано, что если оценка наилучшего совпадения в self.entities с извлеченным объектом превышает score_cutoff и не равна 100, то значение этого извлеченного объекта обновляется значением наилучшего совпадения, а также добавляется этот компонент в список processors, поэтому что мы знаем, что этот компонент использовался при обработке высказывания.

Шаг 5: Определите, как сохранить и загрузить пользовательский компонент

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

Шаг 6: Добавьте пользовательский компонент в config.yml

Наконец, мы добавляем этот компонент в раздел pipeline раздела config.yml. Поскольку мы хотим, чтобы этот компонент запускался после извлечения сущностей и до того, как они будут сопоставлены с синонимами, его следует поместить между компонентами DIETClassifier и EntitySynonymMapper :

Обратите внимание, что мы использовали полное имя класса компонента, которое мы выяснили на шаге 1.

Результаты

После переобучения модели с новым config.yml результатом высказывания «Я из Соединенных Штатов Америки» будет:

По сравнению с рисунком 3 мы видим, что значение извлеченного объекта теперь равно usa, чего мы и хотели. Мы также видим, что EntityTypoFixer находится в списке processors, что указывает на то, что он был вызван как часть процесса извлечения.

Результат обработки «Я из Соединенных Штатов» неизменен, так как в этом высказывании нет опечатки:

Вывод

В этой статье показано, как выполнить нечеткое сопоставление извлеченных сущностей в rasa с помощью библиотеки fuzzywuzzy. Шаги, описанные в этой статье, можно применять для создания других пользовательских компонентов, выполняющих произвольные задачи предварительной или последующей обработки.

Я надеюсь, что вы нашли это полезным.