图神经网络实战(4)——基于Node2Vec改进嵌入质量

图神经网络实战(4)——基于Node2Vec改进嵌入质量

    • 0. 前言
    • 1. Node2Vec 架构
      • 1.2 定义邻居
      • 1.2 在随机游走中引入偏向性
      • 1.3 实现有偏随机游走
    • 2. 实现 Node2Vec
    • 小结
    • 系列链接

0. 前言

Node2Vec 是一种基于 DeepWalk 的架构,DeepWalk 主要由随机游走和 Word2Vec 两个组件构成,Node2Vec 通过改进随机游走的生成方式改进嵌入质量。
在本节中,我们将学习这些改进以及如何为给定的图找到最佳参数,实现 Node2Vec 架构,并将其与在 Zachary's Karate Club 数据集上使用的 DeepWalk 进行比较,以理解两种架构之间的差异。

1. Node2Vec 架构

Node2VecGroverLeskovec2016 年提出,它保留了 DeepWalk 的两个主要组件:随机游走和 Word2Vec。不同之处在于, Node2Vec 中的随机游走不是使用均匀分布生成节点序列,而是进行了有偏处理。接下来,我们将了解为什么这些有偏随机游走表现更好,以及如何实现它们:

  • 定义邻居
  • 在随机游走中引入偏向性

1.2 定义邻居

Node2Vec 引入的关键概念是灵活的邻居概念。直观地说,我们认为邻居是与初始节点接近的节点,但在图中,应该如何定义“接近”呢?以下图为例:

示例图数据

我们希望探索节点 A 相邻的三个节点,该探索过程也称为采样策略 (sampling strategy):

  • 一种解是考虑在连接关系方面最接近的三个节点。在这种情况下,A 的邻居为 N ( A ) = { B , C , D } N(A) = \{B,C,D\} N(A)={B,C,D}
  • 另一种采用策略是首先选择与前一个节点不相邻的节点。在这种情况下,A 的邻居为 N ( A ) = { D , E , F } N(A) = \{D, E, F\} N(A)={D,E,F}

换句话说,在第一种情况下,需要执行广度优先搜索 (Breadth-First Search, BFS),而在第二种情况下,需要执行深度优先搜索 (Depth-First Search, DFS)。BFS 侧重于节点周围的局部网络,而 DFS 则建立了更宏观的图视图。
考虑到我们对邻居的直观定义,首先会想到舍弃 DFS。然而,Node2Vec 则认为这是种错误认知,其认为每种方法都捕捉到了网络的不同但有价值的表示。
将这些算法与以下两种网络属性联系起来:

  • 结构等价性 (Structural equivalence),这意味着如果节点共享许多相同的邻居,则它们在结构上是等效的。因此,如果它们共享许多邻居,则它们的结构等价性就更高
  • 同质性 (Homophily),表示相似的节点更有可能相互连接

Node2Vec 认为 BFS 是突出结构等效性的理想策略,因为该策略仅查看相邻节点。在这些随机游走序列中,节点经常重复出现并保持彼此接近。而 DFS 则通过创建远距离节点序列来强调非同质性。这些随机游走序列会采样距离源节点很远的节点,因此降低了代表性。因此,我们需要在这两种属性之间进行权衡:同质性可能更有助于理解某些图,反之亦然。
通常认为,结合同质性和结构等价性的图是理想的解决方案,因此,我们希望使用这两种采样策略来创建数据集。接下来,我们使用它们来生成随机游走序列。

1.2 在随机游走中引入偏向性

我们已经知道,随机游走是在图中随机选择的节点序列,通过使用一个给定起点(也可以是随机的)和一个预定义的长度创建。在这些图中经常出现在一起的节点就像句子中经常出现在一起的单词一样:根据同质性假设,它们具有相似的含义,因此也具有相似的表示。

Node2Vec 中,我们的目标是将这些随机游走的随机性偏向以下两者之一:

  • 提升与前一个节点没有连接的节点(类似于 DFS)
  • 提升与前一个节点相近的节点(类似于 BFS)

以下图为例,当前节点为 j j j,前一节点为 i i i,特征节点为 k k k。从节点 j j j 到节点 k k k 的非归一化转移概率 π j k \pi_{jk} πjk,该概率可以分解为 π j k = a ( i , k ) ⋅ w j k \pi_jk= a( i, k)\cdot w_{jk} πjk=a(i,k)wjk, 其中 a ( i , k ) a(i , k) a(i,k) 是节点 j j j k k k 之间的搜索偏置 (search bias), w j k w_{jk} wjk j j j k k k 的边的权重。

示例图

DeepWalk 中,对于任意一对节点 a a a b b b,它们之间的边权重 a ( a , b ) = 1 a(a,b)=1 a(a,b)=1。在 Node2Vec 中, a ( a , b ) a( a, b) a(a,b) 的值是根据节点间的距离和两个附加参数定义的:回退参数 p 和进出参数 q,分别用于近似 DFSBFS a ( a , b ) a(a, b) a(a,b) 值的定义如下:
a ( a , b ) = { 1 p d a b = 0 1 d a b = 1 1 q d a b = 2 a(a, b)=\begin{cases} \frac 1 p & d_{ab}=0\\ 1 & d_{ab}=1\\ \frac 1 q & d_{ab}=2\\ \end{cases} a(a,b)= p11q1dab=0dab=1dab=2
其中, d a b d_{ab} dab 是节点 a a a b b b 之间的最短路径距离,可以按如下方式更新上图中的非归一化转移概率:

更新非归一化转移概率

在非归一化转移概率中:

  • 回到前一个节点 i i i 的概率由参数 p p p 控制,参数 p p p 越大,随机游走就会越趋向于探索新的节点,而不是重复相同的节点,看起来就像 DFS
  • 前往 k 1 k_1 k1 的非归一化概率为 1,因为该节点是前一个节点 i i i 的直接邻居
  • 到达节点 k 2 k_2 k2 的概率由参数 q q q 控制,参数 q q q 越大,随机游走就越集中在与前一个节点相近的节点上,看起来就像 BFS

为了理解这些概念,最好的办法就是实际实现这一架构,并对参数进行调整。接下来,我们在 Zachary’s Karate Club 数据集上实现此架构。需要注意的是,该图是一个非加权网络,因此转移概率仅由搜索偏置决定。

1.3 实现有偏随机游走

首先,需要创建一个函数,根据前一个节点、当前节点以及参数 p p p q q q 随机选择图中的下一个节点。

(1) 导入所需的库,并创建图:

import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
# Create graph
G = nx.erdos_renyi_graph(10, 0.3, seed=1, directed=False)# Plot graph
plt.axis('off')
nx.draw_networkx(G, pos=nx.spring_layout(G, seed=0))
plt.show()

随机图

(2) 用参数列表定义 next_node() 函数:

def next_node(previous, current, p, q):

(3) 检索当前节点的邻居节点列表,并初始化 alpha 值列表:

    alphas = []# Get the neighboring nodesneighbors = list(G.neighbors(current))

(4) 对于每个邻居,都要计算出相应的 alpha 值:如果该邻居是前一个节点,则为 1 p \frac1 p p1;如果该邻居与前一个节点相连,则为 1 1 1;否则为 1 q \frac 1 q q1

    # Calculate the appropriate alpha value for each neighborfor neighbor in neighbors:# Distance = 0: probability to return to the previous nodeif neighbor == previous:alpha = 1/p# Distance = 1: probability of visiting a local nodeelif G.has_edge(neighbor, previous):alpha = 1# Distance = 2: probability to explore an unknown nodeelse:alpha = 1/qalphas.append(alpha)

(5) 对这些值进行归一化处理,得出概率:

    probs = [alpha / sum(alphas) for alpha in alphas]

(6) 根据上一步计算出的转换概率,使用 np.random.choice() 随机选择下一个节点并返回:

    next = np.random.choice(neighbors, size=1, p=probs)[0]return next

在测试该函数之前,需要编写整个随机游走的代码。随机游走的代码与我们在 DeepWalk 一节中实现的代码类似。不同的是,下一个节点由 next_node() 函数选择,该函数需要额外的参数:pq,以及上一个节点和当前节点。这些节点可以通过查看添加到 walk 变量中的最后两个元素轻松获得,出于兼容性考虑,函数返回字符串而不是整数。
改进后的 random_walk() 函数如下:

def random_walk(start, length, p, q):walk = [start]for i in range(length):current = walk[-1]previous = walk[-2] if len(walk) > 1 else Nonenext = next_node(previous, current, p, q)walk.append(next)return walk

调用 random_walk()函数,生成长度为 5、p=1q=1` 的随机游走序列:

print(random_walk(0, 8, p=1, q=1))

函数返回序列如下所示:

[0, 9, 1, 0, 1, 0, 4, 3, 6]

该序列是随机的,因为每个相邻节点都有相同的转换概率。

接下来,令算法偏向于回到前一个节点,即 q=10

print(random_walk(0, 8, p=1, q=10))

函数返回序列如下所示:

[0, 9, 1, 0, 1, 9, 0, 1, 2]

可以看到,随机游走探索了图中更多的节点。接下来,使用 p=10 调用函数,由于其概率很低,所以不会返回到之前的节点:

print(random_walk(0, 8, p=10, q=1))

函数返回序列如下所示:

[0, 9, 4, 6, 5, 4, 9, 0, 1]

接下来,我们在实际应用中使用这些属性,并将其与 DeepWalk 进行比较。

2. 实现 Node2Vec

现在,我们已经实现了生成有偏随机游走的函数,Node2Vec 的实现与 DeepWalk 相似,我们可以重复使用相同的代码,并使用 p = 1q = 1DeepWalk 作为 Node2Vec 的一个特例,我们重用 Zachary’s Karate Club 数据集实现 Node2Vec 架构。
我们的目标是将俱乐部的每位成员归类为正确的类别 (“Mr. Hi” 和 “Officer”),使用 Node2Vec 输出的节点嵌入作为机器学习分类器(本节中使用随机森林)的输入。

(1) 首先,在 shell 中使用 pip 命令安装 gensim 库以使用 Word2Vec

pip install gensim

(2) 导入所需的库:

from gensim.models.word2vec import Word2Vec
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

(3) 加载 Zachary’s Karate Club 数据集:

G = nx.karate_club_graph()

(4) 将节点标签转换为数值 (01):

# Process labels (Mr. Hi = 0, Officer = 1)
labels = []
for node in G.nodes:label = G.nodes[node]['club']labels.append(1 if label == 'Officer' else 0)

(5) 指定参数 p=3q=2 调用 random_walk() 函数为图中的每个节点生成 80 个随机游走列表:

walks = []
for node in G.nodes:for _ in range(80):walks.append(random_walk(node, 10, 3, 2))

(6) 使用分层 softmax 函数创建一个 Word2Vec (skip-gram 模型)实例:

node2vec = Word2Vec(walks,hs=1,   # Hierarchical softmaxsg=1,   # Skip-gramvector_size=100,window=10,workers=2,min_count=1)

(7) 在生成的序列上对 skip-gram 模型进行 30 次训练:

node2vec.train(walks, total_examples=node2vec.corpus_count, epochs=30, report_delay=1)

(8) 创建掩码训练并测试分类器:

train_mask = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
test_mask = [0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33]
labels = np.array(labels)

(9) 在训练数据上训练随机森林分类器:

clf = RandomForestClassifier(random_state=0)
clf.fit(node2vec.wv[train_mask], labels[train_mask])

(10) 在测试数据集上使用准确率作为评估模型性能的度量标准:

y_pred = clf.predict(node2vec.wv[test_mask])
acc = accuracy_score(y_pred, labels[test_mask])
print(f'Node2Vec accuracy = {acc*100:.2f}%')
# Node2Vec accuracy = 95.45%

要实现 DeepWalk,我们可以在 p = 1q = 1 的情况下重复完全相同的过程。但是,为了进行公平的比较,我们不能使用单次实验的准确率,因为这其中涉及很多随机过程,可能会出现从最差的模型中得到更好的结果。
为了限制结果的随机性,我们可以重复此过程 100 次,然后取平均值。这样的结果会稳定得多,也可以使用标准差 (np.std()) 来测量准确率的变化。
我们已经知道,Zachary’s Karate Club 是一个具有同质性的网络。这种特性通过 DFS 得到了强调,而增加参数 p 可以鼓励 DFS。假如这一说法和 DFS 与同质性之间的联系是正确的,那么 p 值越大就能够获得更好的结果。
对参数 p 和q在 17 之间重复进行同样的实验。在实际的机器学习项目中,我们会使用验证数据进行参数搜索,在本例中,我们将模型直接作为最终应用,因此直接使用测试数据。结果总结如下表所示:

模型性能对比

从上表中,可以看出:

  • DeepWalk(p = 1,q = 1) 的性能比表中其他 pq 组合都要差。这证明了有偏随机游走对于该数据集而言的有效性,但情况并非总是如此,在其他数据集上,无偏随机游走也可能表现得更好
  • p 值越高,性能越好,这也与我们的假设完全吻合。在社交网络中,通常可以将随机游走偏向于同质性。

我们可以通过调整参数观察使用不同参数时的结果。例如,我们可以探索 p 值较高 (> 7) 时的情况,或者 p 值和 q 值较低(介于 01 之间)时的情况。

小结

在本节中,我们了解了 Node2Vec,这是一种基于 Word2Vec 的架构。我们实现了有偏随机游走,并解释了其参数与两个网络属性(同质性和结构等价性)之间的联系。通过比较 Node2VecDeepWalkZachary's Karate Club 数据集上的性能表现,验证了有偏随机游走的有效性。

系列链接

图神经网络实战(1)——图神经网络(Graph Neural Networks, GNN)基础
图神经网络实战(2)——图论基础
图神经网络实战(3)——基于DeepWalk创建节点表示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/734407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt 格式化打印 日志 QMessagePattern 格式词法语法及设置

一、qt源码格式化日志 关键内部类 QMessagePattern qt为 格式化打印日志 提供了一个简易的 pattern(模式/格式) 词法解析的简易的内部类QMessagePattern,作用是获取和解析自定义的日志格式信息。 该类在qt的专门精心日志操作的源码文件Src\qtbase\src\corelib\global\qloggi…

[LeetCode][226]翻转二叉树

题目 226. 翻转二叉树 给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1] 示例 2: 输入:root [2,1,3] 输出&#x…

深度学习500问——Chapter02:机器学习基础(5)

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 2.14 贝叶斯分类器 2.14.1 图解极大似然估计 极大似然估计的原理,用一张图片来说明,如下图所示: 例:有两个外形完全相同的箱子,1号箱…

重学SpringBoot3-内容协商机制

重学SpringBoot3-内容协商机制 ContentNegotiationConfigurer接口配置内容协商URL参数Accept头使用Url扩展名 自定义内容协商格式步骤1: 注册自定义媒体类型步骤2: 实现HttpMessageConverter接口步骤3: 使用自定义HttpMessageConverter 注意点 在 Spring Boot 3 中,…

vue学习笔记21-组件传递数据_Props

组件与组件之间不是完全独立的&#xff0c;而是有交集的&#xff0c;那就是组件与组件之间是可以传递数据的 传递数据的解决方案就是props 父级&#xff1a; 在父级中引入子集 <template><h3>Parent</h3><Child/> </template><script> i…

GFP-GAN环境搭建推理测试

引子 近期&#xff0c;文生图&#xff0c;wav2lip很火&#xff0c;文生图&#xff0c;见识的太多&#xff0c;不多说了。wav2lip其通过语音驱动唇部动作并对视频质量进行修复&#xff0c;里面一般涉及到三个步骤&#xff0c;文本到语音转化&#xff0c;语音驱动唇部动作&#…

【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)

前言&#xff1a; 本文知识点&#xff1a; 1. C/C内存分布2. C语言中动态内存管理方式3. C中动态内存管理4. operator new与operator delete函数 5. new和delete的实现原理 &#xff08;干货在此&#xff09; 6. 定位new表达式(placement-new)7. 常见面试题 目录 C/C内…

Java反射、枚举类和lambda表达式

前言&#xff1a; 本章我们就来了解Java中的反射和枚举类。枚举类和反射其实有些关系&#xff0c;接下来我们就来学习他们的使用。 反射&#xff1a; 反射的作用&#xff1a; 反射&#xff1a;反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问。 Java中有…

CVE-2021-31440:eBPF verifier __reg_combine_64_into_32 边界更新错误

文章目录 前言漏洞分析构造 vuln reg 漏洞利用漏洞修复参考 前言 影响版本&#xff1a;Linux 5.7 ~ 5.11.20 8.8 编译选项&#xff1a;CONFIG_BPF_SYSCALL&#xff0c;config 所有带 BPF 字样的编译选项。General setup —> Choose SLAB allocator (SLUB (Unqueued Allocat…

从0到1手把手实现RPC|01 RpcProvider本地实现

RPC的简化版原理如下图&#xff08;核心是代理机制&#xff09;。 1.本地代理存根: Stub2.本地序列化反序列化3.网络通信4.远程序列化反序列化5.远程服务存根: Skeleton6.调用实际业务服务7.原路返回服务结果8.返回给本地调用方 注意处理异常。 RpcProvider的本地实现 1、工…

xss.haozi.me靶机 通关

0x00 没有任何过滤可以直接注入<img srcx οnerrοralert(1)> 0x01 使用了testarea标签将我们的输入内容以普通的字符串进行展示 但是我们可以将标签进行闭合 </textarea><img srcx οnerrοralert(1)> 0x02 我们依然可以先闭合之后添加属性a" οncl…

Java17 --- SpringCloud之Consul

目录 一、consul的使用 1.1、主要功能 1.2、安装及运行 1.3、添加微服务到consul 1.3.1、8001微服务添加相关pom、配置文件、注解 1.3.2、80微服务添加相关pom、配置文件、注解 1.4、三个注册中心异同 1.5、consul进行分布式配置 1.5.1、修改8001的yml配置文件 1.5.2…

数字化运营在教育行业的技术架构实践总结

随着科技的不断进步和数字化时代的到来&#xff0c;教育行业也正面临着数字化转型的挑战和机遇。教育行业的数字化运营需要依靠合理的技术架构来支撑&#xff0c;本文将探讨教育行业数字化运营的技术架构设计。 ## 第一步&#xff1a;需求分析和架构设计 在构建教育行业数字化…

SpringMVC08、Json

8、Json 8.1、什么是JSON&#xff1f; JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式&#xff0c;目前使用特别广泛。采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和…

LeetCode 173.二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在…

探索机器学习的无限可能性:从初学者到专家的旅程

探索机器学习的无限可能性&#xff1a;从初学者到专家的旅程 在当今数字时代&#xff0c;机器学习无疑是最引人注目的技术之一。它已经深入到我们生活的方方面面&#xff0c;从个性化推荐到自动驾驶汽车&#xff0c;再到医疗诊断和金融预测。但是&#xff0c;即使我们已经见证…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:RotationGesture)

用于触发旋转手势事件&#xff0c;触发旋转手势的最少手指为2指&#xff0c;最大为5指&#xff0c;最小改变度数为1度。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 接口 RotationGesture(value?: …

三、N元语法(N-gram)

为了弥补 One-Hot 独热编码的维度灾难和语义鸿沟以及 BOW 词袋模型丢失词序信息和稀疏性这些缺陷&#xff0c;将词表示成一个低维的实数向量&#xff0c;且相似的词的向量表示是相近的&#xff0c;可以用向量之间的距离来衡量相似度。 N-gram 统计语言模型是用来计算句子概率的…

docker 子网

当需要给容器分配指定 ip &#xff0c;为避免ip 冲突&#xff0c;指定容器子网处理 创建 subnet 子网 docker network create --subnet 10.0.0.0/24 --gateway 10.0.0.1 subnet-testdocker network ls NETWORK ID NAME DRIVER SCOPE ... f582ecf297bc sub…

vs2022的下载及安装教程(Visual Studio 2022)

vs简介 Visual Studio在团队项目开发中使用非常多且功能强大&#xff0c;支持开发人员编写跨平台的应用程序;Microsoft Visual C 2022正式版(VC2022运行库)&#xff0c;具有程序框架自动生成&#xff0c;灵活方便的类管理&#xff0c;强大的代码编写等功能&#xff0c;可提供编…