Эти вещи о встраивании слов

NLP
Эти вещи о встраивании слов

Item2Vec: обобщение метода Word2vec.

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

clip_image002.jpg

Поэтому в 2015 году Microsoft предложила метод Item2Vec, который является обобщением метода Word2vec, что делает метод Embedding пригодным практически для всех данных последовательности. Технические детали модели Item2Vec почти такие же, как и у Word2vec. Пока мы можем выразить объект, который хотим выразить, в форме данных последовательности, а затем «скормить» данные последовательности модели Word2vec, мы можно получить вложение любого предмета. Предложение Item2vec, конечно, имеет решающее значение для системы рекомендаций, потому что оно делает возможным «встраивание всего». Для рекомендательных системItem2vec может использовать встраивание элементов, чтобы напрямую получить их сходство, или ввести рекомендательную модель как важную функцию для обучения, которая поможет улучшить эффект системы рекомендаций.

clip_image004.jpg

Какие графически структурированные данные существуют в Интернете?

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

Некоторые учащиеся могут не знать, какая важная информация содержится в структуре графа, почему мы хотим использовать их с пользой и создавать на их основе Embedding? Ниже я сначала познакомлю вас с очень типичными структурными данными графа в Интернете. Рисунок 1:

clip_image006.jpg

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

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

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

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

Метод встраивания графа на основе случайного блуждания: Глубокое блуждание

Давайте сначала изучим метод встраивания графов, который имеет относительно большое влияние в отрасли и широко используется, Deep Walk, который был предложен исследователями из Университета Стоуни-Брук в США в 2014 году. Его основная идея состоит в том, чтобы случайным образом перемещаться по структуре графа, состоящей из элементов, генерировать большое количество последовательностей элементов, а затем вводить эти последовательности элементов в качестве обучающих образцов в Word2vec для обучения и, наконец, получать встраивание элемента. Следовательно, DeepWalk можно рассматривать как метод перехода, соединяющий встраивание последовательности и встраивание графа. На рис. 2 ниже показано выполнение метода DeepWalk.

Далее я подробно объясню алгоритм алгоритма DeepWalk со ссылкой на четыре схематические диаграммы на рисунке 2. Рисунок II:

clip_image008.jpg

  • Во-первых, мы строим граф отношения элементов (рис. 2-б) на основе исходной последовательности поведения пользователя (рис. 2-а), такой как последовательность покупки пользователем товаров, просмотра видео и т. д. Из него мы видим, что, поскольку пользователь Ui последовательно купил товар A и товар B, создается направленное ребро от A к B. Если впоследствии генерируются несколько идентичных направленных ребер, веса направленных ребер усиливаются. После преобразования всех последовательностей поведения пользователя в ребра в графе, относящемся к элементам, создается глобальный граф, относящийся к элементам.

  • Затем мы случайным образом выбираем начальную точку случайным блужданием, чтобы восстановить последовательность элементов (рис. 2-c). Среди них количество и длина выборки случайного блуждания — все это гиперпараметры, которые необходимо настроить в соответствии с конкретными приложениями.

  • Наконец, мы передаем эти случайные последовательности элементов, сгенерированные обходом, в модель Word2vec на рис. 2-d, чтобы сгенерировать окончательный вектор встраивания элементов.

В приведенном выше потоке алгоритма DeepWalk единственное, что необходимо формально определить, - это вероятность перехода случайного блуждания, то есть после достижения узла vi следующим шагом является пересечениеviv_i соседствоvjv_j Вероятность. Если граф отношений элементов является направленным и взвешенным графом, то подчиненный узелviv_i перейти к узлуvjv_j Вероятность определяется следующим образом:

P(vjvi)={MijjеN+(Vi),mijvjеN+(Vi)0,eijϵP(v_j|v_i)=\left\{ \begin{aligned} \frac{M_{ij}}{\sum_{j\in N_+(V_i)}},m_{ij} \quad v_j\in N_+(V_i)\\ 0, e_{ij} \not\in \epsilon \end{aligned} \right.

в,N+(Vi)N_+(V_i) узелvjv_j Сбор всех исходящих ребер,MijM_{ij} узелviv_i к узлуvjv_jВес ребра, то есть вероятность прыжка DeepWalk, представляет собой отношение веса прыгающего ребра к сумме весов всех связанных исходящих ребер. Если граф корреляции элементов является неориентированным и невзвешенным графом, то вероятность перехода будет частным случаем приведенной выше формулы, весMijM_{ij} будет константа 1, иN+(Vi)N_+(V_i) должен быть узелviv_i Набор всех «ребер», а не всех «внешних ребер».

После получения новой последовательности элементов путем случайного обхода мы можем сгенерировать элемент Embedding с помощью классического метода Word2vec.

Подход к компромиссу между однородностью и структурой, Node2vec

В 2016 году исследователи из Стэнфордского университета пошли дальше DeepWalk, предложив модель Node2vec. Node2vec настраивает метод вероятности скачка случайного блуждания, так что результаты встраивания графа взвешиваются между однородностью и структурной справедливостью сети и могут дополнительно вводить различные вложения в рекомендательную модель, позволяя системе рекомендаций изучать характеристики различных сетевых структур. .

что я сказал здесь«Однородность» сети означает, что встраивание узлов с одинаковыми расстояниями должно быть как можно ближе., как показано на рисунке 3, выражения Embedded узла u и связанных с ним узлов s1, s2, s3 и s4 должны быть близкими, что является воплощением «однородности» сети. На веб-сайтах электронной коммерции однородные товары, скорее всего, относятся к одной категории, одному и тому же атрибуту или товары, которые часто покупаются вместе.

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

clip_image012.jpg

После понимания этих основных концепций возникает вопрос, как результат встраивания графа выражает структуру и однородность?

Прежде всего, чтобы результаты Graph Embedding выражали «структуру» сети, в процессе случайного блуждания нам нужно сделать процесс блуждания более склонным к BFS (поиск в ширину, поиск в ширину) , т.к. BFS будет больше Выполнение проходного обхода в окрестности текущего узла во многих местах эквивалентно "микросканированию" структуры сети вокруг текущего узла. Независимо от того, является ли текущий узел «локальным центральным узлом», «пограничным узлом» или «узлом подключения», количество и порядок узлов, содержащихся в сгенерированной последовательности, должны быть разными, чтобы окончательное встраивание могло захватить больше структур. сексуальная информация.

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

Итак, как в алгоритме Node2vec контролировать тенденцию BFS и DFS? На самом деле, он в основном контролирует тенденцию перехода через вероятность перехода между узлами. На рис. 4 показана вероятность перехода алгоритма Node2vec с узла t на узел v, а затем с узла v на окружающие точки. Здесь следует обратить внимание на характеристики этих узлов. Например, узел t — это узел, посещенный случайным блужданием на предыдущем шаге, узел v — посещенный в настоящий момент узел, а узелx1,x2,x3х_1, х_2, х_3является узлом, отличным от t, соединенным с v, но узел x1 также соединен с узлом t. Эти разные характеристики определяют вероятность следующего скачка во время случайного блуждания.

clip_image014.jpg

Мы также можем выразить эти вероятности с помощью конкретных формул: вероятность перехода из текущего узла v в следующий узел xчисло Пиvx=альфаpq(t,x)wvxπ_{vx}=\alpha_{pq}(t,x)⋅w_{vx}wvxw_{vx}— исходный вес ребра vx,альфаpq(t,x)\alpha_{pq}(t,x)— это вес прыжка, определенный Node2vec. Склонен ли он к DFS или BFS, в основном связано с определением этого веса прыжка. Здесь мы сначала поймем его точное определение, а затем я объясню далее:

альфаpq(t,x)={1pеслиdtx=01еслиdtx=11qеслиdtx=2\alpha_{pq}(t,x)=\left\{ \begin{aligned} \frac{1}{p} \quad, если d_tx=0\\ 1 \quad, если d_tx=1\\ \frac{1} {q} \quad, если d_tx=2 \end{выровнено} \right.

альфаpq(t,x)\alpha_{pq}(t,x)внутреннийdtxd_{tx}Относится к расстоянию от узла t до узла x. Например, узел x1 на самом деле напрямую связан с узлом t, поэтому это расстояниеdtxd_{tx}равно 1, расстояние от узла t до самого узла tdttd_{tt}равен 0, а узлы x2 и x3, не связанные с t,dtxd_{tx}это 2.

также,альфаpq(t,x)\alpha_{pq}(t,x)Параметры p и q в вместе управляют склонностью к случайному блужданию. Параметр p называется возвращаемым параметром.Чем меньше p, тем больше вероятность случайного возврата к узлу t, и Node2vec уделяет больше внимания выражению структуры сети. Параметр q называется параметром входа-выхода. Чем меньше q, тем больше вероятность случайного перехода к удаленным узлам. Node2vec уделяет больше внимания выражению однородности сети. И наоборот, текущий узел с большей вероятностью будет блуждать по соседним узлам. Можно попробовать самому задать разные значения для p и q, и рассчитать скачок от v до t,x1,x2х_1, х_2иx3 x_3вероятность прыжка. Таким образом, нетрудно понять проблему тенденции случайных блужданий, которую я только что упомянул.

Характеристики гибкого выражения однородности и структуры Node2vec также были подтверждены экспериментами Мы можем заставить его давать разные результаты встраивания, регулируя параметры p и q. На рисунке 5 показано, что Node2vec уделяет больше внимания однородности.Из этого мы можем видеть, что цвета узлов с одинаковыми расстояниями ближе.Нижняя часть рисунка 5 представляет собой вариант, в котором больше внимания уделяется структуре, а цвет узлов с схожие структурные характеристики более похожи рядом.

clip_image018.jpg

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

Как встраивание применяется для разработки функций рекомендательных систем?

На данный момент мы изучили несколько основных методов встраивания, в том числе методы встраивания для данных последовательности, Word2vec и Item2vec, и методы встраивания для графических данных, Deep Walk и Node2vec. Так вы когда-нибудь думали,Почему я представил Embedding в модуле разработки функций? Как Embedding применяется к системе рекомендаций? Здесь я дам единый ответ.

  • На первый вопрос ответить несложно.Поскольку выход Embedding представляет собой числовой вектор признаков, саму технологию Embedding можно рассматривать как своего рода метод обработки признаков. Он просто отличается от простого горячего кодирования и других методов. Встраивание — это метод обработки признаков более высокого порядка, который позволяет интегрировать структуру последовательности, структуру сети и даже другие признаки в вектор признаков.

  • На второй вопрос есть три ответа, потому что есть примерно три способа применения встраивания в рекомендательной системе, а именно «прямое приложение», «приложение для предварительного обучения» и «приложение End2End».

Среди них «прямое применение» — самое простое, то есть после того, как мы получим вектор вложения, мы можем напрямую использовать подобие вектора вложения для реализации функций некоторых рекомендательных систем. Типичные функции: использование схожести между встраиваниями элементов для получения рекомендаций по похожим элементам, использование сходства между встраиваниями элементов и пользовательскими вложениями для достижения классических функций рекомендаций, таких как «угадай, что тебе нравится», а также использование встраивания элементов для достижения уровня отзыва в рекомендательная система и т.д.

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

Третье приложение называется «Приложение End2End». Похоже, что это новый термин, и его полное название «End to End Training», то есть сквозное обучение. Тем не менее, это не загадочно, это означает, что мы не проводим предварительное обучение встраиванию, а объединяем обучение встраиванию с рекомендательной моделью глубокого обучения, обучаем вместе унифицированным сквозным способом и напрямую получаем рекомендательную модель. содержащий слой внедрения. Этот метод очень популярен.Например, на рисунке 6 показаны три классические модели, содержащие слои внедрения, а именно Deep Crossing от Microsoft, FNN от UCL и Wide&Deep от Google.

clip_image020.jpg

clip_image022.jpg

Как сгенерировать Item2vec и встраивание графа с помощью Spark?

Пакет машинного обучения Spark Spark MLlib также содержит большое количество зрелых моделей машинного обучения, включая модель Word2vec, о которой мы говорили. Исходя из этого, мы завершим обучение Item2vec и Graph Embedding на основе Deep Walk на платформе Spark.

Студенты, знакомые с другими платформами машинного обучения, могут спросить: TensorFlow и PyTorch имеют мощные наборы инструментов для глубокого обучения. Можем ли мы использовать эти платформы для обучения встраиванию? Конечно, это возможно.Тем не менее, как собственная платформа распределенных вычислений, Spark по-прежнему имеет больше преимуществ, чем платформы глубокого обучения, такие как TensorFlow, при обработке больших данных, и многие компании в отрасли по-прежнему используют Spark для обучения некоторых моделей машинного обучения с относительно простыми структурами. продолжайте использовать Spark, чтобы завершить практику встраивания.

Во-первых, давайте посмотрим, как завершить обучение Item2vec.

Item2vec: Обработка данных последовательности

Мы знаем, что Item2vec основан на модели обработки естественного языка Word2vec, поэтому Item2vec должен работать с данными последовательности, такими как текстовые предложения и последовательности просмотра фильмов. Прежде чем приступить к обучению Item2vec, нам также необходимо подготовить данные последовательности для обучения. В наборе данных MovieLens есть таблица данных под названием рейтинг, которая содержит рейтинг пользователя и время просмотра просмотренного фильма. Теперь, когда доступны время и история оценок, последовательность просмотра, которую мы хотим использовать, может быть получена путем обработки таблицы оценок.

clip_image024.jpg

Однако нам нужно прояснить еще два вопроса, прежде чем использовать кодирование последовательности просмотра фильмов. Во-первых, рейтинговая таблица MovieLens — это, по сути, рейтинговая таблица, а не настоящая «последовательность фильмов». Но пользователи, разумеется, могут оценить его только после просмотра фильма, так что мы можем трактовать последовательность оценок почти как последовательность просмотра фильма. Во-вторых, должны ли мы помещать все фильмы в последовательность или только те, у которых более высокий рейтинг?

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

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

Итак, как именно этот процесс должен быть реализован в Spark? На самом деле, это очень просто, нам нужно только понять эти 5 ключевых шагов, чтобы достичь этого:

  1. Чтение необработанных данных рейтингов на платформу Spark;

  2. Используйте оператор where для фильтрации записей с низкими оценками;

  3. Используйте операцию groupBy userId для агрегирования записей оценок каждого пользователя, каждая запись в DataFrame представляет собой последовательность оценок пользователя;

  4. Определите пользовательскую операцию sortUdf, используйте ее для сортировки записей рейтинга каждого пользователя по отметке времени;

  5. Запись результатов каждого пользователя преобразуется в строку для использования в последующем процессе обучения.

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

def processItemSequence(sparkSession: SparkSession): RDD[Seq[String]] ={

 //设定rating数据的路径并用spark载入数据

 val ratingsResourcesPath = this.getClass.getResource("/webroot/sampledata/ratings.csv")

 val ratingSamples = sparkSession.read.format("csv").option("header", "true").load(ratingsResourcesPath.getPath)
 //实现一个用户定义的操作函数(UDF),用于之后的排序

 val sortUdf: UserDefinedFunction = udf((rows: Seq[Row]) => {

  rows.map { case Row(movieId: String, timestamp: String) => (movieId, timestamp) }

   .sortBy { case (movieId, timestamp) => timestamp }

   .map { case (movieId, timestamp) => movieId }

 })
 //把原始的rating数据处理成序列数据

 val userSeq = ratingSamples

  .where(col("rating") >= 3.5) //过滤掉评分在3.5一下的评分记录

  .groupBy("userId")      //按照用户id分组

  .agg(sortUdf(collect_list(struct("movieId", "timestamp"))) as "movieIds")  
//每个用户生成一个序列并用刚才定义好的udf函数按照timestamp排序

  .withColumn("movieIdStr", array_join(col("movieIds"), " "))

//把所有id连接成一个String,方便后续word2vec模型处理
//把序列数据筛选出来,丢掉其他过程数据

 userSeq.select("movieIdStr").rdd.map(r => r.getAs[String]("movieIdStr").split(" ").toSeq)

В образцах последовательности оценок пользователя, сгенерированных этим кодом, форма каждого образца очень проста, это последовательность, состоящая из идентификаторов фильмов, например, ниже показана последовательность просмотра пользователем с идентификатором 11888:

296 380 344 588 593 231 595 318 480 110 253 288 47 364 377 589 410 597 539 39 160 266 350 553 337 186 736 44 158 551 293 780 353 368 858

Item2vec: Обучение модели

Теперь, когда данные для обучения готовы, пришло время ввести обучение модели. Весь процесс обучения написанному от руки Item2vec, должно быть, представляет собой относительно «сбойную» вещь, но, к счастью, Spark MLlib подготовил интерфейс модели Word2vec, чтобы мы могли легко вызывать его. Ниже я вставлю обучающий код, а затем проведу пошаговый анализ того, что делает каждая строка кода.

def trainItem2vec(samples : RDD[Seq[String]]): Unit ={

  //设置模型参数

  val word2vec = new Word2Vec()

  .setVectorSize(10)

  .setWindowSize(5)

  .setNumIterations(10)
   //训练模型

 val model = word2vec.fit(samples)

 //训练结束,用模型查找与item"592"最相似的20个item

 val synonyms = model.findSynonyms("592", 20)

 for((synonym, cosineSimilarity) <- synonyms) {

  println(s"$synonym $cosineSimilarity")

 }

 //保存模型

 val embFolderPath = this.getClass.getResource("/webroot/sampledata/")

 val file = new File(embFolderPath.getPath + "embedding.txt")

 val bw = new BufferedWriter(new FileWriter(file))

 var id = 0

 //用model.getVectors获取所有Embedding向量

 for (movieId <- model.getVectors.keys){

  id+=1

  bw.write( movieId + ":" + model.getVectors(movieId).mkString(" ") + "\n")

 }

 bw.close()

Из приведенного выше кода видно, что процесс обучения модели Spark Word2vec очень прост и может быть завершен всего четырьмя или пятью строками кода. Далее я разберу для вас 3 ключевых шага по порядку сверху вниз.

  • Первый — создать модель Word2vec и задать параметры модели. Нам нужно уточнить, что есть 3 ключевых параметра модели Word2vec, а именно: setVectorSize, setWindowSize и setNumIterations. Среди них setVectorSize используется для установки размера сгенерированного вектора Embedding, setWindowSize используется для установки размера скользящего окна для выборки данных последовательности, а setNumIterations используется для установки количества итераций во время обучения. Конкретный выбор этих гиперпараметров должен быть скорректирован в соответствии с фактическим тренировочным эффектом.

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

  • Последний шаг — извлечь и сохранить вектор встраивания.Из последних нескольких строк кода видно, что вектор встраивания, соответствующий идентификатору фильма, можно извлечь, вызвав интерфейс getVectors, а затем их можно сохранить в файл или другая база данных, используемая другими модулями.

После завершения обучения модели давайте проверим, являются ли результаты обучения разумными. В моем коде я получаю похожие фильмы с идентификатором 592. Этот фильм называется Batman Batman, а аналогичные фильмы, полученные через Item2vec, я поместил ниже, вы можете интуитивно судить, является ли этот результат разумным.

clip_image026.jpg

Встраивание графика: подготовка данных

На данный момент, я полагаю, вы знакомы с реализацией метода Item2vec. Далее поговорим о методе внедрения графа на основе случайного блуждания и посмотрим, как использовать Spark для его реализации. Здесь мы выбираем метод Deep Walk для реализации. Рисунок 3:

clip_image027.jpg

В методе Deep Walk наиболее важными данными, которые нам нужно подготовить, является матрица вероятности перехода между элементами. Блок-схема алгоритма Deep Walk представлена ​​на рисунке 3. Матрица вероятности перехода выражает диаграмму отношений элементов на рисунке 3(b), которая определяет вероятность перехода от элемента A к элементу B в процессе случайного блуждания. Итак, давайте сначала посмотрим, как сгенерировать эту матрицу вероятности перехода с помощью Spark.

//samples 输入的观影序列样本集
def graphEmb(samples : RDD[Seq[String]], sparkSession: SparkSession): Unit ={
 //通过flatMap操作把观影序列打碎成一个个影片对
 val pairSamples = samples.flatMap[String]( sample => {
  var pairSeq = Seq[String]()
  var previousItem:String = null

  sample.foreach((element:String) => {
   if(previousItem != null){
    pairSeq = pairSeq :+ (previousItem + ":" + element)
   }
   previousItem = element
  })
  pairSeq
 })
 //统计影片对的数量
 val pairCount = pairSamples.countByValue()
 //转移概率矩阵的双层Map数据结构
 val transferMatrix = scala.collection.mutable.Map[String, scala.collection.mutable.Map[String, Long]]()
 val itemCount = scala.collection.mutable.Map[String, Long]()
 //求取转移概率矩阵
 pairCount.foreach( pair => {
  val pairItems = pair._1.split(":")
  val count = pair._2
  lognumber = lognumber + 1
  println(lognumber, pair._1)
  if (pairItems.length == 2){
   val item1 = pairItems.apply(0)
   val item2 = pairItems.apply(1)

  if(!transferMatrix.contains(pairItems.apply(0))){
    transferMatrix(item1) = scala.collection.mutable.Map[String, Long]()
   }

   transferMatrix(item1)(item2) = count
   itemCount(item1) = itemCount.getOrElse[Long](item1, 0) + count
  }

Входными данными для функции, формирующей матрицу вероятности перехода, являются данные последовательности просмотра, обработанные при обучении Item2vec. Выходом является матрица вероятности перехода.Поскольку матрица вероятности перехода относительно разрежена, я не использовал метод двумерного массива, который тратит память впустую, а использовал для его реализации двухслойную структуру Map. Например, если мы хотим получить вероятность перехода предмета A в предмет B, тогда TransferMatrix(itemA)(itemB) является этой вероятностью перехода.

В процессе получения матрицы вероятности перехода я сначала использую операцию Spark flatMap, чтобы «разбить» последовательность фильмов на пары фильмов, а затем использую операцию countByValue для подсчета количества этих пар фильмов и, наконец, вычисляю количество пар фильмов. на основе количества этих пар фильмов Возьмите вероятность перехода между каждыми двумя фильмами.

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

Встраивание графа: процесс выборки случайного блуждания

Процесс выборки случайного блуждания — это процесс генерации новых выборок последовательности с использованием матрицы вероятности перехода. Это как понять? Сначала нам нужно случайным образом выбрать начальный элемент в соответствии с распределением количества вхождений элемента, а затем войти в процесс случайного блуждания. В каждом блуждании мы находим вероятность перехода между двумя элементами по матрице вероятности перехода, а затем прыгаем в соответствии с этой вероятностью. Например, если текущим элементом является A, и из матрицы вероятности перехода установлено, что A может перейти к элементу B или элементу C, вероятности перехода равны 0,4 и 0,6 соответственно, тогда мы случайным образом идем к B или C в соответствии с этим вероятности, и действуем по очереди, спускаясь вниз до тех пор, пока длина выборки не будет удовлетворять нашим требованиям.

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

//随机游走采样函数
//transferMatrix 转移概率矩阵
//itemCount 物品出现次数的分布
def randomWalk(transferMatrix : scala.collection.mutable.Map[String, scala.collection.mutable.Map[String, Long]], itemCount : scala.collection.mutable.Map[String, Long]): Seq[Seq[String]] ={
 //样本的数量
 val sampleCount = 20000
 //每个样本的长度
 val sampleLength = 10
 val samples = scala.collection.mutable.ListBuffer[Seq[String]]()
 //物品出现的总次数
 var itemTotalCount:Long = 0
 for ((k,v) <- itemCount) itemTotalCount += v
 //随机游走sampleCount次,生成sampleCount个序列样本
 for( w <- 1 to sampleCount) {
  samples.append(oneRandomWalk(transferMatrix, itemCount, itemTotalCount, sampleLength))
 }

 Seq(samples.toList : _*)
}
//通过随机游走产生一个样本的过程
//transferMatrix 转移概率矩阵
//itemCount 物品出现次数的分布
//itemTotalCount 物品出现总次数
//sampleLength 每个样本的长度
def oneRandomWalk(transferMatrix : scala.collection.mutable.Map[String, scala.collection.mutable.Map[String, Long]], itemCount : scala.collection.mutable.Map[String, Long], itemTotalCount:Long, sampleLength:Int): Seq[String] ={
 val sample = scala.collection.mutable.ListBuffer[String]()
 //决定起始点
 val randomDouble = Random.nextDouble()
 var firstElement = ""
 var culCount:Long = 0
 //根据物品出现的概率,随机决定起始点
 breakable { for ((item, count) <- itemCount) {
  culCount += count
  if (culCount >= randomDouble * itemTotalCount){
   firstElement = item
   break
  }
 }}

 sample.append(firstElement)
 var curElement = firstElement
 //通过随机游走产生长度为sampleLength的样本
 breakable { for( w <- 1 until sampleLength) {
  if (!itemCount.contains(curElement) || !transferMatrix.contains(curElement)){
   break
  }
  //从curElement到下一个跳的转移概率向量
  val probDistribution = transferMatrix(curElement)
  val curCount = itemCount(curElement)
  val randomDouble = Random.nextDouble()
  var culCount:Long = 0
  //根据转移概率向量随机决定下一跳的物品
  breakable { for ((item, count) <- probDistribution) {
   culCount += count
   if (culCount >= randomDouble * curCount){
   		curElement = item
   	 	break
   }
  }}
  sample.append(curElement)
 }}
 Seq(sample.toList : _

После создания выборок sampleCount, необходимых для нашего обучения с помощью случайных блужданий, следующий процесс точно такой же, как и процесс Item2vec, который заключается в вводе этих обучающих выборок в модель Word2vec для завершения окончательного создания встраивания графа. Вы также можете использовать тот же метод для проверки эффекта внедрения, созданного методом внедрения графа. Что касается реализации Item2vec в Spark, следует обратить внимание на несколько параметров VectorSize, WindowSize, NumIterations и т. д. обучающей модели Word2vec, зная их соответствующие роли. Они используются для установки размерности вектора встраивания, размера скользящего окна для выборки данных последовательности и количества итераций во время обучения. При реализации Deep Walk мы должны сосредоточиться на понимании метода генерации матрицы вероятностей перехода между элементами и процесса генерации обучающих выборок посредством случайного блуждания.

clip_image029.jpg

Суммировать

Вышеупомянутое является релевантным знанием о встраивании слов, и вышеуказанный контент прошел практический тест.

Я тоже новичок в этой области, и если что не так, дайте пожалуйста инструкцию.

Если есть что-то, что вы не понимаете, вы можете прокомментировать, и мы можем обсудить и решить это вместе!

结尾.gif