Введение в word2vec в глубоком обучении

Основы алгоритма word2vec

Здравствуйте и вновь добро пожаловать на занятия по теме «Обработка естественного языка: глубокое обучение на языке Python, часть 6».

В этой статье мы обсудим основы алгоритма word2vec.

Не забывайте, что word2vec используется для векторного представления слов, поэтому у нас будет матрица размерности VxD. Если вы проходили мой курс по рекуррентным нейронным сетям, то должны быть знакомы с идеей прогнозирования следующего слова. В этой задаче мы просто берём все предыдущие слова в последовательности и стараемся спрогнозировать следующее слово последовательности. Мы начнём даже с более простой задачи: будем брать лишь одно слово в каждый момент времени и стараться предсказать следующее. Напомню, это называется биграммой. По сути, это марковская модель, поскольку каждое слово обусловлено лишь одним предыдущим значением. Для решения этой задачи нам потребуются навыки, полученные в «Глубоком обучении, часть 1».

Итак, каков же вид модели? В качестве входа у нас есть матрица VxD, один скрытый слой и на выходе – матрица DxV. Интересно, что в word2vec в скрытом слое не используются никакие нелинейные функции – значения просто проходят по нему. Это значит, что по сути мы имеем лишь линейное отображение от предыдущего слова к последующему. Забавно, но метод word2vec был изобретён именно в то время, когда глубокое обучение стало очень популярным. Тем не менее, эта модель вовсе не относится к глубокому обучению.

Для обучения нашей модели в настоящий момент мы воспользуемся только уже имеющимися знаниями. У нас есть одно целевое слово на каждый учебный пример. Мы установим выход равным 1, воспользуемся функцией софтмакс, вычислим кросс-энтропийную функцию ошибок и запустим градиентный спуск – пока что ничего особенного. В последующих лекциях мы обсудим обновления этой архитектуры, которые и делают из word2vec то, чем оно является, – куда более мощной моделью, нежели простая биграммная модель предсказания.

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

Подумаемо том, как можно решить данную задачу, если бы мы действительно использовалилогистическую регрессию. Тогда на самом деле нам не нужен градиентный спуск. Насамом деле это нечто вроде союза логистической регрессии и марковских моделей,о которых вы узнали из моего курса по скрытым марковским моделям. Матрицу VxV можнорассматривать как марковскую, в которой каждая строка представляет вероятностьпоявления следующего слова с учётом того, что предыдущее слово представляет этустроку. В связи с этим можно просто решить всю матрицу, использовав максимумправдоподобия и, возможно, добавив сглаживание.

Разберёмпростенький пример. Пусть в нашем корпусе документов есть два предложения, аразмер словаря равен 4. Предложения следующие: «Я люблю собак» и «Я люблюкотов». Тогда VxV матрицаприобретает вид

Последниедве строки представлены нулями, поскольку после «собак» и «котов» слов нет.

Какя указывал, эта модель только похожа на логистическую регрессию. Умножив W2 на W1, мы получимматрицу размерности VxV, так что функциональная форма окажетсяодинаковой.

Последниедве строки представлены нулями, поскольку после «собак» и «котов» слов нет.

Какя указывал, эта модель только похожа на логистическую регрессию. Умножив W2 на W1, мы получимматрицу размерности VxV, так что функциональная форма окажетсяодинаковой.

Вопросв их отличии.

Прикинем,сколько у нас будет вариантов, если мы прямо используем логистическуюрегрессию. Для словаря размером в 2000 размер матрицы весовых коэффициентовбудет равен 2000×2000 =4 000 000. Что же касается биграммной модели, то предположим, чторазмер нашего скрытого слоя D равен 100, чтобы размер векторного представленияслов был равен 100. Тогда размер W1 будет равен2000×100, размер W2 также будетравен 2000×100, а всего получится 2000×100+ 2000×100 = 400 000 параметров. Это в 10 раз меньше,чем в логистической регрессии.

Поведёмитоги. Да, мы делаем нечто вроде логистической регрессии, но с намного меньшимколичеством параметров для обучения, что приводит к более компактной модели сболее высоким уровнем представления данных. В качестве упражнения попробуйтепостроить векторное представление слов, используя данную биграммную модель, ипосмотреть, получится ли найти какие-то интересные закономерности. Незабывайте, что всё это требует лишь знаний, полученных в «Глубоком обучении,часть 1», так что на данный момент для вас это должно быть очень просто.

CBOW

Здесь, мы обсудим первую модификацию метода word2vec простой биграммной модели. Она называется CBOW, что расшифровывается как «непрерывный мешок слов».

По сути, она включает в себя контекст. Точнее говоря, мы можем лучше предсказывать слово, если будем учитывать окно окружающих слов, а не лишь одно предыдущее слово. Впервые это обсуждалось в моём курсе по введению в обработку естественного языка, где для написания синонимайзера текста использовались предыдущее и последующее слова, чтобы предсказать слово, лежащее между ними. В том примере мы приняли размер контекста, равным 1. В word2vec обычно используется размер контекста, равный от 5 до 10 слов, то есть 10 слов слева и 10 слов справа, хотя иногда, когда говорят о размере контекста, имеют в виду всего 10 слов. Поэтому, вообще говоря, когда вы видите упоминание о размере контекста, проверяйте, что именно имеется в виду. Предсказываем же мы лежащее посередине слово – именно то, что мы делали в примере с синонимайзером текста.

Итак,как же видоизменить нейронную сеть, чтобы использовать CBOW?Для этого мы просто добавляем в нейронную сеть больше входов. Вход получаетсягораздо большим, но выход остаётся прежним. Обратите внимание на одинаковыевходы скрытых весовых коэффициентов слева (см. слайд). Не забывайте, что входому нас служат слова, полученные прямым кодированием, так что каждое из нихзанимает одну строку матрицы векторных представлений слов и передаётся вскрытый слой. Таким образом, это не обязательно должны быть общие весовыекоэффициенты.

Ачто же происходит в скрытом слое? Если у нас есть 10 входных векторов, то вскрытом слое у нас будет 10 векторов размерности D, и нам нужно каким-то образом сопоставить это сматрицей DxV, чтобы получитьответ. В CBOW мы просто берём среднее значение этих десятивекторов. То есть мы просто суммируем их, делим на 10 и получаем векторразмерности 1xD, который можетбыть передан исходящему слою. Обратите внимание, что у нас по-прежнему нетникаких нелинейных функций в скрытом слое, как и не будет ни в одном алгоритме,которые рассматриваются в этом курсе.

Skip-Gram

Теперь изучим вторую модификацию простой биграммной модели, которая называется Skip-gram.

CBOW и Skip-gram являются двумя основными методами включения контекста в word2vec, то есть это не просто биграммное прогнозирование. Skip-gram по сути является противоположностью CBOW: тогда как CBOW использует контекст, чтобы предсказать лежащее в середине слово, Skip-gram использует это среднее слово, чтобы предсказать контекст. Если показывать наглядно, то теперь у нас вход остаётся прежнего размера, а выход «разбухает» (см. слайд). Обратите внимание на исходящие весовые коэффициенты, повторяющиеся на правой части диаграммы.

Еслимы с вами похожи, то модель, вероятно, покажется вам несколько странной. Мызнаем, что функция софтмакс предназначена для прогнозирования только одногокласса, то есть из V слов софтмакс выберет одно. Мы же как бы отправляемпротиворечивые сигналы нейронной сети, указывая ей: стой, выбери все 10 слов,учитывая данное среднее. Но мы будем продолжать, как будто здесь нет ничеготакого.

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

Вкачестве упражнения я настоятельно рекомендую попытаться создать описанную вышемодель Skip-gram. Вновь-таки, этопотребует только знаний, которые вы усвоили в «Глубоком обучении, часть 1».Можете использовать как Numpy, так и Theano. Одна из проблем, с которой вы при этомстолкнётесь, заключается в большом количестве обновлений весовых коэффициентов,особенно если размер вашего словаря будет измеряться миллионами слов. Прииспользовании Numpy получится, что нужно будет обновлять каждый весовойкоэффициент между скрытым и исходящим слоями, поскольку результат будет илиправильным, или нет, и весовые коэффициенты нужно обновить в соответствии сполученным сигналом. Между входным же и скрытым слоями обновляться должнотолько слово-вектор среднего слова, поскольку это единственный параметр,который передаётся на исходящий слой. Таким образом, в целом придётся обновлятьD*(V + 1)вещественных чисел.

Ачто, если использовать Theano? Тонкость с Theano в том, что мы должны взять всю матрицу весовыхкоэффициентов как одну переменную. Обновления же будут представлены в Theano в виде кортежей в форме (W,W-lr*g), где W – весовыекоэффициенты, lr – коэффициент обучения, g– градиент. Таким образом, на данный момент не представляется возможнымобновить лишь часть весовых коэффициентов. Если же мы попытаемся это сделать в Theano, то нам придётся обновлять 2*V*D вещественныхчисел, что даже больше, чем в Numpy. Вы можетерешить создать 2*V векторов, каждый с размерностью D,но это, вероятнее всего, не очень хорошая идея, поскольку создание объектовпотребует дополнительных усилий.

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

Отрицательное сэмплирование

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

Сутьв следующем. Если у нас есть K слов в контексте, то должно быть и K целевыхпеременных. Соответственно, будет K*(V – 1) слов, которые не являются целевымипеременными. Почему? Потому что каждое из целевых слов контекста являетсяцелевой переменной только в один момент времени, а всё остальное время –таковой не является. Это значит, что много времени мы тратим на то, чтобы словане были целевыми переменными.

Основнаяидея отрицательного сэмплирования в том, что мы отбрасываем большинство этихслов, не являющихся целевыми переменными, то есть не состоящих в контексте, – аэто почти размер всего словаря. Таким образом, нам не нужно «объяснять»нейронной сети, что эти слова не являются целевыми переменными во все моментывремени. Нам просто нужно сообщить нейронной сети, что иногда эти слова неявляются целевыми переменными. Эти слова, не входящие в контекст, называются«отрицательными примерами». Обычно их берут небольшое количество, порядкаразмера контекста. Например, 10 – неплохое значение.

Возникаетвопрос: выбирать эти отрицательные примеры из равномерного распределения иликаким-то другим способом? Обычно отрицательные примеры выбираются, основываясьна равномерном распределении или на распределении, основанном на вероятностипоявления слова – такое распределение обозначается Pn(w). Исследования показали, что начальноераспределение, возведённое в степень 3/4, даёт неплохие результаты.

Почемутак? Если слово появляется в корпусе документов много раз, то мы соответственностараемся избавиться от него, если оно не является частью контекста. Для этогонам нужна его функция вероятности появления p(w). Однако некоторые из этих вероятностейбудет очень маленькими. В общем случае вероятности слов имеют распределение сдлинным «хвостом», и множество слов появляется очень редко. Мы можем увеличитьшанс попасть в выборку, возводя вероятность в степень меньше единицы.

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

Тоесть, мы суммируем по всем исходящим словам контекста, берём логарифм сигмоидыскалярного произведения весовых коэффициентов. Из всего этого вычитаем всеисходящие слова отрицательных примеров, которые рассчитываются как суммалогарифмов сигмоиды отрицательного скалярного произведения входных данных иисходящих весовых коэффициентов.

Каквидите, вернулась наша старая подруга – сигмоида. Обратите внимание, что уотрицательных примеров аргументом сигмоиды является отрицательное скалярноепроизведение. wозначает матрицу между входным и скрытым слоями, i – индекс входящего слова, v – матрица междускрытым и исходящим слоем, o – индекс исходящего слова контекста или исходящегослова отрицательных примеров.

Чтодалее? Далее идёт, конечно же, вычисление производной для градиентного спуска.Вы уже знаете, как взять производную логарифма, сигмоиды и скалярногопроизведения, так что, надо полагать, моя помощь тут не нужна. Я покажу ответ,но в качестве упражнения попытайтесь найти производную сами.

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

Здесьto – целеваяпеременная, равная 0, если это отрицательный пример и 1, если это слово изконтекста. Не забывайте, что для обновления от входного до скрытого слоя o в суммеиндексирует и все исходящие слова контекста, и все исходящие отрицательныепримеры.

Иещё несколько замечаний, прежде чем двинуться дальше. Рассматривая весь учебныйкорпус документов в целом и отдельные образцы, предоставляемые модели дляобучения, возникает вопрос: что делать с тем обстоятельством, что некоторыеслова будут возникать на входе более чем один раз? При этом каждый раз,вероятнее всего, они будут иметь совершенно разный контекст. К примеру,рассмотрим два предложения: «Мне нравятся собаки и кошки» и «Собаки сгрызли моюдомашнюю работу». В обоих случаях «собаки» является входящим словом. Как жеможно предсказать такого рода слова, если нейронная сеть имеет лишь одинвозможный выход? Для некоторых это может показаться странным, поскольку вмашинном обучении мы стараемся делать правильные прогнозы, но поскольку нашамодель, по сути, в конце реализует софтмакс, то получиться может только однозначение прогноза. Это значит, что если мы будем пытаться использовать даннуюмодель для прогнозирования, то толку от этого будет немного. Так что высокий коэффициентклассификации нам здесь не нужен. Нам нужно лишь, чтобы функция затрат сходилак минимуму, а затем оценить результат, проделав нечто вроде словесных аналогийили любую другую задачу, которая бы свидетельствовала о полезности векторногопредставления слов.

Этовсё, что качается отрицательного сэмплирования.

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

Ясам провёл несколько опытов и нашёл, что следует брать порядка 50 и большетекстовых файлов, полученных через утилиту wp2txt. Вы можете использовать столько, сколько захотите,но учтите, что чем больше у вас будет учебных данных, тем большим будет времяобучения.

Мыне упомянули об ещё одной модификации функции софтмакс. Она называетсяиерархическим софтмаксом. Исследования показали, что лучше всего работаетотрицательное сэмплирование в сочетании со Skip-gram, и именно их мы и реализуем.

Ипоследнее замечание по поводу кода. Поскольку я показал вам формулу градиентадля градиентного спуска, код мы будем писать прямо в Numpy.Кроме прочего, это позволит нам проиндексировать конкретные весовыекоэффициенты, которые мы хотим обновить, вместо того чтобы обновлять всю ихматрицу, как в Theano.

Тут вы можете спросить: а можно ли в Theano обновлять только часть общих переменных? Ответ: да, можно. И поэтому мы напишем два примера кода с word2vec. Первый из них будет в Numpy, поскольку это наиболее очевидный способ и непосредственно следует из этих лекций. Вы даже можете написать его самостоятельно, пользуясь только теми методами, которые были изучены в предыдущих курсах.

Второйспособ – выполнить всё в Theano, поскольку онавтоматически рассчитывает градиенты. Но для этого понадобятся некоторые новыеприёмы, а именно: способы обновлять лишь часть общих переменных, чтобы можнобыло воспользоваться преимуществами оптимизации, которые предоставляетотрицательное сэмплирование.

Зачем нужно 2 матрицы векторных представлений слов и что с ними делать

Наданный момент остаётся только одно небольшое затруднение, которое нужно решить,прежде чем вы сможете самостоятельно приступить к реализации словесныханалогий. В случае с рекуррентными нейронными сетями у нас была единичная матрицавекторных представлений слов – матрица размерности VxD в начале нейронной сети. Тамразмещались слова-векторы и оттуда мы могли их использовать для векторногопредставления слов.

С word2vec ситуация другая. На самом деле у нас есть две матрицы VxD – одна для весовых коэффициентов между входным и скрытым слоями, а вторая для весовых коэффициентов между скрытым и исходящим слоями. Возникает вопрос: какая же из них отвечает за векторное представление слов? Первая? Вторая? Обе?

Вэтой лекции я покажу два способа, которыми исследователи сочетали их в прошлом.

Первый метод – просто объединить слова-векторы. Мы берём первую матрицу векторных представлений и помещаем рядом с транспонированной второй матрицей векторных представлений:

Здесьto – целеваяпеременная, равная 0, если это отрицательный пример и 1, если это слово изконтекста. Не забывайте, что для обновления от входного до скрытого слоя o в суммеиндексирует и все исходящие слова контекста, и все исходящие отрицательныепримеры.

Иещё несколько замечаний, прежде чем двинуться дальше. Рассматривая весь учебныйкорпус документов в целом и отдельные образцы, предоставляемые модели дляобучения, возникает вопрос: что делать с тем обстоятельством, что некоторыеслова будут возникать на входе более чем один раз? При этом каждый раз,вероятнее всего, они будут иметь совершенно разный контекст. К примеру,рассмотрим два предложения: «Мне нравятся собаки и кошки» и «Собаки сгрызли моюдомашнюю работу». В обоих случаях «собаки» является входящим словом. Как жеможно предсказать такого рода слова, если нейронная сеть имеет лишь одинвозможный выход? Для некоторых это может показаться странным, поскольку вмашинном обучении мы стараемся делать правильные прогнозы, но поскольку нашамодель, по сути, в конце реализует софтмакс, то получиться может только однозначение прогноза. Это значит, что если мы будем пытаться использовать даннуюмодель для прогнозирования, то толку от этого будет немного. Так что высокий коэффициентклассификации нам здесь не нужен. Нам нужно лишь, чтобы функция затрат сходилак минимуму, а затем оценить результат, проделав нечто вроде словесных аналогийили любую другую задачу, которая бы свидетельствовала о полезности векторногопредставления слов.

Этовсё, что качается отрицательного сэмплирования.

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

Ясам провёл несколько опытов и нашёл, что следует брать порядка 50 и большетекстовых файлов, полученных через утилиту wp2txt. Вы можете использовать столько, сколько захотите,но учтите, что чем больше у вас будет учебных данных, тем большим будет времяобучения.

Мыне упомянули об ещё одной модификации функции софтмакс. Она называетсяиерархическим софтмаксом. Исследования показали, что лучше всего работаетотрицательное сэмплирование в сочетании со Skip-gram, и именно их мы и реализуем.

Ипоследнее замечание по поводу кода. Поскольку я показал вам формулу градиентадля градиентного спуска, код мы будем писать прямо в Numpy.Кроме прочего, это позволит нам проиндексировать конкретные весовыекоэффициенты, которые мы хотим обновить, вместо того чтобы обновлять всю ихматрицу, как в Theano.

Тут вы можете спросить: а можно ли в Theano обновлять только часть общих переменных? Ответ: да, можно. И поэтому мы напишем два примера кода с word2vec. Первый из них будет в Numpy, поскольку это наиболее очевидный способ и непосредственно следует из этих лекций. Вы даже можете написать его самостоятельно, пользуясь только теми методами, которые были изучены в предыдущих курсах.

Второйспособ – выполнить всё в Theano, поскольку онавтоматически рассчитывает градиенты. Но для этого понадобятся некоторые новыеприёмы, а именно: способы обновлять лишь часть общих переменных, чтобы можнобыло воспользоваться преимуществами оптимизации, которые предоставляетотрицательное сэмплирование.

Зачем нужно 2 матрицы векторных представлений слов и что с ними делать

Наданный момент остаётся только одно небольшое затруднение, которое нужно решить,прежде чем вы сможете самостоятельно приступить к реализации словесныханалогий. В случае с рекуррентными нейронными сетями у нас была единичная матрицавекторных представлений слов – матрица размерности VxD в начале нейронной сети. Тамразмещались слова-векторы и оттуда мы могли их использовать для векторногопредставления слов.

С word2vec ситуация другая. На самом деле у нас есть две матрицы VxD – одна для весовых коэффициентов между входным и скрытым слоями, а вторая для весовых коэффициентов между скрытым и исходящим слоями. Возникает вопрос: какая же из них отвечает за векторное представление слов? Первая? Вторая? Обе?

Вэтой лекции я покажу два способа, которыми исследователи сочетали их в прошлом.

Первый метод – просто объединить слова-векторы. Мы берём первую матрицу векторных представлений и помещаем рядом с транспонированной второй матрицей векторных представлений:

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

Второйметод – взять среднее арифметическое:

Витоге получатся векторы с прежней размерностью D.

Вкоде мы реализуем оба способа, ведь это несложно.

Витоге получатся векторы с прежней размерностью D.

Вкоде мы реализуем оба способа, ведь это несложно.

Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: