Быстрое встраивание предложений (fse) позволяет вычислить вложения предложений для миллионов отзывов всего за несколько минут.

Код fse в этой статье может быть объявлен устаревшим. Обязательно используйте обновленный код, как указано на Github.

Вступление

Во время учебы в аспирантуре я регулярно работаю с встраиванием предложений. В частности, я работаю со средними [1] и гладкими обратными частотными (SIF) [2] вложениями. Хотя оригинальные реализации на Github весьма полезны, мне всегда было сложно интегрировать их в любой конвейер NLP, который я использую. Это произошло из-за нестандартизированного интерфейса и отсутствия оптимизаций. Таким образом, я решил реализовать вложения Average, SIF и uSIF [3] в оптимизированном пакете, который аккуратно интегрируется в Gensim. Отчасти потому, что мне понравился вызов, отчасти потому, что мне нужны были хорошие инструменты. Этот пакет называется fse и доступен на Github и Pypi. Взгляните на учебник Блокнот, чтобы увидеть, как он работает.

pip install -U fse

Вам понадобятся обычные пакеты Python (›3.6), в частности Numpy, Scipy, Cython и Gensim.
TL; DR: Если вам нужно быстрое встраивание предложений, просто используйте:

from gensim.models import FastText
sentences = [["cat", "say", "meow"], ["dog", "say", "woof"]]
ft = FastText(sentences, min_count=1, size=10)
from fse.models import Average
from fse import IndexedList
model = Average(ft)
model.train(IndexedList(sentences))
model.sv.similarity(0,1)

Этот пост предназначен для аудитории специалистов по науке о данных. Мы собираемся изучить, как можно использовать быстрое встраивание предложений для визуализации хорошо известного набора данных обзора Amazon. В этой истории используются торговые инструменты fse, FIt-SNE и Tableau.

Результат этого конвейера показан на первой картинке этого поста. В конце этого сообщения вы найдете ссылку на интерактивное сопоставление Таблицы для просмотра всех 100 000 продуктов.

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

Данные

Если вы работаете с НЛП, скорее всего, вы слышали из общедоступного набора данных Стэнфордского обзора Amazon. Я получил полную версию от Джулиана Маколи три года назад для моей докторской диссертации по маркетингу и продолжаю работать с ней время от времени. Второй по величине категорией является категория Электроника с 7 824 482 отзывами. Было бы неплохо узнать, что там на самом деле?

Чтобы получить вложения для каждого продукта, нам нужны данные обзора и метаданные. Оба связаны уникальным идентификатором Amazon ASIN. Я уже подготовил все как хороший DataFrame pandas (которым мне не разрешено делиться). Посмотрим на метаданные:

Чтобы фактически визуализировать данные (т.е. представить каждый продукт в виде отображаемого вектора), мы можем использовать только обзоры для каждого продукта. Таким образом, мы справляемся с вложением "многие к одному". После фильтрации ASIN с менее чем 10 отзывами мы получаем 97 249 уникальных ASIN и 6 875 530 отзывов.

Мы не выполняем никакой предварительной обработки текстовых данных.
Почему?
Потому что.

От отзыва до встраивания продукта

Чтобы получить вложение для каждого обзора, нам сначала нужно какое-то предварительно обученное вложение. Вполне вероятно, что отзывы могут содержать много неизвестных слов. К счастью, fse предлагает поддержку моделей FastText из коробки. Сначала загружаем общедоступную модель FastText:

from gensim.models.keyedvectors import FastTextKeyedVectors
ft = FastTextKeyedVectors.load("../models/ft_crawl_300d_2m.model")

Затем мы создаем экземпляр модели SIF из fse.

from fse.models import SIF
model = SIF(ft, components=10, lang_freq="en")

Количество компонентов равно 10, что было указано в разделе Воспроизводимость теста STS.

Обратите внимание на аргумент lang_freq. Некоторые предварительно обученные вложения не содержат информации о частоте слов в корпусе. fse поддерживает индукцию частотности слов для предварительно обученных моделей для нескольких языков, которые необходимы для моделей SIF и uSIF (это может занять некоторое время в зависимости от размера вашего словарного запаса).

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

s = (["Hello", "world"], 0)

fse предоставляет несколько классов ввода, каждый из которых обеспечивает разную функциональность. На выбор предлагается 6 входных классов:

  • IndexedList: для уже предварительно разбитых предложений.
  • C IndexedList: для уже разделенных предложений с индивидуальным индексом для каждого предложения.
  • SplitIndexedList: для предложений, которые не были разделены. Разделит струны.
  • Разделенный C IndexedList: для предложений, которые не были разделены, и с индивидуальным индексом для каждого предложения.
  • C SplitIndexedList: для предложений, которые не были разделены. Разделит струны. Вы можете предоставить настраиваемую функцию разделения.
  • C Разделение C IndexedList: для предложений, в которых вы хотите предоставить настраиваемый индекс и настраиваемую функцию разделения.
  • IndexedLineDocument: для потоковой передачи предложений с диска. Индексируется для облегчения поиска похожих предложений.

Они упорядочены по скорости. Это означает, что IndexedList является самым быстрым, а C Split C IndexedList - самым медленным вариантом (больше вызовов = медленнее). Почему несколько классов? Потому что я хотел, чтобы каждый метод __getitem__ имел как можно меньше строк кода, чтобы не замедлять вычисления.

Для данных наших обзоров мы используем Split C IndexedList, так как мы не хотим предварительно разделять данные (предварительное разделение 7 миллионов обзоров занимает огромное количество оперативной памяти). Внутри класс будет указывать на наши обзоры и выполнять предварительную обработку только при вызове __getitem__.

from fse import SplitCIndexedList
review = ["I really like this product.", "Its nice and comfy."]
s = SplitCIndexedList(review, custom_index = [0, 0])
print(s[0])
print(s[1])
>>> (['I', 'really', 'like', 'this', 'product.'], 0)
>>> (['Its', 'nice', 'and', 'comfy.'], 0)

Обратите внимание, что оба предложения указывают на индекс 0. Следовательно, они оба будут добавлены к встраиванию с индексом 0. Чтобы сопоставить каждый ASIN с индексом, нам нужны только некоторые дополнительные вспомогательные функции.

from fse import SplitCIndexedList
ASIN_TO_IDX = {asin : index for index, asin in enumerate(meta.index)}
indexed_reviews = SplitCIndexedList(data.reviewText.values, custom_index = [ASIN_TO_IDX[asin] for asin in data.asin])

Теперь, когда у нас все готово, мы можем просто позвонить

model.train(indexed_reviews)

Модель обучалась на облачном инстансе с 16 ядрами и 32 ГБ оперативной памяти. Весь процесс занимает около 15 минут, около 8500 отзывов в секунду. Каждый отзыв содержит в среднем 86 слов, а всего мы встречаем 593 774 622 слова. Мы сжали около 7 миллионов обзоров в матрицу размером 100 000 * 300. Добавление дополнительных рабочих процессов не имеет значения, потому что предварительная обработка (разделение) является узким местом.

Если ваши данные уже предварительно разделены, вы можете получить до 500 000 предложений в секунду на обычном MacBook Pro. Загляните в учебник Блокнот, если хотите узнать больше.

Использование и визуализация встраивания

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

model.sv[0]       # Access embedding with index 0
model.sv.vectors  # Access embedding matrix 

Соответствующий класс Sentencevectors (sv) предоставляет довольно много функций для работы с результирующими вложениями предложений. Например, вы можете использовать сходство, расстояние, наиболее_подобное, подобное_по_слову, подобное_по_выпуску или подобное_по_ вектору.

Визуализация такого количества данных может занять очень много времени, если мы вернемся к стандартной реализации sklearn t-SNE. Итак, попробуем более оптимизированный подход: FIt-SNE. Эта оптимизированная реализация t-SNE использует преобразования Фурье для ускорения вычисления t-SNE. Смело читайте статью [4]. Он работает как шарм и использует все 16 ядер машины.

import sys; sys.path.append('../FIt-SNE')
from fast_tsne import fast_tsne
mapping = fast_tsne(model.sv.vectors, perplexity=50, seed=42)

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

Отображение Таблицы

Чтобы получить доступ к соответствующей графике, посетите мою общедоступную страницу с таблицей:

Https://public.tableau.com/views/ProductMap_15674406439260/TSNEPrice?:embed=y&:display_count=yes&:origin=viz_share_link

Вы можете навести указатель мыши на каждую точку и получить информацию о цене продукта, названии, бренде и т. Д.

Глядя на встраивание, мы видим, что в каждом кластере содержится довольно много информации.

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

Помните: все, что мы делали, - это усредняли все слова для каждого отзыва и суммировали все отзывы. Я очень ошеломлен тем, что возможно с использованием простого встраивания на основе среднего.

Заключение

Вложения предложений - важная часть конвейеров НЛП. В этом сообщении блога показано, как использовать быстрые встраивания предложений, FIt-SNE и Tableau для визуализации хорошо известного набора данных обзора Amazon.

Надеюсь, вам нравится использовать fse. Не стесняйтесь предлагать другие модели или функции, которые могут быть полезны.

Соответствующий пакет fse доступен на pip / Github и предлагает специалистам по обработке данных быстрый способ вычисления вложений предложений.

По всем вопросам и вопросам обращайтесь к мне.

И не забывайте подписываться на меня, если вам нравится этот контент :-)

Дополнительная информация

Код этого поста доступен на Github и через pip:

pip install -U fse

Литература

  1. Iyyer M, Manjunatha V, Boyd-Graber J, Daumé III H (2015) Глубокая неупорядоченная композиция конкурирует с синтаксическими методами классификации текста. Proc. 53-я годовщина. Встретиться. Доц. Comput. Лингвист. 7-й Int. Jt. Конф. Nat. Lang. Процесс., 1681–1691.
  2. Arora S, Liang Y, Ma T (2017) Простая, но непростая базовая линия для встраивания предложений. Int. Конф. Учиться. Представлять. (Тулон, Франция), 1–16.
  3. Ethayarajh, Kawin (2018) Вложения предложений случайным блужданием без учителя: надежный, но простой базовый уровень. Труды 3-го семинара по репрезентативному обучению для НЛП, 91–100.
  4. Linderman G C, Rachh M, Hoskins J G, Steinerberger S, Kluger Y (2019) Основанный на быстрой интерполяции t-SNE для улучшенной визуализации данных одиночной РНК-seq. Природные методы (16), 243–245.

Отказ от ответственности

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