NLPx

Tales of Data Science

История об LDA2vec: взболтать, но не смешивать

catdog_word2vec_cropped

UPD: В английской версии этого поста оставили очень ценный комментарий, и теперь я вижу, что я слишком заострил внимание на различиях LDA и word2vec, а они с алгоритмической точки зрения не так уж и сильно отличаются. Поэтому я несколько изменил первоначальную версию текста. Кстати, рекомендую прочитать презентацию товарища Голдберга про word2vec.

Буквально только что, когда уже хотел взяться за написание текста про конференцию (как обещал в предыдущем посте), я обнаружил совсем недавно созданный гибридный алгоритм, который хитрым образом берет лучшее (по крайней мере, должен брать лучшее) из известного алгоритма тематического моделирования LDA (Латентное размещение Дирихле) и из чуть менее известного инструмента языкового моделирования word2vec (никак не расшифровывается, но про него я писал ранее).

Вы также можете прочитать этот текст на английском

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

В чем фишка?

Размышления на тему

homer2_lda2vec

Из LDA и word2vec автором инструмента lda2vec (Крис Муди его зовут, если что) были взяты разные идеи.

Идея, которую lda2vec взял из LDA — это его «глобальность», то есть возможность выделять из документов темы, которые могут быть легко (хотя и не всегда) интерпретированы человеком. Кроме того, LDA, в отличие от word2vec воспринимает набор разных документов именно как набор документов, а не как одну большую строку слов.

Из word2vec была взята идея «локальности» — т.е. идея возможности создавать векторные представления слов на небольших промежутках текста, так называемых «окнах».

Вообще, можно говорить о том, что word2vec предсказывает слова локально — т.е. при данном одном слове он предсказывает близлежащее слово. В то же время LDA предсказывает глобально — предсказывает слово относительно глобального контекста (всего набора документов).

LDA_image2

Типичный вектор word2vec представляет собой плотный вектор вещественных чисел, в то время как вектор LDA — разреженный вектор вероятностей слов принадлежать к теме. Разреженность вектора выражается в том, что большая часть значений в векторе будет равна нулю — за счет этого получается большая интерпретируемость модели. Плотный же вектор word2vec не может похвастаться такой же степенью интерпретируемости, но сильно выигрывает в гибкости (плотнее вектор — больше степеней свободы).

lda2vec_image

Каким же образом можно объединить эти, казалось бы, необъединяемые идеи?

UPD: На самом деле не такие уж они необъединяемые. Товарищ Голдберг проделал хорошую работу, доступно объяснив, что подход, лежащий в основе word2vec, может быть немного переинтерпретирован и сведен к чему-то до ужаса похожему на SVD, которое Singular Value Decomposition.

В то же время и LDA относится к SVD самым непосредственным образом:

  1. SVD — стандартная математическая техника
  2. LSI (Латентное семантическое индексирование) — просто применение SVD в задаче информационного поиска (или извлечения информации в общем)
  3. LSA (Латентный семантический анализ) — это просто LSI, приложенное к решению задач автоматической обработки естественного языка
  4. PLSA (Вероятностный латентный семантический анализ) — это улучшение LSA
  5. LDA (Скрытое/Латентное размещение Дирихле) — улучшение PLSA

Таким образом, можно думать о разнице  LDA и word2vec в терминах выбора гиперпараметров и их применения к разным задачам (для моделирования отношений документ-слово или отношений слово-слово). При этом алгоритмически (так сказать, по modus operandi) они очень близки.

Для того, чтобы иметь возможность предсказывать слово как локально, так и глобально, автор применяет подход, сходный подходу из paragraph2vec (он же doc2vec) — когда к каждому вектору слова прибавляется метка (label) о принадлежности его определенному документу. Однако в случае lda2vec используется не метка, а разреженный вектор LDA. Затем к получившемуся в результате сложения вектору можно прибавлять различные заранее известные категориальные признаки и уже потом рассчитывать распределение слов по темам.

Таким образом, когда мы говорим о предсказывании слов в тексте, то каждое последующее слово предсказывается не только исходя из их наиболее вероятного расположения в контексте, как в word2vec:

P(Vout|Vin)

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

P(Vout|Vin+Vdoc+Vfeature)

где

Vdoc — грубо говоря вектор вероятностей принадлежать к темам для входного слова

Vfeature — некий категориальный признак

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

С помощью этого подхода можно (в теории) делать модели для обучения с учителем — например, модель для оценки известности авторов книг. Для каждого слова мы складываем вектор этого слова из word2vec и вектор LDA, добавляем туда какие-нибудь известные категориальные признаки (например, год издания или название издательства). Получившийся вектор используется для «присваивания» тем LDA соответствующим авторам книг. И в итоге выходит, что теоретически возможно использование этих связанных с авторами векторов для предсказывания каких-нибудь скрытых параметров, скажем, известности автора.

А если кратко?

homer-deep-thought_lda2vecВ объяснениях выше я не затрагивал особенные сложности, но все это может быть не очень понятно, а главное — скучновато. Поэтому можно сказать проще и уложиться в несколько пунктов.

Итак, о чем говорилось выше?

  • Word2vec моделирует отношения слово-слово, в то время как LDA моделирует отношения документ-слово
  • Модель lda2vec пытается совместить лучшие элементы обеих вышеуказанных моделей в один фреймворк.
  • Модель lda2vec создана с целью построения как тем на основе документов, так и тем на основе слов (одновременно), при этом теоретически возможно использование модели для обучения с учителем, чтобы создавать т.н. supervised темы с учетом различных параметров.

А зачем это кому-нибудь должно понадобиться?

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

Сравниваем Lda2vec с LDA

Какие тестовые данные?

В качестве тестового набора данных автор использует набор данных «Twenty newsgroups» из библиотеки scikit-learn (sklearn.datasets). Набор данных состоит из 18000 текстов на 20 различных тем. Данные разбиты на два набора — тренировочный и тестовый. Для примера в lda2vec автор использует тренировочный набор данных.

В наборе данных присутствует 20 тем:

  • comp.graphics
  • comp.os.ms-windows.misc
  • comp.sys.ibm.pc.hardware
  • comp.sys.mac.hardware
  • comp.windows.x
  • rec.autos
  • rec.motorcycles
  • rec.sport.baseball
  • rec.sport.hockey
  • sci.crypt
  • sci.electronics
  • sci.med
  • sci.space
  • misc.forsale
  • talk.politics.misc
  • talk.politics.guns
  • talk.politics.mideast
  • talk.religion.misc
  • alt.atheism
  • soc.religion.christian

Называются они не совсем по-человечески, но вполне понятно, о чем каждая из них.

Результаты я оценивал по двум субъективным критериям (с объективными было возиться лень, извините):

  1. Количество тем, которые я с первого взгляда смогу однозначно соотнести с реальными темами. Совпадающие темы я буду писать в скобках после списка слов, характеризующих тему LDA или lda2vec, например, (sci.med).
  2. Количество тем, которые хорошо выглядят, т.е. которым вполне можно подобрать адекватное название (пусть даже не совпадающее ни с одним из реальных). Такие темы я буду помечать тегом (looks ok).

Автор в своем репозитории на GitHub приводит следующие результаты работы lda2vec:

  • topic 0 out_of_vocabulary hicnet x/  oname hiv  pts lds eof_not_ok
  • topic 1 out_of_vocabulary hiv vitamin infections candida foods infection dyer diet patients (sci.med) (looks ok)
  • topic 2 out_of_vocabulary duo adb c650 centris lciii motherboard fpu vram simm (looks ok)
  • topic 3 yeast candida judas infections vitamin foods scholars greek tyre
  • topic 4 jupiter lebanese lebanon karabakh israeli israelis comet roby hezbollah hernlem (talk.politics.mideast) (looks ok)
  • topic 5 xfree86 printer speedstar font jpeg imake deskjet pov fonts borland (looks ok)
  • topic 6 nubus 040 scsi-1 scsi-2 pds israelis 68040 lebanese powerpc livesey
  • topic 7 colormap cursor xterm handler pixmap gcc xlib openwindows font expose (comp.graphics) (looks ok)
  • topic 8 out_of_vocabulary circuits magellan voltage outlet circuit grounding algorithm algorithms polygon
  • topic 9 amp alomar scsi-1 scsi-2 68040 mhz connectors hz wiring (looks ok)
  • topic 10 astronomical astronomy telescope larson jpl satellites aerospace visualization redesign (sci.space) (looks ok)
  • topic 11 homicides homicide handgun ># firearms cramer guns minorities gun rushdie (talk.politics.guns) (looks ok)
  • topic 12 out_of_vocabulary koresh adl bullock atf batf fbi davidians waco nra
  • topic 13 stephanopoulos stimulus keenan vat prize lopez gainey
  • topic 14 bike dod# lyme :> corn gt behanna cview bmw bikes (rec.motorcycles) (looks ok)
  • topic 15 out_of_vocabulary algorithm 80-bit ciphers cipher plaintext encrypted escrow ciphertext decrypt (sci.crypt) (looks ok)
  • topic 16 riders bike rider jody satan eternal helmet riding god ra
  • topic 17 stephanopoulos sumgait secretary karina q senator serbs azerbaijani (talk.politics.misc) (looks ok)
  • topic 18 out_of_vocabulary tires anonymity tire brake plaintext ciphertext ciphers helmet
  • topic 19 m»`@(«`@(«`@(«`@(«`@(«`@(«`@(«`@(«` max>’ax>’ax>’ax>’ax>’ax>’ax>’ax>’ax pts pt det 55.0 $ tor nyi

Результаты пока довольно грязные, однако для некоторых тем lda2vec можно найти соответствия в реальных темах. Я. например, сразу смог соотнести 8 тем, при этом 11 тем выглядят вполне нормально (включая те, для которых я нашел соответствия).

А теперь сравним эти результаты с результатами работы простого алгоритма LDA в реализации gensim. Я написал быстрый скрипт, где не вход в LDA подаются тексты в том же объеме и с почти той же предобработкой и сходным количеством итераций алгоритма (вы можете взять его у меня на GitHub и попробовать):

  • topic 0: game team play player win season last hockey score run (rec.sport.hockey) (looks ok)
  • topic 1: nasa gov jpl nec dseg power run center cool research
  • topic 2: government war tax insurance cramer arm law militia health bear
  • topic 3: armenian turkish law muslim jew greek turk government armenia jewish (talk.politics.mideast) (looks ok)
  • topic 4: believe christian mean science exist bible truth reason book belief (alt.atheism) (looks ok)
  • topic 5: drive washington mail mac space please hard thank computer disk
  • topic 6: file run thank version mit mouse help card graphic ibm  (looks ok)
  • topic 7: key encryption clipper government phone public chip netcom clinton information  (sci.crypt) (looks ok)
  • topic 8: jesu christian believe life day tell live law love christ  (soc.religion.christian) (looks ok)
  • topic 9: scsi drive bit card ide mac file color controller bus (comp.sys.mac.hardware) (looks ok)
  • topic 10: pitt food bank msg gordon keith water cause geb caltech
  • topic 11: car drive buy dealer israeli navy price mile virginia really
  • topic 12: thank drive usa cleveland please sale mail cwru computer monitor
  • topic 13: max uiuc value manager nasa cso men show set number
  • topic 14: space bike nasa list ride launch orbit motorcycle image data
  • topic 15: price sale file org access uucp help bob net maynard
  • topic 16: key chip clipper bit encryption law government technology toronto alaska (looks ok)
  • topic 17: gun israel israeli arab kill weapon firearm attack american control (talk.politics.guns) (looks ok)
  • topic 18: van chi uchicago win helmet princeton access det rutger tor
  • topic 19: jim government drug never isc udel fbi cwru case morality (talk.politics.misc) (looks ok)

LDA показывает приблизительно такие же результаты — я сразу соотнес 8 тем, при этом 11 тем выглядят вполне адекватными (включая те, для которых я нашел соответствия). Это говорит о том, что в текущей версии lda2vec качество тематического моделирования приблизительно такое же, как и у обычного LDA (если увеличивать итерации и там, и там — качество должно вырасти). Это неплохо, однако я ожидал чего-то более веселого.

Безусловно, кому-то может показаться, что количество тем, которые можно однозначно соотнести и вообще хорошо выглядящих тем на самом деле меньше (или больше), но все равно видно, что качество тематического моделирования более-менее одинаковое.

Как его попробовать самому?

Устанавливаем сам lda2vec

Lda2vec можно скачать с GitHub-репозитория его автора, распаковать в какую-нибудь папку, затем запустить setup.py с помощью команды (в командной оболочке, само собой):

sudo python /path-to-lda2vec-package/lda2vec/setup.py install

где /path-to-lda2vec-package/ — путь к распакованному вами архиву с lda2vec.

Если вы устанавливаете lda2vec не в стандартную директорию, где хранятся все библиотеки питона, то вам необходимо прописать в sys.path путь к папке с lda2vec.

Например, в моем случае:

import sys

sys.path.append('/home/torselllo/lda2vec/')
print sys.path
>>['/usr/lib/python2.7', '/usr/local/lib/python2.7/dist-packages', 
'/usr/lib/python2.7/dist-packages', '/usr/lib/pymodules/python2.7', 
'/home/torselllo/lda2vec/']

И можно запускать. Но не забудьте установить зависимости!

Устанавливаем зависимости

Чтобы самостоятельно попробовать lda2vec, необходимо установить зависимости — NumPy, Chainer и spaCy:

  • NumPy — это расширение языка Python, добавляющее поддержку больших многомерных массивов и матриц, вместе с большой библиотекой высокоуровневых математических функций для операций с этими массивами.
  • Chainer — это фреймворк для работы с нейросетями для глубокого (и не очень) обучения
  • spaCy — это библиотека для обработки естественного языка, славящаяся (по мнению ее авторов) скоростью и точностью работы

Установить их проще всего можно с помощью pip

Обходим возможные проблемы со spaCy

Нужно заметить, что spaCy — достаточно хитрая штука в плане установки. Например, если просто установить ее с помощью pip, а затем запустить lda2vec — может произойти интересная вещь — вы получите ошибку ввода-вывода:

>> IOError: /usr/local/lib/python2.7/dist-packages/spacy/en/data/vocab/strings.json.

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

sudo python -m spacy.en.download

Будьте осторожны — модель качается с официального репозитория и весит 519.05MB

Казалось бы — просто, но не очевидно, особенно если устанавливаешь в качестве зависимости и не посещаешь перед этим официальный сайт.

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

/usr/local/lib/python2.7/dist-packages/spacy/data/en_default-1.0.7

а искать ее lda2vec продолжала в

/usr/local/lib/python2.7/dist-packages/spacy/en/data/

Исправить это можно небольшим грязным хаком — переместить модель туда, где ее будут искать! Сделать это можно с помощью классической команды mv, которая не только перемещает, но и переименовывает. В моем случае я сделал так:

sudo mv /usr/local/lib/python2.7/dist-packages/spacy/data/en_default-1.0.7 /usr/local/lib/python2.7/dist-packages/spacy/en/data/

Дальше можно запускать пример. Но, если вы не собираетесь применять расчеты на GPU (которые работают в 10 раз быстрее, чем расчеты на CPU), потому что у вас видеокарта, не поддерживающая работу библиотеки CUDA (не NVidia GeForce, например), то будьте осторожны — в нынешней версии (26 января 2016) реализация lda2vec очень долго сходится. К примеру, на 500 входных документов все это дело считалось час (core i5 2МГц, 2 Гб ОЗУ). На всех 18 000 текстов считалось больше 12 часов, а потом мне надоело и я выключил, так и не доведя дело до конца, каюсь.

Заключение

Это была история об lda2vec, интересном подходе и реализации этого подхода, который я попробовал и сравнил с обычным LDA. Подход интересный и, кажется, достаточно перспективный, хотя в данную минуту выглядит не полностью убедительно.

На всякий случай сообщаю, что данная минута — это 30 января 2016 года.

Ссылки

Официальная документация по lda2vec

Репозиторий lda2vec на GitHub

Обсуждение lda2vec на Ycombinator

Презентация lda2vec на slideshare

 

6,683 просмотров всего, 12 просмотров сегодня

История об LDA2vec: взболтать, но не смешивать
4.3 3 votes

Leave a Reply

3 Comments on "История об LDA2vec: взболтать, но не смешивать"

avatar
Sort by:   newest | oldest | most voted
Николай
Guest

Очень интересный обзор. Вы предполагаете, что это будет лучше работать с точки зрения сегментирования клиентов по-всей видимости в достаточно общие категории (спорт, литература, кино, например), но если речь идёт о кластеризации более частных проблем взаимодействия клиент-компания (вопросы по конкретной услуге, товару и т.д) так ли эффективен будет lda2vec по сравнению с LDA или doc2vec, что вы думаете? Спасибо.

wpDiscuz