【Neo4j】第 10 章:图嵌入 - 从图到矩阵

 大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流

个人主页-Sonhhxg_柒的博客_CSDN博客 

欢迎各位→点赞 + 收藏⭐️ + 留言​

系列专栏 - 机器学习【ML】 自然语言处理【NLP】  深度学习【DL】

​​

 foreword

✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。

如果你对这个系列感兴趣的话,可以关注订阅哟

文章目录

技术要求

为什么我们需要嵌入?

为什么需要嵌入?

One-hot encoding

为文字创建特征——手动方式

Embedding specifications

The graph embedding landscape

基于邻接的嵌入

邻接矩阵和图拉普拉斯算子

特征向量嵌入

局部线性嵌入

基于相似性的嵌入

高阶邻近保留嵌入 (HOPE)

使用 Python 计算节点嵌入

创建一个networkx图

拟合节点嵌入算法

从人工神经网络中提取嵌入

简而言之,人工神经网络

关于神经网络原理的提醒

不同类型的神经网络

Skip-graph模型

假任务

输入

隐藏层

输出层

DeepWalk 节点嵌入

通过随机游走生成节点上下文

从 GDS 生成随机游走

使用 karateclub 嵌入 DeepWalk

Node2vec,DeepWalk 的替代方案

来自 GDS 的 Node2vec (≥ 1.3)

图神经网络

扩展 CNN 和 RNN 的原理以构建 GNN

消息传播和聚合

考虑节点属性

GNN 的应用

图像分析

文本分析

还有更多...

在实践中使用 GNN

来自 GDS 的 GNN – GraphSAGE

用图算法走得更远

最先进的图算法

概括

问题

进一步阅读


在本章中,我们将继续探索图分析的主题并解决最后一个难题:通过嵌入通过图进行特征学习。由于自然语言处理NLP ) 中使用的词嵌入,嵌入变得流行。在本章中,我们将首先讨论为什么嵌入很重要,并了解术语图嵌入所涵盖的不同类型的分析。之后,我们将开始从许多基于图邻接矩阵的算法中学习嵌入算法,试图减小其大小。

稍后,我们将通过发现神经网络如何帮助嵌入来继续我们的旅程。从词嵌入的例子开始,我们将学习skip-gram模型,并使用DeepWalk算法绘制平行图。最后,在最后一节中,我们将讨论其他图嵌入技术,并用一些话来总结一种新的有前途的算法:图神经网络GNN )。

本章将涵盖以下主题:

  • 为什么我们需要嵌入?
  • 基于邻接的嵌入
  • 从人工神经网络中提取嵌入
  • 图神经网络
  • 用图算法走得更远

技术要求

在本章中,我们将使用以下技术和库:

  • Neo4j 和 GDS
  • Python (>= 3.6) 具有以下软件包(所有 pip 可安装):
  • Jupyter Notebooks(或 Jupyter Lab)
  • 熊猫、NumPy、Matplotlib
  • 网络x
  • 空手道俱乐部:https ://github.com/benedekrozemberczki/karateclub

本章中使用的代码可在 GitHub 上的https://github.com/PacktPublishing/Hands-On-Graph-Analytics-with-Neo4j/ch10/上找到。

为什么我们需要嵌入?

机器学习模型基于矩阵计算:我们的观察被组织成表格中的行,而特征是列或向量。将文本或图形等复杂对象表示为合理大小的矩阵可能是一项挑战。这是嵌入技术旨在解决的问题。

为什么需要嵌入?

在第 8 章,在机器学习中使用基于图的特征中,我们绘制了以下模式:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第1张图片

特征工程步骤涉及从我们的数据集中提取特征。当这个数据集由已经具有数值或分类特征的观察组成时,很容易想象如何根据这些特征构建特征。

但是,某些数据集没有这种表格结构。在这种情况下,我们需要在将数据集输入机器学习模型之前创建该结构。

以包含数千个单词的文本为例,例如一本书。现在想象一下,你的任务是从给定的单词中预测哪个单词更有可能出现。为了创建这个模型,我们需要找到一个机器学习模型,这样:

Model(Word) = Next Word

然而,机器学习模型,从线性回归到人工神经网络,都使用特征向量。因此,我们需要找到与每个V(Word)相关联的特征列表,然后将模型拟合到这些向量:

Model(V(Word)) = V(Next Word)

挑战在于找到一个好的 V。然而,在此之前,我们需要定义什么是好的V。

One-hot encoding

让我们考虑一下阿瑟·柯南·道尔(Arthur Conan Doyle )的小说《斯嘉丽的研究》中著名人物侦探福尔摩斯所说的以下引语:

在没有数据之前进行理论化是一个大错误。

首先,我们将通过删除不提供任何信息的单词来简化这句话,例如athe(在 NLP 中称为停用词)并删除动词的共轭形式:

在有数据之前就大写错误理论

在大多数情况下,我们还会对单词进行排序,比如说按字母顺序,并删除重复项,这样我们就可以对以下单词进行编码:

在大写日期之前有错误一论

为了用向量表示这个语料库的每个单词,我们可以使用 one-hot 编码技术。这涉及创建一个大小等于语料库中单词数量的向量,除了单词的索引处以外的所有地方都为零。如下图所示:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第2张图片

be这个词是我们语料库中的第一个词,所以表示这个词的向量除了第一个位置外,到处都是零,我们把1放在了那里。

使用这种技术意味着每个单词的特征与数据集中的单词数量一样多。在真实的文本分析应用程序中,语料库可以包含数万个单词,因此,正如您可以想象的那样,表示所讨论的整个数据集将是内存效率低下的。即使我们要利用数据稀疏性并使用稀疏矩阵表示,我们也可能陷入维数的诅咒。

当观察的数量无法覆盖整个特征空间时,就会出现这个问题。假设您有一个特征X,其值均匀分布在 0 和 10 之间。如果您希望每个大小为 1 的 bin 有一个点,您将需要大约 10 个观察值。如果您添加另一个具有相同分布的特征Y并希望覆盖由XY组成的完整 2D 平面,这意味着在每个大小为 1×1 的正方形中至少有一个点,那么您将需要 100 次观察。随着您添加更多功能,这个数字会继续增长,直到您无法收集那么多观察结果。

这就是嵌入的用武之地。嵌入技术允许我们为每个单词找到一个向量表示,涉及的维度少于单词的总数。以保留有关初始数据集的关键信息(例如词义)的方式选择特征。

为文字创建特征——手动方式

在文本语料库中,每个观察对应一个词,我们需要为每个观察找到并量化特征。创建特征是有意义的,这样代表相似概念的单词将具有相似的特征。作为第一个例子,让我们考虑星球大战电影中的一些角色。

我们可以尝试找到每个角色的特征列表。在这里,确定了三个特征:性别、物种和善(0 代表坏,1 代表好)。利用这三个特征,我们可以构建下表:

特点 性别 物种 善良
Darth Vader 1 1 0
Yoda 1 2 1
Princess Leia 0 1 1
R2D2 1 3 1

达斯维德是一个来自原力黑暗面的人——传奇中的坏人,而莱娅和尤达则属于光明面——好人。虽然达斯维达和莱娅都是人类,但 R2D2 是机器人,而尤达来自外星物种。

我们可以对其他类别的单词进行相同的练习。例如,让我们将颜色视为特征。如果我们选择三个特征——红色、绿色和蓝色,我们可以使用下表来表示它们:

Color Redness Greenness Blueness
Red 1 0 0
Green 0 1 0
Blue 0 0 1
White 1 1 1
Yellow 1 1 0
Black 0 0 0
Orange 1 0.6 0
Violet 0.9 0.5 0.9

第一列(特征)编码每种颜色的红色程度,而第二和第三列提供有关其绿色和蓝色的信息。

在这个例子中,我们看到了单词表示的另一个有趣的方面。我们可以通过使用例如点积来测量两个实数向量的接近程度。因此,我们可以使用上表中的向量表示来衡量红色蓝色的接近程度:

V(Red) . V(Blue) = (1, 0, 0) . (0, 0, 1) = 0

紫色蓝色之间的接近度要高得多:

V(Violet) . V(Blue) = (0.9, 0.5, 0.9) . ——(0, 0, 1) = 0.9

我们对颜色的矢量表示告诉我们,蓝色红色更接近紫罗兰色。因此,这种表示看起来不错,因为它还带有一些关于单热编码无法看到的颜色的信息。实际上,两个 one-hot 编码向量的点积将返回 1(当向量相同时)或 0(当向量不同时),从而隐藏它们之间的任何差异。

现在我们有两组特征:一侧是 [ Redness , Greenness , Blueness ],另一侧是 [ Gender , Species , Goodness ]。我们可以将它们合并成一个完整的集合 [ Redness , Greenness , Blueness , Gender , Species , Goodness ]:

Word Redness Greenness Blueness Gender Species Goodness
Red 1 0 0 0 0 0
Darth Vader 0 0 0 1 1 0

我们也知道尤达有一定的绿色,所以我们可以为他填写颜色特征:

Word Redness Greenness Blueness Gender Species Goodness
Yoda 0.4 0.6 0.3 0 0 0

本节让您了解我们希望特征在表示单词时如何出现。如您所见,手动构建特征来表示语料库中的所有单词是不可行的。但是,我们已经讨论了相似性的重要概念:嵌入不会返回随机数,而是以某种方式编码实体之间的相似性(此处为单词)。

现在,让我们继续学习嵌入技术如何解决我们的问题。

Embedding specifications

嵌入的目标是将单词编码为维度为d « N的向量V(word),从而以某种方式保留单词的含义。因此,从表示单词的 one-hot 编码矩阵开始,我们希望得到一个大小为N×d的矩阵,其中d很小,如下图所示:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第3张图片

然而,到目前为止,我们所做的只是减少了特征的数量。下图说明了保留单词含义的实际含义:

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第4张图片

该图显示了四个单词——孩子年轻老人每个单词都由二维向量表示。这些向量相互关联,如下式所示:

V(儿童) - V(年轻) + V(老) ≈ V(老人)

这意味着,如果您获取表示单词child的向量并从中删除表示单词young的向量,您将得到一个表示没有年龄的人的中间向量。如果您将单词old的向量表示添加到此向量中,那么您必须找到表示老年人的向量。

换句话说,嵌入不仅减少了描述实体所需的特征数量,而且还对问题的某些部分进行了编码,使得真实数据集中的两个紧密实体在嵌入空间中也很接近。因此,在谈论嵌入时,相似性的概念非常重要;衡量两个实体的相似程度至关重要,在预测问题中使用时,实体表示不良将导致结果不佳。

文本是一长串单词,而图形即使不是连续的,也是一长串节点,通过边相互连接。由于图由多个实体组成,一侧的节点和另一侧的边,图嵌入实际上可以指代几种类型的算法,具体取决于被编码的实体。

The graph embedding landscape

在前两章中,我们看到了如何将传统的机器学习管道应用于图,使用节点或边作为观察值。我们已经讨论了如何根据一些节点属性和图结构(社区、节点重要性、邻域)创建表示节点和边的特征。

图包含两种不同类型的对象,节点和边,两者都可以是给定分析的感兴趣实体并表示为向量。在第 8 章,在机器学习中使用基于图的特征中,我们对节点感兴趣并研究了如何执行一些节点分类。与文本类似,我们可以使用邻接矩阵创建图的N×N矩阵表示,其中N是节点数。但是,能够在保留图结构的同时找到节点表示的低维向量将非常有用。

在第 9 章,预测关系中,我们的观察结果是边缘。使用包含节点之间所有可能边的矩阵对边进行建模将具有N 2 个元素。

回顾一下,图嵌入涵盖了三种类型的算法:

  • 节点嵌入:嵌入的对象是节点,因此算法为每个节点创建一个向量。这可以用于节点分类问题。
  • 边缘嵌入:在这里,我们使用边缘作为主要实体,并尝试像我们在上一章(第 9 章,预测关系)中使用 Adamic-Adar 分数手动为它们分配一个向量。
  • 全图嵌入:最后,还有另一个嵌入应用程序,其中整个图可以表示为单个向量。全图嵌入的一种应用是小图分析(例如分子,其中原子是通过化学键相互连接的节点)。研究图随时间的演变可能很有用,而全图嵌入可以为我们提供有关图动态的信息。
许多作者会使用术语图嵌入来指代节点嵌入,因此如果您经常遇到这个术语,请不要感到惊讶。

在本章的其余部分,我们将重点介绍最常见的图嵌入算法,即节点嵌入问题。在此之前,让我们关注主要的词嵌入方法,因为这将有助于我们在将其应用于图形之前理解该概念。

基于邻接的嵌入

图可以很容易地表示为大矩阵。我们要研究的第一个可以减小这个矩阵大小的技术叫做矩阵分解

邻接矩阵和图拉普拉斯算子

与文本分析类似,图形可以用一个非常大的矩阵来表示,该矩阵对节点之间的关系进行编码。我们在前面的章节中已经使用过这样的矩阵——邻接矩阵,在下图中命名为M :

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第5张图片

其他算法依赖于图拉普拉斯矩阵L = D - M其中D是包含每个节点度的对角矩阵。但原则保持不变。

特征向量嵌入

减小矩阵大小的一种简单方法是将其分解为特征向量,并仅使用数量减少的这些向量作为嵌入。

使用图形定位时可以看到这种图形表示的示例。实际上,在二维平面上绘制图形是一种嵌入。可以找到其中一种定位技术,它包括networkx将spectral_layout拉普拉斯矩阵分解为其特征向量。

局部线性嵌入

局部线性嵌入LLE ) 假设节点n i的向量表示,我们称之为Vi,必须是i的邻居向量表示的线性组合,(i)。它被编码为以下等式,其中邻接矩阵由字母M表示:

V i = ∑ j∈N(i) M ij × V j

因此,找到一个嵌入被简化为一个优化问题,在这个问题中,您要找到向量V i,使得V i与其邻居的线性组合之间的距离尽可能小。用数学术语来说,我们最终会遇到一个最小二乘最小化问题,其中要最小化的函数如下:

Φ(V) = ∑ i ( V i - ∑ j∈N(i) M ij × V j )²

这个问题包含许多变量,因为未知变量是V i向量的分量——因此是N×d。然而,可以证明这个问题的解决方案是矩阵M' = (I -M) T. (IM)的前 d+1 个特征向量,因此,问题被简化为特征向量问题。

LLE 技术也可以在图上下文之外使用。通常,邻居是通过 k-最近邻居方法定义的,并且权重M ij在算法的第一阶段学习。

基于相似性的嵌入

如果我们无法对向量在嵌入空间中的样子做出任何假设,我们仍然可以假设它们需要保持某种相似性。

高阶邻近保留嵌入 (HOPE)

正如我们之前在使用向量表示的点积比较颜色之间的相似度时所做的那样,我们可以通过计算它们向量的点积来测量嵌入节点的相似度。但是,我们也可以使用其他启发式方法来测量节点相似度,例如我们在第 7 章社区检测和相似度度量中研究过的那些。Jaccard 或 Adamic-Adar 相似性是节点相似性度量的著名示例。

我们可以通过尝试使两个节点的向量相似性尽可能接近来构建节点嵌入。向量空间中的节点相似度由嵌入向量的点积Vi来衡量 。V j,而图中的节点相似度由评分函数S ij测量。可以使用任何相似性度量(例如 Adamic-Adar)来计算此评分函数。减少这两种措施之间的差异需要最小化以下功能:

Φ(V) = ∑ i,j ( V i . V j - S ij )²

在本节中,我们介绍了许多嵌入技术,但可以找到更多。在下一节中,我将介绍karateclub包含许多实现的 Python 包,以及相关论文的链接。

使用 Python 计算节点嵌入

节点嵌入算法通常由研究人员首先实施,他们试图找到在低维空间中表示图的新方法。有很多人使用不同的语言来研究这个主题。希望在使用图算法(例如嵌入 Python)时,我们可以找到旨在在一致的 API 下协调这些实现的包。其中,我们可以引用以下内容:

  • scikit-networks:在 scikit 工具箱中,它使用与 完全相同的 API scikit-learn,每个算法都有拟合/转换方法。图需要表示为邻接矩阵,使用稀疏矩阵numpy或scipy稀疏矩阵。
  • karateclub: 这使用了类似的 API,即使与 不完全相同scikit-learn,只是它基于networkx包及其图形表示。

即使在构造scikit-networks上更接近scikit-learnAPI,目前也只包含了几个嵌入算法;这就是为什么我们将karateclub在本节的其余部分中使用该包。由于karateclub基于networkx,我们的第一个任务是networkx从 Neo4j 图创建一个图对象。

不要将karateclub包与 karateclub 图混淆:karateclub 图是包含 34 个节点的示例图,而karateclub包包含可以在任何图上运行的图算法。

创建一个networkx图

有很多方法可以创建图形对象networkx,从导入边缘列表文件到读取 pandas DataFrame。在这里,我们想从 Neo4j 图表中输入它。因此,我们将使用networkx.from_pandas_edge_list,因为我们已经从前面的章节中知道如何从 Neo4j 创建 DataFrame。

Neo4j 测试图

在本节中,我们将使用著名的 Zachary 空手道俱乐部图(参见第 7 章,社区检测和相似性度量)。这是图社区中一个非常流行的图,并且可能启发了包的名称。在与本书相关的代码文件中提供了在 Neo4j 中创建此图的 Cypher 查询。

从 Neo4j 中提取边缘列表数据

从 Neo4j 中提取边列表非常简单,因为我们只需要两条信息:源节点和目标节点,它们通过关系链接在一起。考虑到我们的图是无向的,我们可以使用以下 Cypher 查询来提取通过LINK 类型关系链接在一起的节点对:

MATCH (n:Node)-[r:LINK]-(m:Node)
RETURN n.id as source, m.id as target

因此,与我们在前几章中所做的类似,我们可以使用 Neo4j Python 驱动程序提取这些数据:

from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", ""), encrypted=False)
with driver.session() as session:
    res = session.run("""
            MATCH (n:Node)-[r:LINK]-(m:Node)
            RETURN n.id as source, m.id as target
        """)

res然后可以利用结果对象来创建一个新的 DataFrame:

data = pd.DataFrame.from_records(res.data())

我们现在可以使用这个 DataFrame 来创建一个图,使用这个networkx结构。

从熊猫创建一个networkx图矩阵

我们刚刚创建的 DataFrame 的第一行在下图中重现:

                                        【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第6张图片

我们可以使用它来networkx使用以下函数创建图形:

import networkx as nx

G = nx.from_pandas_edgelist(data)
用作目标的列的名称是可配置的。在前面的代码中,我使用了默认值,但我可以编写以下命令:
G = nx.from_pandas_edgelist(data, source="source", target="target")

现在我们有了图形对象,我们可以在其上运行算法,例如节点嵌入。

拟合节点嵌入算法

例如,我们将运行 HOPE 嵌入算法。我们首先需要从以下位置导入它karateclub:

from karateclub import HOPE

然后,类似于我们对 的操作scikit-learn,我们可以创建模型实例:

hope = HOPE(dimensions=10)

该dimension参数给出了结果嵌入的大小d

创建模型后,可以将其拟合到networkx图上:

hope.fit(G)

为了从拟合模型中提取嵌入,我们需要使用以下get_embedding方法:

embeddings = hope.get_embedding()

我们在这里。您可以检查embeddings变量是否为大小为34节点数×10嵌入向量的维度)的矩阵

最后,我们可以尝试可视化嵌入向量。由于二维空间中的可视化更容易,因此对嵌入执行主成分分析PCA ) 以将其大小减小到2绘图之前:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第7张图片

 为了评估嵌入的质量,让我们绘制图形并让ground truth community出现:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第8张图片

如您所见,HOPE 嵌入在将图拆分为两个真实社区方面表现得非常好。聚类算法可以为我们提供有关此结果的一些有意义且更定量的指标,但我将把这项任务留给您(请参阅问题部分)。

该karateclub软件包包含更多算法以及相关论文的链接。我们现在要处理的可能是最著名的节点嵌入算法之一,它基于图中的随机游走。

从人工神经网络中提取嵌入

神经网络是机器学习模型的新黄金标准。由于这种结构,从图像分析到语音识别都取得了令人瞩目的进步,计算机现在能够执行越来越复杂的任务。神经网络的一个令人惊讶的应用是它们能够以更少的维度对复杂对象(例如图像、文本或音频记录)进行建模,同时仍保留原始数据集的某些方面(图像中的形状、音频中的频率等)上)。在本节中,在对神经网络进行快速一般性回顾之后,我们将关注一种称为 skip-gram 的架构,它首先用于词嵌入的上下文中,但也可以扩展到图。

简而言之,人工神经网络

人工神经网络受到人脑的启发,其中数百万个神经元通过突触相互连接。人脑显然擅长学习和识别。例如,一旦你看过一个松鼠的例子,你就可以识别出所有的松鼠,即使它们更小,颜色不同,或者摄像头角度不同:

关于神经网络原理的提醒

让我们回顾一下神经网络的一些基本原理,重点关注嵌入上下文中的相关内容。

神经元、层和前向传播

为了理解神经网络是如何工作的,让我们考虑一个简单的分类问题,它有两个输入特征x 1x 2,以及一个输出类O,其值可以是 0 或 1。

下图说明了一个可以用来解决这个问题的简单神经网络:

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第9张图片

神经网络有一个隐藏层,包括三个神经元(中间层)和输出层(最右边的层)。隐藏层的每个神经元都有一个权重向量w i,其大小等于输入层的大小。这些权重是我们将尝试优化的模型参数,以使输出接近真实情况。

当观察通过输入层输入网络时,会发生以下情况:

  1. 隐藏层的每个神经元接收所有输入特征。
  2. 隐藏层的每个神经元使用其权重向量和偏差计算这些特征的加权和。例如,隐藏层的第一个神经元的输出如下:

    h 1 = (x 1 , x 2 ) 。W 1 + b 1 = x 1 × w 11 + x 2 × w 12 + b 1
     
  3. 输出层还执行其输入的加权组合,这些输入是最后一个隐藏层的输出:

    o = (h 1 , h 2 , h 3 ) 。O + b O = h 1 × o 1 + h 2 × o 2 + h 3 × o 3 + b O
  4. 对数据集中的所有观察结果重复此过程。
  5. 计算误差度量或损失函数,比较网络输出和预期标签。基于此损失函数,调整隐藏层中的权重(反向传播)。
  6. 重复这个过程,直到损失函数不能再显着改善。

隐藏层可以链接在一起。在这种情况下,第i个隐藏层的输出是第 ( i +1)个隐藏层的输入,直到输出层。这使得这种结构高度可定制,并且根据目标,可以想象许多不同的层组合方式。

我不会详细介绍激活函数,即使它们是神经网络魔法的一部分,因为它们允许将非线性引入模型。检查进一步阅读部分以了解有关它们的更多信息。

不同类型的神经网络

根据您希望实现的目标,许多不同的神经网络架构都是可能的。每个架构都定义了自己的层以及它们如何转换输入值。最著名的神经网络类型如下:

  • 卷积神经网络CNN ):这些通常用于图像分析,并且在二维图像中查找形状方面非常有效。它们可用于:
  • 图像分类
  • 计算机的光学字符识别OCR ) 将显示文本的图像转换为可编辑的文本文档
  • 图像上的对象检测可以有应用,例如,在以下领域:
  • 用于乳腺癌检测的医疗保健
  • 自动驾驶汽车,需要了解其环境,部分使用来自车载摄像头的图像,以选择最佳轨迹
  • 循环神经网络RNN ):它们非常擅长分析数据序列,例如文本或时间序列。它们可用于以下应用:
  • 图片说明:找到一组最能描述图片的词
  • 情感分析:将文本分类为积极或消极的语气
  • 文本翻译:将文本从一种语言翻译成另一种语言

您还将在文献中找到对抗性神经网络,它可用于填充缺失数据以及更多应用。在本书的最后一部分,我们甚至会看到图如何通过 GNN 与神经网络相关联。

理解这些结构中的每一个都超出了本书的范围。我也没有在这里详细介绍损失函数、反向传播或梯度下降的概念,这些对于接下来的部分并不重要。如果您有兴趣了解有关神经网络架构和跳过图如何工作的更多信息,请参阅进一步阅读部分。

在下一节中,我们将专注于一种简单但功能强大的神经网络,它将帮助我们创建嵌入的skip-gram模型。

Skip-graph模型

人工神经网络包含一个或多个隐藏层。通常,网络学习到的隐藏层的权重值并不是特别有趣:它们只是模型的参数,我们只关心模型输出。例如,当使用 CNN 预测您的图像是狗还是猫时,您只想从模型中得到预测。嵌入正好相反;我们并不直接对模型输出感兴趣,而是对隐藏层学习到的权重感兴趣,也就是嵌入的词。

假任务

为了像任何其他机器学习模型一样训练神经网络,我们需要定义一个要完成的任务,即预测器的目标;例如,基于一些标签或文本翻译的分类。在嵌入场景中,我们对模型输出并不真正感兴趣,但我们仍然需要定义它以便训练神经网络。这就是为什么我们在这种情况下提到一个假任务。

在 skip-gram 模型中,假任务如下:给定一个单词,查看附近的单词并随机返回其中一个单词。选择这个任务是因为我们可以假设相似的词有相似的上下文——烹饪厨房厨房降落伞更可能是同一个句子的一部分。

在实践中,附近由一个数字N确定,并且目标单词周围大小为N的窗口内的所有单词都被认为在目标单词邻域中。

输入

让我们看一下训练数据集的形状,首先谈谈嵌入之前的单词表示。然后我们将关注模型目标的定义。

嵌入前的词表示

一种可能的方法是使用one-hot 编码器并创建一个大小为N×N的矩阵,其中N是文本中不同单词的数量,也称为字典。如本章第一节所述,每个矩阵元素的值为 0 或 1。

目标

请记住,我们的虚假任务是在单词周围给定大小的窗口内预测单词。所以我们的目标变量也是一个词,我们的训练集将由出现在同一上下文中的词对组成。这里的上下文由窗口的大小定义;窗口大小越大,我们的数据集就越大(我们可以创建更多对)。然而,如果窗口大小更大,我们会开始在训练集中获得更多不相关的数据,因为我们会得到彼此相距很远的成对单词。

让我们再次考虑一下福尔摩斯的名言:

在没有数据之前进行理论化是一个大错误。

考虑窗口大小为 2,我们将按以下方式创建数据集(见下图)。从输入的第一个单词开始,我们可以将其与 2 单词窗口中的所有单词配对。由于我们正在考虑文本的第一个单词,所以我们只能向右移动,遇到两个单词:isa。因此,我们创建了两个训练样本:( it , is ) 和 ( it , a )。通过移动到下一个单词is,我们可以将它与接下来的两个单词acapital配对,也可以与前一个单词it. 因此,我们可以创建三对训练样本,依此类推,直到最后一句话:【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第10张图片

 因此,当使用s=2的窗口大小时,生成的输入数据集将包含以下对:

(it, is)
(it, a)

(is, it)
(is, a)
(is, capital)

(a, it)
(a, is)
(a capital)
(a mistake)

...

元组的第一个元素是输入,而第二个元素是预期输出之一。由于我们的单词是 one-hot 编码的,因此真正的输入数据集将包含以下元素:

( (1, 0, 0, 0, 0, ...), (0, 1, 0, 0, 0, ...) )
( (1, 0, 0, 0, 0, ...), (0, 0, 1, 0, 0, ...) )
( (0, 1, 0, 0, 0, ...), (1, 0, 0, 0, 0, ...) )

隐藏层

skip-gram 神经网络架构包含一个隐藏层。该层中的神经元数量对应于嵌入空间的维度或降维后特征的数量d。下图说明了我们如何从隐藏层中的神经元权重(每个d个神经元的一个长度为N的向量,垂直向量)到词嵌入,长度为d的N个向量(右侧的水平向量):

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第11张图片

由于跳图网络只有一个隐藏层,计算流程的下一步是输出层。

输出层

记住我们的假任务:从输入单词中预测相同上下文(窗口)中的单词。这意味着我们不是在尝试执行二元分类(在关于神经网络的介绍部分中使用的示例),而是一个具有N个类别的分类,N是语料库中的单词数。因此,输出层包含N个值为 0 或 1 的神经元:如果索引i处神经元的值为 1,则词i是所选词,这意味着网络预测词i与输入词。在实践中,神经网络将使用 softmax 分类器,其中 softmax 函数给出概率与输入词在同一上下文中的词:

softmax(i) = e o i / Σ i e o i

在这个公式中,o i是输出层中第i个神经元的输出。

这是skip-gram背后的基本思想。在实践中,在实现这样的模型时需要注意:

  • 某些单词,例如the,将被过度表示,这使得它们更有可能出现在任何其他单词附近。
  • 随着语料库的大小,要优化的权重数量会快速增长(请记住,我们在隐藏层中有N×d权重)。

已经提出了通过使用子采样和负采样技术来处理这两个问题的解决方案。在这里深入了解这些细节超出了本书的范围,但是您将能够通过进一步阅读部分中列出的参考资料更深入地研究 skip-gram 模型。

现在我们对 skip-gram 模型以及如何使用它来创建词嵌入有了更好的理解,让我们回到图的上下文并讨论 DeepWalk 算法,这是一种基于 skip-gram 的节点嵌入技术。

DeepWalk 节点嵌入

DeepWalk 可能是最著名的节点嵌入算法之一,由Perozzi 等人于 2014 年开发。它的核心概念类似于我们在上一节中研究的词嵌入算法,使用随机游走图来生成句子。

通过随机游走生成节点上下文

在词嵌入场景中,我们通过在给定的窗口大小内将词与位于它附近的所有词配对来生成词上下文。但是,图不是顺序的,那么我们如何为节点生成上下文呢?解决方案是使用给定长度的随机游走图。

考虑下图中左侧的图表:

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第12张图片

从节点A开始,我们可以生成长度为 3 的路径,通过B然后C,或者从D开始并继续到F例如。此图中右侧表示的路径相当于文本分析上下文中的句子。使用这些节点序列,我们现在可以生成一个训练集并训练一个 skip-gram 模型。

在继续讨论 DeepWalk 之前,让我们从 GDS 中提取随机游走。

从 GDS 生成随机游走

在 GDS 中,可以通过以下方式使用过程生成通过投影图的随机游走gds.alpha.randomwalk(仍然使用前面部分中的 karateclub 图作为示例):

MATCH (n:Node {id: 1})
CALL gds.alpha.randomWalk.stream({
    nodeProjection: "*", 
    relationshipProjection: {
        LINKED_TO: {
            type: "LINK", 
            orientation: "UNDIRECTED"
        }
    }, 
    start: id(n),
    walks: 1,
    steps: 2
})
YIELD nodeIds
RETURN nodeIds

您可以识别我们之前已经遇到的参数,用于配置行走次数(这里等于1)和要执行的跳数(等于2前面的查询)。

上述查询的结果是类似于以下内容的节点 ID 列表:

╒═════════╕
│"nodeIds"│
╞═════════╡
│[1,317,285] │
└─────────┘

以下是提供skip-gram模型所需的句子。

在实践中,使用现有的实现会容易得多,它会为我们处理一切,从随机游走到神经网络训练。该karateclub软件包提出了这样的实现。

使用 karateclub 嵌入 DeepWalk

实际上,如果您使用的是 1.3 版本之前的 GDS,则尚未实现嵌入算法。要训​​练模型,您必须从 Neo4j 中提取数据。我们可以通过与karateclub上一节类似的方式对包执行此操作。例如,我们可以使用以下内容:

from karateclub import DeepWalk

dw = DeepWalk(walk_number=50, walk_length=15, dimensions=5

对于 DeepWalk 算法,除了嵌入空间d的维数之外,您还可以配置以下内容:

  • 从同一节点开始的步行次数
  • 每个生成路径的长度
  • 用于生成形成训练集的节点对的窗口大小
  • 神经网络训练参数、学习率和 epoch(迭代)数

DeepWalk 的替代方案 node2vec 添加了两个附加参数,以便为算法的随机游走部分添加更多控制。

Node2vec,DeepWalk 的替代方案

虽然 DeepWalk 算法使用完全随机游走,但 2016 年提出的 node2vec 替代方案引入了两个新参数来控制随机游走是深度优先还是广度优先,传统上称为pq

  • p或返回参数:更高的p将迫使随机游走更频繁地返回前一个节点,从而创建更多本地化路径。
  • q或 in-out 参数:与前面相比,q给出了随机游走将访问更远的未知节点的概率,因此增加了每次游走所覆盖的距离

因此,与 DeepWalk 相比,node2vec 对图的局部结构和全局结构提供了更多控制。

inOut您可以使用和return参数从 GDS 生成类似 node2vec 的随机游走:

MATCH (n:Node {id: 1})
CALL gds.alpha.randomWalk.stream({
    nodeProjection: "*", 
    relationshipProjection: {
        LINKED_TO: {
            type: "LINK", 
            orientation: "UNDIRECTED"
        }
    }, 
    start: id(n),
    walks: 1,
    steps: 2,
    inOut: 0.2,
    return: 1.0
})
YIELD nodeIds
RETURN nodeIds

使用这种方法,您需要从 Neo4j 中提取数据以提供一个 skip-gram 模型或一个将为您完成整个计算的函数(随机游走和模型训练,就像karateclub正在做的那样)。从 GDS 1.3 版开始,还可以计算节点嵌入,而无需事先进行数据提取。

来自 GDS 的 Node2vec (≥ 1.3)

如果您使用的是 Neo4j 4,则可以使用带有一些节点嵌入算法的 GDS 1.3 版本。特别是,您可以在 Neo4j 中运行 node2vec 算法。嵌入过程的输出是节点嵌入本身。与 GDS 的任何其他程序一样,您首先必须创建一个投影图,然后您可以使用以下查询为该投影图中的节点提取嵌入:

CALL gds.alpha.node2vec.stream("projected_graph")

该node2vec过程返回每个节点的嵌入向量。您可以使用配置图配置随机游走和模型训练。例如,让我们将嵌入大小从 100(默认值)更改为 20,并将每个节点生成的随机游走数从 10 更改为 2:

CALL gds.alpha.node2vec.stream(“MyGraph”, {walksPerNode: 2, embeddingSize: 10})

现在让我们看看这些过程的结果如何用于机器学习分析。

与 GDS 中的其他过程一样,您也可以使用嵌入的写入模式将结果作为节点属性写入,而不是直接将其流式传输回用户:
CALL gds.alpha.node2vec.write(“MyGraph”, {})

从 Python 获取嵌入结果

计算嵌入通常不是故事的结局。一旦您设法获得节点的向量表示,您就可以继续您的机器学习任务,例如节点分类,使用您最喜欢的包(例如,这可以是 scikit-learn 以使用决策树或支持向量)。我们不会在本书中详细介绍此类分析,但这里是如何从 Neo4j 中检索计算的向量。

首先,我们需要创建一个 Neo4j (如果您不了解 Neo4j Python 驱动程序,driver请查看第 8 章,在机器学习中使用基于图形的特征​​):

from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", ""))

然后,我们可以运行嵌入过程并在 DataFrame 中获取结果:

import pandas as pd

with driver.session() as session:
    result = session.run(
        "CALL gds.alpha.node2vec('proj_graph')"
    )
    df = pd.DataFrame.from_records(result)

但是,在 中df,嵌入将作为列表存储在单个列中。如果我们想扩展这个列表,使得每个嵌入特征都在一个单独的列中,我们可以使用以下代码:

df = pd.DataFrame(df.tolist())

现在,df具有与嵌入维度一样多的列,这意味着每一列都是一个特征。您可以使用此 DataFrame 继续进行其余的分析。

DeepWalk 和 node2vec 嵌入非常直观,但重要的是要注意它们是转换算法。这意味着每次向图中添加一个新节点时,都必须再次训练整个算法。从随机游走生成到神经网络训练,所有节点的嵌入都必须重新学习。这就是 GNN 的用武之地;这些不是自己学习嵌入,而是学习如何从图结构中创建嵌入。

图神经网络

GNN 于 2005 年推出,在过去 5 年左右的时间里受到了很多关注。它们背后的关键概念是尝试概括 CNN 和 RNN 背后的思想,以将它们应用于任何类型的数据集,包括图形。本节只是对 GNN 的简短介绍,因为我们需要一整本书才能充分探索该主题。与往常一样,如果您想更深入地了解该主题,更多参考资料将在进一步阅读部分提供。

扩展 CNN 和 RNN 的原理以构建 GNN

CNN 和 RNN 都涉及在特殊环境中聚合来自邻域的信息。对于 RNN,上下文是输入序列(例如单词),而序列只不过是一种特殊类型的图。这同样适用于用于分析图像或像素网格的 CNN,它们也是一种特殊类型的图形,其中每个像素都连接到其相邻像素。因此,尝试对所有类型的图使用神经网络是合乎逻辑的(参见下图):【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第13张图片

为了找到与每个节点关联的嵌入,GNN 将使用来自该节点的数据以及来自图中其邻居的数据。

消息传播和聚合

GNN 层对每个节点的邻居发送的消息进行聚合。让我们看一下下面的图表:

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第14张图片

考虑这个问题:

如何计算节点 A 在第三层 L 3中的嵌入?

通过查看图右侧的图结构,可以看到A的邻居是节点BD,因此节点A在第三层之后的嵌入h A 3是节点嵌入的组合上一层中的BD , 2。第二层中BD的嵌入同样是使用它们在前一层1中的邻居的嵌入来计算的。这由以下等式总结,给出节点i在 ( k+1)中的嵌入第层:

h i k+1 = σ( W k Σ j h j k + B k h i k )

等式的第二项是为了确保第 k 层中 i 的表示也考虑在内,并且σ是一个激活函数。

从这个等式中要记住的最重要的事情是W kB k是算法将学习的参数,并且在所有节点之间是相同的。这意味着一旦网络经过训练,W kB k是已知的,并且在添加新节点时,您可以使用这些参数及其邻居计算其嵌入,而无需重新运行完整的嵌入算法。

GNN 是归纳的,因此解决了我们在本章前面研究的其他嵌入算法的一个问题。

前面的等式非常简单,并且已经提出了更多的聚合技术(替换上图中的灰色十字),这解释了构建 GNN 时可用层的种类繁多。

考虑节点属性

与我们在本章中看到的其他节点嵌入算法相比,GNN 的其他优势之一是它们能够在图结构之上考虑节点特征。事实上,在上一节中,我没有给出任何关于网络输入h 0的细节。如果您没有节点功能,您只需使用 one-hot 编码的节点 ID 或类似的东西。但是,如果您的节点具有特征x i,则输入将如下所示:

hi0 = xi

然后,您可以使用图结构作为传播路径沿图传播此特征向量。这是生成节点的向量表示的最佳方式,该向量表示承载实体的特征,例如人的年龄或产品的价格,以及这些实体之间的关系,并编码在图结构中。

尽管 GNN 最近出现在机器学习领域,但它们已经有了很多应用。在下一节中,我们将探索这些应用程序并讨论它们的强大功能。

GNN 的应用

GNN 已被证明在许多情况下都非常有用。除了学习节点、边和全图嵌入之外,它们已经在以下领域成功使用。

图像分析

从图像分类到目标检测,在没有 GNN 的情况下,图像分析领域已经取得了令人难以置信的成果。GNN 已被用于进一步改进此类分析。

视频分析

例如,GNN 用于识别视频帧(交互网络)之间的对象交互,或在不使用任何物理模拟器的情况下预测对象的未来位置。

零样本学习

分类任务要求训练数据集具有将在测试集中观察到的所有目标类的示例(观察值)。让我们考虑一个分类任务,您想从图片中提取动物物种,无论动物是什么。最近的估计假设地球上有大约 800 万种物种。这意味着我们将不得不构建一个包含数百万张图像的图像数据集。为了不达到这些数字,零样本学习尝试推断测试集中的类,即使它们不在训练集中

这是一个正在进行的研究课题,并且已经提出了几种解决方案来解决这个问题。使用 GNN 的一种方法包括以下想法。从每个节点是一个类的知识图开始,根据某些属性的相似性连接,训练一个 GNN,其任务是为每个类输出一个分类器。在实践中,GNN 学习预训练 CNN 的输出层的权重。由于 GNN 是归纳的,为了添加一个新的类,在类知识图中添加一个节点就足够了,而无需添加任何图像。换句话说,一个神经网络被训练来学习另一个网络的权重。

文本分析

在上一节中,我们用词类比构建了我们的第一个神经网络来推断节点嵌入(DeepWalk 算法)。令人惊讶的是,我们还可以通过将文本转换为图形并对其应用 GNN 来获取有关文本的信息。

要了解为什么图表在 NLP 中很重要,请查看下图,该图是从第 3 章“使用 Pure Cypher 赋能您的业务”中重复而来的:

【Neo4j】第 10 章:图嵌入 - 从图到矩阵_第15张图片

上图显示了句子中单词之间的关系,显然不是线性的。

还有更多...

GNN 的应用超越了图像和文本分析。例如,GNN 已被用于组合分析,例如旅行商问题(在第 4 章,图数据科学库和路径查找中讨论)。

在对 GNN 应用的简短讨论之后,让我们探索 GNN 在实践中的使用。

在实践中使用 GNN

已经存在几个库来为所有类型的 GNN 提供通用 API,就像scikit-learn机器学习算法一样。在 Python 中,您可以参考以下任何内容,具体取决于您喜欢的深度学习包:

  • PyTorch Geometric:顾名思义,这是一个 PyTorch 扩展,它允许我们处理复杂的数据集,例如带有新Dataset对象的图形。它还收集了数十种算法实现(GitHub - pyg-team/pytorch_geometric: Graph Neural Network Library for PyTorch)。
  • Graph Nets 库:由 AlphaGo 背后的公司 DeepMind 创建,该算法是第一个能够在围棋中击败人类棋手的算法。借助 Graph Nets,您将能够使用 TensorFlow ( https://github.com/deepmind/graph_nets ) 构建 GNN。
  • 深度图库DGL ):DGL 支持 PyTorch 和 TensorFlow,提供构建所有类型 GNN 的工具 ( Deep Graph Library )。
  • GDS:从 1.3 版开始,GDS 包含一些嵌入算法的实现,包括一个 GNN 架构,我们将在下一节中讨论。

来自 GDS 的 GNN – GraphSAGE

从 1.3 版开始,GDS 包含一些嵌入算法的实现。其中之一是 GraphSAGE 算法,它是 GNN 系列的一部分。它由斯坦福大学的一组研究人员于 2017 年发明,是当今最广泛使用的 GNN 架构之一。

GNN 的一个特点是它们可以考虑节点属性来获得它们的表示。在 GDS 中,此行为是使用nodePropertyNames属性参数化的。如果您不想使用属性,则必须明确告诉算法使用该degreeAsProperty属性的节点度数来初始化自身。因此,这里有两个从 GDS 运行 GraphSAGE 的示例:

  • 不使用节点属性的操作如下:
CALL gds.alpha.graphSage.stream("proj_graph", {degreeAsProperty: true})
  • 使用节点属性如下:
CALL gds.alpha.graphSage.stream("proj_graph", {nodePropertyNames: ['x', 'y']})

与该node2vec过程类似,该graphSage过程为每个节点返回一个向量,可以将其导入 DataFrame 以进行进一步分析。

在结束本章之前,也关闭了本书与图算法严格相关的部分,我们将探索图算法领域的广泛概述,而不局限于 Neo4j 和 GDS,并查看一些有助于我们的建议及时了解最先进的算法。

用图算法走得更远

图和图算法是热门研究课题,每周都会发表新论文,提出社区检测、动态图演化、网络异常检测等方面的新方法。在本节中,我们将详细介绍几种方法来继续学习图算法并了解使它们变得更加强大的最新进展。

最先进的图算法

已发表的关于图的论文可以在专门的期刊上找到,例如Journal of Graph Algorithms and Applications ( http://jgaa.info )。带有代码的论文在收集代码公开可用的论文方面也做得非常出色。图表部分 ( Graphs | Papers With Code ) 很好地概述了当前有关图表的热门研究主题。

但是,如果您每周无法阅读多篇论文,您仍然可以通过定期查看专门用于图表的软件包来扩展您对图表的知识并了解最新进展。Neo4j Graph Data Science 插件就是这样一个包的一个例子。

当您的图形存储在 Neo4j 中时,GDS 非常重要,并且已经提供了许多有趣的算法。但是,并非所有这些都已实现,并且某些应用程序(例如图嵌入或重叠社区检测)可能需要其他类型的算法。为了了解现有的图算法,我鼓励您检查在处理图的主要包中实现的算法。

在 Python 中,我们已经讨论了数据分析、科学和研究社区中用于图形分析的主要三个包:

  • networkx: NetworkX — NetworkX documentation
  • karateclub: Karate Club Documentation — karateclub documentation
  • scikit-network: Welcome to scikit-network’s documentation! — scikit-network 0.27.1 documentation

图结构也用于其他语言(当然!)。例如,R 有这个igraph包,而 Java 开发人员可能会觉得JGraphT有趣。

概括

本章概述了图嵌入算法。从使用相似性度量的基于邻接的方法开始,我们转向基于神经网络的方法。在了解了以词嵌入为例的跳过图模型后,我们使用 DeepWalk 生成句子与图进行了对比。我们还研究了一种称为 node2vec 的 DeepWalk 变体,其中遍历由两个参数配置以增强局部或全局图结构。下表提供了对所研究的每种算法中的图结构假设的简短总结:

算法 假设
Adjacency matrix 节点ij之间的边权重越高,节点ij越相似。
LLE 节点嵌入是其邻居嵌入的线性组合。
HOPE 图中节点之间的相似性可以通过 Adamic-Adar 得分等指标来衡量。
DeepWalk 两个节点之间的相似性由从节点i以最大k跳随机游走找到节点j的概率给出。

最后,我们考虑了使用图神经网络进行图分析的未来,以及了解该领域最新进展的一些技巧。

本章结束了我们关于图算法的长系列。在下一章中,我们将学习如何使用 Neo4j 构建一个运行在生产环境中的 Web 应用程序,学习 Graph Objects Mapper 和 GraphQL 查询语言来构建可重用的 API。

问题

  • karateclub在图嵌入上运行聚类算法,例如 K-means 。你觉得结果如何?
  • 使用该karateclub包通过 DeepWalk 算法生成节点嵌入。

进一步阅读

  • 网络嵌入教程,H. Chen等人。:https ://arxiv.org/abs/1808.02590
  • 非对称传递性保持图嵌入, M. Ou等人。:https ://www.kdd.org/kdd2016/papers/files/rfp0184-ouA.pdf
  • 背后的论文karateclub:
    一个面向 API 的开源 Python 框架,用于图上的无监督学习,B. Rozemberczki等人。:https ://arxiv.org/abs/2003.04819
  • 介绍 DeepWalk 的论文:社会表征的在线学习,B. Perozzi等人。:https ://arxiv.org/abs/1403.6652
  • node2vec:网络的可扩展特征学习, A. Grover等人。, ACM SIGKDD 知识发现和数据挖掘国际会议 (KDD), 201: https://arxiv.org/abs/1607.00653
  • 您将在以下位置找到对 GNN 的更深入介绍:
  • 使用 Python进行高级深度学习的第 13 章,I. Vasilev,Packt Publishing。
  • 图神经网络:方法和应用回顾,J. Zhou等人。:https ://arxiv.org/abs/1812.08434
  • 图神经网络综合调查,Z. Wu等人。:https ://arxiv.org/abs/1901.00596
  • GraphSAGE:所有相关信息都可以在GraphSAGE的 SNAP(斯坦福网络分析项目)页面上找到。
  • GNN 在零样本学习中的应用:
    重新思考零样本学习的知识图传播,M. Kampffmeyer等人。:https ://arxiv.org/abs/1805.11724

你可能感兴趣的:(Neo4j,neo4j,矩阵,线性代数)