TL; DR: Мы создали специальный Rasa Featurizer, который добавляет Универсальное кодирование предложений, улучшая производительность классификации намерений, преодолевая ограничения, присущие моделям набора слов. Смотрите код в this Gist.

При создании чат-ботов первым шагом обычно является создание классификатора намерений, чтобы помещать произвольные пользовательские сообщения (Можете ли вы зарезервировать мне столик в ресторане?) в предварительную -определенное намерение (request_restaurant_reservation). Обычно это модели набора слов (BoW), потому что они требуют небольшого количества обучающих данных и являются удивительно эффективной базой.

Модели мешков со словами только дошли до нас

Модели мешка слов по существу суммируют представления слов для слов в сообщении, чтобы вычислить представление сообщения. Неотъемлемым ограничением этого подхода является то, что модель не имеет представления об исходном порядке слов.

Например, рассмотрим следующие сообщения:

  • Я хочу пиццу, а не суши.
  • Я хочу суши, а не пиццу.

Поскольку оба сообщения содержат одни и те же слова, их набор слов будет одинаковым, и у классификатора не будет возможности различить их.

Итак, неужели это наш единственный вариант - использовать более сложный классификатор и накормить его тысячами обучающих примеров?

Универсальные кодировщики предложений спешат на помощь

Нет. Гораздо более простым решением было бы использовать предварительно обученный универсальный кодировщик предложений (USE) для сопоставления входного предложения с векторным представлением, которое фиксирует смысл предложения. Учитывая такой вектор, мы можем передать его в качестве входных данных классификатору намерений в дополнение к представлению «мешок слов».

Например, Google выпустил предварительно обученный Универсальный кодировщик предложений как Модуль TensorFlow Hub, готовый для использования. Посмотрите этот рисунок из статьи, иллюстрирующий, как сходство результирующих векторов предложений коррелирует с семантическим значением пары предложений:

Добавление функции кодирования предложений

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

pipeline:
  - name: "intent_featurizer_count_vectors"
  - name: "intent_classifier_tensorflow_embedding"

На первом этапе конвейера строится вектор счетчика BoW (содержащий количество вхождений каждого слова в словаре). На языке раса это называется featurizer. Второй шаг вызывает классификатор встраивания Rasa. Он умножает вектор счета на выученную матрицу, что математически эквивалентно изучению векторов слов с нуля и их сложению. См. Это сообщение в блоге для описания встраиваемого классификатора.

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

В результате вектор, представляющий сообщение, состоит из двух частей:

  1. Представление «Мешок слов» с использованием векторов слов, изученных с нуля.
  2. Универсальное кодирование предложений, проецируемое в то же векторное пространство с использованием изученной матрицы проекций.

Обе части эффективно вычисляются независимо и суммируются для получения комбинированного представления сообщения. По сравнению с использованием только классификатора векторных подсчетов, нам нужно только изучить дополнительную матрицу проекции (параметры d x dUSE).

Реализация настраиваемого Featurizer

Мы можем добавлять пользовательские компоненты в конфигурацию Rasa NLU, обращаясь к ним через их имя пакета:

pipeline:
  - name: "intent_featurizer_count_vectors"
  - name: "my_package.UniversalSentenceEncoderFeaturizer"
  - name: "intent_classifier_tensorflow_embedding"

Все, что осталось сделать, это реализовать Featurizer, который вызывает универсальный кодировщик предложений и добавляет свой вывод в text_features сообщения. Для этого используется всего около 50 строк кода с использованием существующего модуля TensorFlow Hub. Ознакомьтесь с this Gist для полной реализации.

Пока что мы опробовали этот подход в одном проекте. Без какой-либо настройки гиперпараметров мы увидели уверенное улучшение показателя F1 на 3 процентных пункта. Даже при использовании кодировки предложения в качестве входных функций only сохранялась такая же производительность, как и при простом использовании функции count vector featurizer (при значительном сокращении количества параметров модели).

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

Мы считаем, что добавление предварительно обученных кодировщиков предложений в качестве функций в конвейер NLU - отличный способ расширить возможности классификатора намерений, сохраняя при этом низкие требования к данным. Дайте нам знать, если вы сами попробуете такой подход в своем проекте, и расскажите, как все прошло!