图神经网络 GNN

前言

深度学习4  搬运了国外一篇比较好的博客

A Gentle Introduction to Graph Neural Networks

正文

图形无处不在;现实世界中的物体通常是通过与其他事物的连接来定义的。一组物体和它们之间的连接自然地表达为一个图。研究人员已经开发了能够处理图形数据的神经网络(称为图神经网络或GNN)超过十年。最近的发展增强了它们的能力和表达能力。图神经网络开始在诸如抗菌发现、虚假新闻检测、交通预测和推荐系统等领域看到实际应用。

本文探讨并解释了现代图神经网络。我们将这项工作分为三个部分。首先,我们看看哪种数据最自然地表达为图形,以及一些常见的例子。其次,我们探讨了图形与其他类型数据的不同之处,以及在使用图形时需要做出的一些专业选择。第三,我们构建了一个现代的GNN,逐步介绍模型的每个部分,从该领域的历史建模创新开始。我们从一个简单的实现逐步迈向最先进的GNN模型。

 首先,让我们明确图是什么。图表示实体(节点)之间的关系(边)。

为了进一步描述每个节点、边或整个图,我们可以在每个图元素中存储信息。

我们可以通过给边赋予方向(有向、无向)来进一步特化图形。

图及其出现的地方

你可能已经熟悉某些类型的图形数据,例如社交网络。然而,图形是一种非常强大且通用的数据表示方法,我们将展示两种你可能不认为可以建模为图形的数据类型:图像和文本。尽管这可能有些反直觉,但通过将图像和文本视为图形来查看它们的对称性和结构,我们可以建立一种直觉,从而更好地理解其他非网格状的图形数据,我们稍后将讨论这些数据。

图像作图形数据

我们通常将图像视为具有图像通道的矩形网格,将其表示为数组(例如,244\times244\times3浮点数)。将图像看作有规律结构的图形,其中每个像素表示一个节点,并通过边连接到相邻像素,也是一种思考图像的方式。每个非边界像素恰好有8个相邻节点,并且每个节点存储一个三维向量,表示像素的RGB值。

一种可视化图形连接性的方法是通过其邻接矩阵。我们对节点进行排序,例如在一个简单的5 \times 5的笑脸图像中有25个像素,然后填充一个n_{nodes} \times n_{nodes}的矩阵,如果两个节点共享一个边,则在该矩阵中填入一个条目。请注意,下面这三个表示是同一数据的不同视图。

 文本作图形数据

我们可以通过将每个字符、单词或词元与索引关联起来,将文本数字化,并将文本表示为这些索引的序列。这样创建了一个简单的有向图,其中每个字符或索引都是一个节点,并通过边缘连接到后续的节点。

 当然,在实践中,这通常不是文本和图像的编码方式:这些图形表示是多余的,因为所有图像和所有文本都将具有非常规则的结构。例如,图像在其邻接矩阵中具有带状结构,因为所有节点(像素)都连接在一个网格中。文本的邻接矩阵只是一条对角线,因为每个单词只连接到前一个单词和下一个单词。

图结构数据有哪些问题类型?

本文已经描述了一些实际中的图示例,但我们希望对这些数据执行哪些任务呢?在图中有三种常见的预测任务:图级别、节点级别和边级别。

在图级别任务中,我们预测整个图的一个单一属性。在节点级别任务中,我们为图中的每个节点预测某些属性。在边级别任务中,我们希望预测图中边的属性或存在性。

对于上述三种预测问题的三个级别(图级别、节点级别和边级别),我们将展示所有以下问题都可以用单一模型类 GNN 来解决。但首先,让我们更详细地浏览三类图预测问题,并提供每种问题的具体示例。

图级别任务

在图级别任务中,我们的目标是预测整个图的属性。例如,对于一个用图表示的分子,我们可能希望预测这种分子的气味,或者它是否会与与某种疾病有关的受体结合。

这类似于 MNIST 和 CIFAR 的图像分类问题,我们希望将标签与整个图像关联起来。对于文本数据,情感分析是一个类似的问题,我们希望一次性识别整个句子的情感或情绪。

节点级别任务

节点级别任务涉及预测图中每个节点的身份或角色。

一个经典的节点级别预测问题是 Zach 的空手道俱乐部。数据集是一个单一的社交网络图,由于政治分歧,其中的个人宣誓效忠于两个空手道俱乐部中的一个。据说,Mr. Hi(教练)和John H(管理员)之间的争执在空手道俱乐部中造成了分裂。节点代表个体空手道练习者,边表示这些成员在空手道之外的互动。预测问题是在争执之后分类给定成员是否忠诚于Mr. Hi或John H。在这种情况下,节点到教练或管理员之间的距离与此标签高度相关。

节点级别预测问题类似于图像分割,我们试图标记图像中每个像素的角色。对于文本数据,类似的任务是预测句子中每个单词的词性(如名词、动词、副词等)。

边级别任务

在图中,剩下的预测问题是边预测。

边级别推断的一个例子是图像场景理解。除了识别图像中的对象外,深度学习模型还可以用于预测它们之间的关系。我们可以将其表示为边级别分类:给定代表图像中对象的节点,我们希望预测哪些节点共享边缘或该边缘的值是什么。如果我们希望发现实体之间的连接,我们可以将图形视为完全连接的,并基于其预测值修剪边缘,从而得到一个稀疏的图形。

机器学习中使用图的挑战

那么,我们该如何使用神经网络解决这些不同的图形任务呢?第一步是考虑如何表示图形,使其与神经网络兼容。

机器学习模型通常以矩形或网格状数组作为输入。因此,如何以与深度学习兼容的格式表示图形并不是很直观。图形最多有四种类型的信息,我们可能想要使用它们来进行预测:节点、边、全局上下文和连通性。前三个相对简单:例如,对于节点,我们可以形成一个节点特征矩阵N,通过为每个节点分配一个索引i并在N中存储节点i的特征来实现。虽然这些矩阵具有可变数量的示例,但它们可以在没有任何特殊技术的情况下进行处理。

然而,表示图形的连通性则更加复杂。最明显的选择可能是使用邻接矩阵,因为这很容易张量化。然而,这种表示方法有一些缺点。从前面的数据集表格中可以看出,图形中的节点数可以达到数百万,每个节点的边数可以高度可变。通常,这导致非常稀疏的邻接矩阵,它们的空间效率低下。

另一个问题是,有许多邻接矩阵可以编码相同的连通性,并且无法保证这些不同的矩阵会在深度神经网络中产生相同的结果(也就是说,它们不是置换不变的)。

学习置换不变操作是最近研究的一个领域。例如,前面提到的黑白棋图可以用这两个邻接矩阵等价地描述。它也可以用节点的所有其他可能排列来描述。

一种优雅且内存高效的表示稀疏矩阵的方式是使用邻接表。它们将边 e_k 连接的节点 n_i 和 n_j 的连通性描述为一个元组 (i,j),在邻接表的第 k 个条目中。由于我们预期边的数量要比邻接矩阵的条目数(n_{nodes}^2)低得多,因此我们避免了对图的非连通部分进行计算和存储。

为了使这个概念更加具体,我们可以看看如何根据这个规范表示不同图中的信息:

需要注意的是,图中使用了每个节点/边缘/全局的标量值,但是大多数实际的张量表示都会在每个图属性上使用向量。我们将处理大小为[n_{nodes}node_{dim}]的节点张量,以及其他图属性。 

GNN

现在,我们已经将图的描述格式化为一个置换不变的矩阵形式,接下来我们将使用图神经网络(GNN)来解决图形预测任务。GNN是一个可优化的转换,应用于图的所有属性(节点、边、全局上下文),同时保持图的对称性(置换不变性)。我们将使用由Gilmer等人提出的“消息传递神经网络”框架以及由Battaglia等人引入的Graph Nets体系结构图来构建GNN。GNN采用“图输入,图输出”的结构,意味着这些模型类型接受一个图作为输入,并将信息加载到其节点、边和全局上下文中,逐步转换这些嵌入,而不改变输入图的连接。

最简单的GNN

我们已经构建了上面的图形的数值表示(用向量代替标量),现在我们可以构建一个GNN。我们将从最简单的GNN架构开始,其中我们为所有图属性(节点、边、全局)学习新的嵌入,但我们还没有使用图的连接。

这个GNN对图的每个组件使用单独的多层感知机(MLP);我们称之为GNN层。对于每个节点向量,我们应用MLP并返回一个学习到的节点向量。对于每个边缘,我们也做同样的操作,学习一个每个边缘的嵌入,并为全局上下文向量做同样的操作,学习整个图的单个嵌入。

作为神经网络模块或层常见的做法,我们可以将这些GNN层堆叠在一起。

因为GNN不会更新输入图的连接,所以我们可以用与输入图相同的邻接列表和相同数量的特征向量来描述GNN的输出图。但是,由于GNN已经更新了每个节点、边和全局上下文表示,所以输出图具有更新的嵌入。

GNN信息汇聚的预测

我们已经构建了一个简单的GNN,但是我们如何在我们描述的任何任务中进行预测呢?

我们将考虑二元分类的情况,但是这个框架可以很容易地扩展到多类或回归情况。如果任务是对节点进行二元预测,并且图已经包含节点信息,则方法很简单——对于每个节点嵌入,应用一个线性分类器。

然而,并不总是这么简单。例如,您可能在边中存储了图中的信息,但没有节点中的信息,但仍需要对节点进行预测。我们需要一种方式来从边缘收集信息并将其提供给节点进行预测。我们可以通过池化来实现这一点。汇集分为两个步骤:

  1. 对于要汇总的每个项目,收集它们的每个嵌入并将它们连接成一个矩阵。

  2. 然后聚合收集到的嵌入,通常是通过求和操作。

有关聚合操作的更深入讨论,请转到比较聚合操作部分。我们用字母\rho表示汇集操作,并将从边缘到节点收集信息表示为p_{En}\rightarrow v_n

 

如果我们只有边级别的特征,并且试图预测二元节点信息,我们可以使用池化将信息传递到需要的位置。该模型如下图所示: 

如果我们只有节点级别的特征,而要预测边级别的二进制信息,则模型如下所示。 

如果我们只有节点级别的特征,并且需要预测二元全局属性,我们需要将所有可用的节点信息聚合在一起。这类似于CNN中的全局平均池化层。边也可以采用类似的方式。

在我们的例子中,分类模型c可以很容易地替换成任何可微模型,或者通过使用广义线性模型来适应多类分类。

现在我们已经演示了如何构建一个简单的GNN模型,并通过在图的不同部分之间路由信息来进行二元分类预测。这种汇集技术将作为构建更复杂的GNN模型的基本组件。如果我们有新的图形属性,我们只需要定义如何从一个属性传递信息到另一个属性。

请注意,在这个最简单的GNN公式中,我们没有在GNN层内部使用图形连接。每个节点都是独立处理的,每个边也是如此,以及全局上下文。我们只有在汇集信息进行预测时才使用连接。

图上的消息传递

我们可以通过在GNN层内使用池化技术来使我们学习的嵌入感知图连接性,从而进行更复杂的预测。我们可以使用消息传递来实现这一点,其中相邻的节点或边交换信息并影响彼此的更新嵌入。

消息传递包括三个步骤:

  1. 对于图中的每个节点,收集所有相邻节点的嵌入(或消息),这是上述g函数所描述的。

  2. 通过聚合函数(如求和)聚合所有消息。

  3. 将所有汇总的消息通过更新函数传递,通常是一个学习的神经网络。

这些步骤对于利用图的连接性至关重要。我们将在GNN层中构建更复杂的消息传递变体,从而产生越来越具有表现力和能力的GNN模型。

这种操作序列,如果应用一次,则是最简单的消息传递GNN层。

这与标准卷积类似:实质上,消息传递和卷积是聚合和处理元素邻居信息的操作,以更新元素的值。在图中,元素是节点,在图像中,元素是像素。但是,图中相邻节点的数量可以是可变的,不像图像中每个像素都有一组相邻元素。

通过堆叠消息传递GNN层,节点最终可以整合整个图中的信息:经过三层处理后,一个节点可以获取它距离三步的节点的信息。

我们可以更新我们的体系结构图,以包括节点的这种新信息来源:

边的表示

我们的数据集并不总是包含所有类型的信息(节点、边和全局上下文)。当我们想对节点进行预测,但我们的数据集只有边信息时,我们可以使用汇聚来将信息从边传递到节点,但仅在模型的最终预测步骤中进行。我们可以使用消息传递在GNN层内在节点和边之间共享信息。

我们可以像之前使用相邻节点信息那样,将相邻边的信息合并起来,首先汇聚边信息,然后使用更新函数进行转换并将其存储。

然而,在图中存储的节点和边信息不一定具有相同的大小或形状,因此不清楚如何将它们组合起来。一种方法是学习从边空间到节点空间的线性映射,反之亦然。或者,可以在更新函数之前将它们连接在一起。

 

构建GNN时,我们更新哪些图属性以及更新它们的顺序是一个设计决策。我们可以选择在更新节点嵌入之前更新边嵌入,或者反之。这是一个开放性研究领域,有许多解决方案。例如,我们可以以“编织”方式进行更新,其中有四个更新表示被合并成新的节点和边表示:从节点到节点(线性)、从边到边(线性)、从节点到边(边层)、从边到节点(节点层)。

 增加全局表示

到目前为止,我们所描述的网络存在一个缺陷:在图中相距较远的节点可能永远无法有效地相互传递信息,即使我们多次应用消息传递。对于一个节点,如果我们有k层,信息最多只会传播k步。这可能会对依赖于远离的节点或节点组的预测任务造成问题。一种解决方案是使用图的全局表示(U),有时称为主节点或上下文向量。这个全局上下文向量连接到网络中的所有其他节点和边缘,并可以作为它们之间传递信息的桥梁,逐步构建出整个图的表示。这创建了一个比否则可以学习到的更丰富和复杂的图表示。

在这种观点中,所有的图属性都有了学习到的表示,因此我们可以通过将我们感兴趣的属性的信息相对于其余属性进行条件化来利用它们。例如,对于一个节点,我们可以考虑来自相邻节点、连接边和全局信息的信息。为了在所有这些可能的信息源上对新节点嵌入进行条件化,我们可以简单地将它们连接起来。此外,我们还可以通过线性映射将它们映射到相同的空间并将它们相加,或者应用特征调制层(feature-wise modulation layer),它可以被视为一种特征化注意机制。 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以!以下是一个简单的示例代码,展示了如何使用PyTorch Geometric库实现一个神经网络(Graph Neural Network,GNN)模型: ```python import torch import torch.nn as nn import torch.nn.functional as F from torch_geometric.datasets import Planetoid from torch_geometric.nn import GCNConv # 加载数据集 dataset = Planetoid(root='data/Cora', name='Cora') data = dataset[0] class GNNModel(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(GNNModel, self).__init__() self.conv1 = GCNConv(input_dim, hidden_dim) self.conv2 = GCNConv(hidden_dim, output_dim) def forward(self, x, edge_index): x = F.relu(self.conv1(x, edge_index)) x = self.conv2(x, edge_index) return F.log_softmax(x, dim=1) # 配置模型和优化器 input_dim = dataset.num_features hidden_dim = 16 output_dim = dataset.num_classes model = GNNModel(input_dim, hidden_dim, output_dim) optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4) # 训练模型 model.train() for epoch in range(200): optimizer.zero_grad() out = model(data.x, data.edge_index) loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask]) loss.backward() optimizer.step() # 测试模型 model.eval() _, pred = model(data.x, data.edge_index).max(dim=1) correct = int(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item()) acc = correct / int(data.test_mask.sum()) print(f'Test Accuracy: {acc:.4f}') ``` 上述代码使用了PyTorch Geometric库来加载Cora数据集,并根据GCN(Graph Convolutional Network)模型的架构实现了GNN模型。模型的前向传播通过两个GCNConv层实现,使用ReLU作为激活函数,并使用log_softmax输出。然后使用Adam优化器进行训练,并使用负对数似然损失进行监督学习。最后,将模型切换到评估模式,计算测试集上的准确率。 请注意,这只是一个简单的示例,实际应用中可能需要根据需求进行调整和优化。你可以根据自己的数据集和任务来修改和扩展这个代码。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值