>>1.00<<>>1.00<<Видео проигрыватель загружается.Воспроизвести видеоВоспроизвестиБез звукаТекущее время 0:00/Продолжительность 7:36Загрузка: 0.00%0:00Тип потока ОНЛАЙНSeek to live, currently behind liveОНЛАЙНОставшееся время -7:36 1xСкорость воспроизведения2x1.75x1.5x1.25x1x, выбрано0.75x0.5xГлавыГлавыОписанияОтключить описания, выбраноСубтитрынастройки субтитров, откроется диалог настройки субтитровСубтитры выкл., выбраноЗвуковая дорожкаPicture-in-PictureПолноэкранный режимThis is a modal window.Начало диалоговго окна. Кнопка Escape закроет или отменит окноТекстColorБелыйЧерныйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачностьПолупрозрачныйФонColorЧерныйБелыйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачностьПолупрозрачныйПрозрачныйОкноColorЧерныйБелыйКрасныйЗеленыйСинийЖелтыйПурпурныйГолубойTransparencyПрозрачныйПолупрозрачныйПрозрачностьРазмер шрифта50%75%100%125%150%175%200%300%400%Стиль края текстаНичегоПоднятыйПониженныйОдинаковыйТеньШрифтПропорциональный без засечекМоноширинный без засечекПропорциональный с засечкамиМоноширинный с засечкамиСлучайныйПисьменныйМалые прописныеСбросить сбросить все найстройки по умолчаниюГотовоЗакрыть модальное окноКонец диалогового окна.
С подготовкой данных — всё, переходим к описанию модели. Давайте я напомню основную идею, лежащую в основе модели SkipGram.[1] В модели SkipGram для каждого слова у нас есть два вектора — первый вектор используется, когда слово находится в центре скользящего окна, и второй вектор используется, когда это слово описывает контекст. Для того, чтобы хранить эти вектора, мы создаём две матрицы. Каждая матрица имеет размер по количеству слов в словаре и по количеству элементов в векторе. То есть — размер словаря на размер нашего эмбеддинга. Настраивать значения этих матриц, то есть обучать модель, мы будем по методу максимального правдоподобия. Изначальная интуиция описывается вот этой формулой — то есть мы моделируем условное распределение соседних слов в некотором окне (небольшом, как правило это "5") при условии того, что мы пронаблюдали центральное слово и у нас есть какие-то параметры модели. Это распределение в общем виде посчитать очень сложно. Мы предполагаем, что оно раскладывается на произведения более простых распределений. Каждое такое "более простое" распределение нам говорит, насколько вероятно можно встретить какое-то контекстное слово рядом с центральным словом. То есть, для слов, которые типично встречаются рядом, наша модель должна возвращать вероятность, близкую к единице, а для слов, которые никогда не встречаются рядом — вероятность, близкую к нулю. В этом распределении у нас есть две случайные величины. Обе они — категориальные (то есть, дискретные и принимающие значение из некоторого фиксированного конечного набора). Общепринятый способ моделировать категориальные распределения — это софтмакс. Софтмакс — это функция такого вида, которой на вход подаётся вектор вещественных чисел из произвольного диапазона, и она переводит этот вектор в вектор, описывающий распределение вероятности категориальной величины. В контексте word2vec мы подаём в софтмакс оценки сходства слов. Сходство слов мы будем моделировать как скалярное произведение векторов этих слов. Причём мы будем, для центрального слова, брать векторы из первой матрицы (из матрицы w), а для контекстного слова мы будем брать вектор из второй матрицы (матрицы d). Всё, вроде бы, хорошо, но в этой формуле есть проблемы. Проблема заключается в том, что нам необходимо брать сумму в знаменателе по очень большому числу слагаемых. Это очень вычислительно неэффективно. Авторы модели предлагают заменить сумму по всему словарю суммой по небольшому количеству случайно выбранных слов и, каждый раз, когда нам нужно посчитать аппроксимацию к этому софтмаксу, мы выбираем новые случайные слова — это, как раз, называется "negative sampling". То есть, SkipGram (это "предсказываем соседние слова по центральному слову") — это вот эта часть формул, а "negative sampling" — это вот эта часть формул. Короче говоря, задача обучения word2vec сводится к обучению классификатора, который, имея два идентификатора слова (два номера токена) предсказывает — могут они встретиться вместе, или не могут. Всё, на самом деле — проще, чем может показаться, когда вы посмотрите на эти формулы. Давайте перейдём к программированию нашей модели и процессу её обучения. Сначала определим вспомогательную функцию, которая нам будет полезна. Наша модель принимает на вход целое предложение и должна оценивать вероятности встречаемости двух слов внутри небольшого окна. Другими словами, нам нужно игнорировать факты совместной встречаемости слов в одном предложении, но — далеко друг от друга, за пределами окна. Для того, чтобы игнорировать такие случаи, введём функцию, которая создаёт маску. В данном случае, маска — это квадратная матрица, сторона матрицы равна длине предложения, с которым мы работаем, все элементы в этой матрице — нулевые, за исключением двух полосок вдоль главной диагонали. Эти полоски заполнены единичками, и ширина этих полосок равна половине ширины окна. Таким образом мы задаём множество пар позиций токенов в предложении, для которых мы учитываем факты совместной встречаемости. Другими словами, строки и столбцы этой матрицы соответствуют некоторым позициям токенов в предложении, и значение этой матрицы задаёт — учитываем ли мы тот факт, что два токена, стоящие на этих позициях, встречается в одном предложении — учитываем ли мы этот факт как положительный пример при обучении, или игнорируем этот факт. Например, для позиций 10 и 2 мы игнорируем, потому что эти две позиции стоят далеко. А если позиции отличаются всего лишь на единичку — например 3 и 2, то мы уже учитываем, потому что тогда эти 2 токена всегда входят в наше окно. Эта матрица нам потребуется чуть позже для того, чтобы реализовать эффективную пакетную обработку на видеокарте. Итак, начнём описывать нашу модель. Как вы помните, в модели есть две прямоугольные матрицы размерности "количество слов в словаре" на "размер эмбеддинга". В pytorch есть модуль, который реализует функции выборки из этой таблицы по номеру токена — этот модуль называется embedding, и он лежит в пакете nn. Мы создаём два экземпляра этого класса для того, чтобы хранить таблицу центральных векторов и контекстных векторов. Очень важный момент, который не всегда описывается в руководствах и статьях про обучение эмбеддингов: очень важно проинициализировать эти таблицы. По умолчанию, nn.embedding заполняет значения в своей матрице нормальным шумом. Для обучения word2vec эта инициализация совершенно не подходит. Правильный способ инициализации весов для обучения word2vec — это равномерный шум, причём диапазон значений этого шума связан с размерностью эмбеддингов. Такая инициализация нужна для того, чтобы длина вектора, начальная, примерно равнялась единице. Также, как мы помним, у нас есть фиктивное слово — фиктивный токен "pad". Мы его используем для того, чтобы дополнять предложения до фиксированной длины. Мы говорим слою nn embedding, что токен с индексом "0" — фиктивный и что для него не нужно учить вектор, для него вектор всегда будет нулевым. Он не будет меняться в процессе обучения. Проделываем всё то же самое для матрицы контекстных векторов. И создаём, один раз, матрицу масок с двумя полосками ненулевых элементов — как мы чуть раньше сказали. Это — то, что касается инициализации.
[1] Word2vec Made Easy https://towardsdatascience.com/word2vec-made-easy-139a31a4b8ae

К сожалению, у нас пока нет статистики ответов на данный вопрос, но мы работаем над этим.