【教程】PyG入门,初步尝试运行第一行GNN代码

本文介绍了图神经网络(GNNs)的基本概念,通过PyTorchGeometric库展示了如何处理图数据并进行深度学习。以Zachary的空手道俱乐部网络为例,演示了如何使用GNN进行社区检测。文章涵盖了数据预处理、模型构建、训练和可视化,显示了GNN在无规则结构化数据上的应用能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn]

Colab Notebook

安装必备的库

# Install required packages.
import os
import torch
os.environ['TORCH'] = torch.__version__
print(torch.__version__)

!pip install -q torch-scatter -f https://data.pyg.org/whl/torch-${TORCH}.html
!pip install -q torch-sparse -f https://data.pyg.org/whl/torch-${TORCH}.html
!pip install -q git+https://github.com/pyg-team/pytorch_geometric.git

# Helper function for visualization.
%matplotlib inline
import networkx as nx
import matplotlib.pyplot as plt


def visualize_graph(G, color):
    plt.figure(figsize=(7,7))
    plt.xticks([])
    plt.yticks([])
    nx.draw_networkx(G, pos=nx.spring_layout(G, seed=42), with_labels=False,
                     node_color=color, cmap="Set2")
    plt.show()


def visualize_embedding(h, color, epoch=None, loss=None):
    plt.figure(figsize=(7,7))
    plt.xticks([])
    plt.yticks([])
    h = h.detach().cpu().numpy()
    plt.scatter(h[:, 0], h[:, 1], s=140, c=color, cmap="Set2")
    if epoch is not None and loss is not None:
        plt.xlabel(f'Epoch: {epoch}, Loss: {loss.item():.4f}', fontsize=16)
    plt.show()

介绍:图神经网络的实践

        最近,图的深度学习已经成为深度学习界最热门的研究领域之一。在这里,图神经网络(GNNs)旨在将经典的深度学习概念推广到不规则的结构化数据(与图像或文本相反),并使神经网络能够推理对象及其关系。

        这是通过一个简单的神经信息传递方案来实现的,图G=(V,E)中所有节点v∈V的节点特征x(ℓ)v通过聚合来自其邻居N(v)的局部信息而反复更新。

         本教程将向你介绍一些关于通过基于PyTorch Geometric(PyG)库的图神经网络进行图上深度学习的基本概念。PyTorch Geometric是流行的深度学习框架PyTorch的一个扩展库,由各种方法和工具组成,以简化图神经网络的实现。

        继Kipf等人(2017)之后,让我们通过观察一个简单的图结构的例子来深入了解GNN的世界,即著名的Zachary的空手道俱乐部网络。这个图描述了一个空手道俱乐部的34名成员的社会网络,并记录了在俱乐部外互动的成员之间的联系。在这里,我们感兴趣的是检测由成员互动产生的社区。

        PyTorch Geometric通过torch_geometric.datasets子包提供了对这个数据集的简单访问。

from torch_geometric.datasets import KarateClub

dataset = KarateClub()
print(f'Dataset: {dataset}:')
print('======================')
print(f'Number of graphs: {len(dataset)}')
print(f'Number of features: {dataset.num_features}')
print(f'Number of classes: {dataset.num_classes}')
Dataset: KarateClub():
======================
Number of graphs: 1
Number of features: 34
Number of classes: 4

        在初始化KarateClub数据集后,我们首先可以检查它的一些属性。例如,我们可以看到这个数据集正好有一个图,而且这个数据集的每个节点都被分配了一个34维的特征向量(它唯一地描述了空手道俱乐部的成员)。此外,该图正好有4个类,代表每个节点所属的社区。

        现在让我们更详细地看一下底层图。

data = dataset[0]  # Get the first graph object.

print(data)
print('==============================================================')

# Gather some statistics about the graph.
print(f'Number of nodes: {data.num_nodes}')
print(f'Number of edges: {data.num_edges}')
print(f'Average node degree: {data.num_edges / data.num_nodes:.2f}')
print(f'Number of training nodes: {data.train_mask.sum()}')
print(f'Training node label rate: {int(data.train_mask.sum()) / data.num_nodes:.2f}')
print(f'Has isolated nodes: {data.has_isolated_nodes()}')
print(f'Has self-loops: {data.has_self_loops()}')
print(f'Is undirected: {data.is_undirected()}')
Data(x=[34, 34], edge_index=[2, 156], y=[34], train_mask=[34])
==============================================================
Number of nodes: 34
Number of edges: 156
Average node degree: 4.59
Number of training nodes: 4
Training node label rate: 0.12
Has isolated nodes: False
Has self-loops: False
Is undirected: True

        PyTorch Geometric中的每个图形都由一个数据对象表示,该对象拥有描述其图形表示的所有信息。我们可以通过print(data)随时打印数据对象,以获得关于其属性及其形状的简短摘要:

Data(edge_index=[2, 156], x=[34, 34], y=[34], train_mask=[34])

        我们可以看到,这个数据对象拥有4个属性:

        (1) edge_index属性拥有关于图连接性的信息,即每条边的源节点和目的节点索引的一个元组;

        (2) 节点特征称为 x(34个节点中的每一个都被分配了一个34维的特征向量);

        (3) 节点标签称为 y(每个节点都被精确地分配到一个类别);

        (4) 还存在一个额外的属性,叫做train_mask,它描述了我们已经知道哪些节点的社区分配。

        总的来说,我们只知道4个节点的真实标签(每个社区一个),我们的任务是推断其余节点的社区分配

        数据对象还提供了一些实用函数来推断基础图的一些基本属性。例如,我们可以很容易地推断出图中是否存在孤立的节点(即不存在通往任何节点的边),图中是否包含自循环(即(v,v)∈E),或者图是否是无向的(即对于每条边(v,w)∈E,也存在边(w,v)∈E)。

        现在让我们更详细地检查edge_index属性。

from IPython.display import Javascript  # Restrict height of output cell.
display(Javascript('''google.colab.output.setIframeHeight(0, true, {maxHeight: 300})'''))

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

        通过打印edge_index,我们可以了解PyG在内部如何表示图的连接性。我们可以看到,对于每一条边,edge_index持有两个节点索引的元组,其中第一个值描述了源节点的节点索引,第二个值描述了一条边的目的节点的节点索引。

        这种表示法被称为COO格式(坐标格式),通常用于表示稀疏矩阵。PyG不是用密集表示法A∈{0,1}|V|×|V|来保存邻接信息,而是稀疏地表示图,这指的是只保存A中条目为非零的坐标/值。

        重要的是,PyG不区分有向图和无向图,并将无向图视为有向图的一个特例,其中edge_index中的每个条目都存在反向的边

        我们可以通过将其转换为networkx库的格式来进一步实现图形的可视化,该库除了实现图形操作的功能外,还实现了强大的可视化工具。

from torch_geometric.utils import to_networkx

G = to_networkx(data, to_undirected=True)
visualize_graph(G, color=data.y)

实现图神经网络

        在学习了PyG的数据处理之后,是时候实现我们的第一个图谱神经网络了!为此,我们将使用最简单的GNN运算符,即GCN层(Kipf等人2017)。为此,我们将使用最简单的GNN操作,GCN层,其定义为: 

        其中W(ℓ+1)表示形状为[num_output_features, num_input_features]可训练权重矩阵cw,v是指每条边的固定归一化系数

        PyG通过GCNConv实现这一层,可以通过传入节点特征表示xCOO图连接表示edge_index来执行。

        有了这些,我们就可以通过在torch.nn.Module类中定义我们的网络架构来创建我们的第一个图形神经网络。

import torch
from torch.nn import Linear
from torch_geometric.nn import GCNConv


class GCN(torch.nn.Module):
    def __init__(self):
        super().__init__()
        torch.manual_seed(1234)
        self.conv1 = GCNConv(dataset.num_features, 4)
        self.conv2 = GCNConv(4, 4)
        self.conv3 = GCNConv(4, 2)
        self.classifier = Linear(2, dataset.num_classes)

    def forward(self, x, edge_index):
        h = self.conv1(x, edge_index)
        h = h.tanh()
        h = self.conv2(h, edge_index)
        h = h.tanh()
        h = self.conv3(h, edge_index)
        h = h.tanh()  # Final GNN embedding space.
        
        # Apply a final (linear) classifier.
        out = self.classifier(h)

        return out, h

model = GCN()
print(model)
GCN(
  (conv1): GCNConv(34, 4)
  (conv2): GCNConv(4, 4)
  (conv3): GCNConv(4, 2)
  (classifier): Linear(in_features=2, out_features=4, bias=True)
)

        在这里,我们首先在__init__中初始化我们所有的构建模块,并在forward中定义我们网络的计算流程。我们首先定义并堆叠了三个图卷积层,这相当于聚集了每个节点周围的3跳邻域信息(3 "跳 "以内的所有节点)。此外,GCNConv层将节点特征维度降低到2,即34→4→4→2。每个GCNConv层都被一个tanh非线性增强。

        之后,我们应用一个单一的线性变换(torch.nn.Linear),作为一个分类器,将我们的节点映射到4个类别/社区中的一个。

        我们同时返回最终分类器的输出以及由GNN产生的最终节点嵌入。我们继续通过GCN()初始化我们的最终模型,并打印我们的模型,产生其所有使用的子模块的摘要。

嵌入Karate Club Network

        让我们来看看由我们的GNN产生的节点嵌入。在这里,我们将初始节点特征x图的连接信息edge_index传递给模型,并将其二维嵌入可视化

model = GCN()

_, h = model(data.x, data.edge_index)
print(f'Embedding shape: {list(h.shape)}')

visualize_embedding(h, color=data.y)
Embedding shape: [34, 2]

        值得注意的是,即使在训练我们模型的权重之前,该模型产生的节点嵌入与图的社区结构非常相似。尽管我们模型的权重是完全随机初始化的,而且到目前为止我们还没有进行任何训练,但相同颜色(社区)的节点已经在嵌入空间中紧密地聚集在一起了!这导致的结论是,GNNs引入了强烈的归纳偏置,导致输入图中相互接近的节点的嵌入相似

在Karate Club Network上训练

        让我们看一个例子,如何根据图中4种节点(每个社区一种)的社区分配知识来训练我们的网络参数。

        由于我们模型中的所有东西都是可分的和参数化的,我们可以添加一些标签,训练模型并观察嵌入的反应。在这里,我们使用了一个半监督或过渡性的学习程序。我们只是针对每一类的一个节点进行训练,但允许我们使用完整的输入图数据。

        训练我们的模型与任何其他PyTorch模型非常相似。除了定义我们的网络结构,我们还定义了一个损失准则(这里是CrossEntropyLoss)并初始化了一个随机梯度优化器(这里是Adam)。之后,我们进行多轮优化,每轮包括一个前向和后向传播,以计算我们模型参数的梯度,即前向传播得出的损失。如果你不是PyTorch的新手,这个方案对你来说应该很熟悉。否则,PyTorch文档提供了一个关于如何在PyTorch中训练神经网络的良好介绍。

        请注意,我们的半监督学习方案是由以下一行实现的。

loss = criterion(out[data.train_mask], data.y[data.train_mask])

        虽然我们为所有的节点计算节点嵌入,但我们只利用训练节点来计算损失。在这里,这是通过过滤分类器的输出真实标签data.y来实现的,只包含train_mask中的节点。

        现在让我们开始训练,看看我们的节点嵌入是如何随时间演变的(最好是通过明确地运行代码来体验)。

import time
from IPython.display import Javascript  # Restrict height of output cell.
display(Javascript('''google.colab.output.setIframeHeight(0, true, {maxHeight: 430})'''))

model = GCN()
criterion = torch.nn.CrossEntropyLoss()  # Define loss criterion.
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)  # Define optimizer.

def train(data):
    optimizer.zero_grad()  # Clear gradients.
    out, h = model(data.x, data.edge_index)  # Perform a single forward pass.
    loss = criterion(out[data.train_mask], data.y[data.train_mask])  # Compute the loss solely based on the training nodes.
    loss.backward()  # Derive gradients.
    optimizer.step()  # Update parameters based on gradients.
    return loss, h

for epoch in range(401):
    loss, h = train(data)
    if epoch % 10 == 0:
        visualize_embedding(h, color=data.y, epoch=epoch, loss=loss)
        time.sleep(0.3)

 

         正如人们所看到的,我们的3层GCN模型成功地线性分离了社区,并对大多数节点进行了正确分类。

        此外,我们只用了几行代码就完成了这一切,这要感谢PyTorch的PyG库,它在数据处理和GNN的实现方面帮助了我们。

总结

        对GNN和PyTorch Geometric世界的第一次介绍到此结束。在后续课程中,你将学习如何在一些真实世界的图数据集上实现最先进的分类结果。

        下一篇:用图谱神经网络进行节点分类

人工智能(AI)最近经历了复兴,在视觉,语言,控制和决策等关键领域取得了重大进展。 部分原因在于廉价数据和廉价计算资源,这些资源符合深度学习的自然优势。 然而,在不同的压力下发展的人类智能的许多定义特征仍然是当前方法无法实现的。 特别是,超越一个人的经验 - 从婴儿期开始人类智能的标志 - 仍然是现代人工智能的一项艰巨挑战。 以下是部分立场文件,部分审查和部分统一。我们认为组合概括必须是AI实现类似人类能力的首要任务,结构化表示和计算是实现这一目标的关键。就像生物学利用自然和培养合作一样,我们拒绝“手工工程”和“端到端”学习之间的错误选择,而是倡导一种从其互补优势中获益的方法。我们探索如何在深度学习架构中使用关系归纳偏差来促进对实体,关系和组成它们的规则的学习。我们为AI工具包提供了一个新的构建模块,具有强大的关系归纳偏差 - 图形网络 - 它概括和扩展了在图形上运行的神经网络的各种方法,并为操纵结构化知识和生成结构化行为提供了直接的界面。我们讨论图网络如何支持关系推理和组合泛化,为更复杂,可解释和灵活的推理模式奠定基础。作为本文的配套文件,我们还发布了一个用于构建图形网络的开源软件库,并演示了如何在实践中使用它们。
<think>好的,我现在需要处理用户关于图神经网络(GNN入门知识和资源的问题。首先,用户明确提到想要了解GNN入门教程和学习资料,所以我的回答需要结构清晰,逐步引导,并且提供实用资源。 首先,我应该回顾用户提供的引用内容。引用1和2介绍了GNN的基本概念和应用场景,引用3提到了输出函数和不动点理论,引用4讨论了节点特征的层次处理。这些引用虽然有用,但用户真正的需求是入门资料,可能需要更基础的解释和资源推荐。 接下来,我需要组织回答的结构。通常,入门指南应该包括定义、核心概念、学习路径、资源推荐和常见问题。这样可以帮助用户系统地了解GNN。 然后,我需要确保遵循用户的格式要求:行内公式用$...$,独立公式用$$...$$,正确的中文回答,生成相关问题。同时,引用需要自然地插入到相关内容末尾,如引用[^1]、[^2]等。 在核心概念部分,我应该解释图数据的特点,比如节点、边、邻接矩阵,并举例说明。例如,社交网络中的节点是用户,边是关系。同时,需要提到GNN的关键组件,如信息传递机制,这里可以引用引用3中的局部输出函数和不动点理论。 学习路径部分,建议用户先掌握基础数学知识,如线性代数和图论,再学习深度学习基础,最后进入GNN的具体模型。资源推荐应包括书籍、在线课程、论文和代码实践,比如PyTorch Geometric库。 常见问题部分,需要解答GNN与传统NN的区别、处理异构图的方法、层数限制等,这些问题能帮助用户澄清疑惑。例如,引用4提到的多层处理节点特征,可以解释GNN层数过多可能导致过度平滑。 最后,生成的相关问题需要围绕用户可能进一步关心的内容,比如GNN的数学基础、实际应用、框架对比和优化方法,这样能引导用户深入学习。 需要检查是否所有引用都正确标注,并且没有格式错误。同时,确保语言自然,避免技术术语过多,适合入门者理解。可能还需要补充一些经典模型如GCN、GAT的简要介绍,帮助用户建立基本概念。 总结,回答的结构应该是:定义→核心概念→学习路径→资源推荐→常见问题→相关问题。每个部分结合引用内容,提供足够的信息但不过于复杂,确保用户能够逐步入门GNN。</think>### 图神经网络(GNN入门指南 #### 一、GNN 的定义与核心概念 图神经网络(Graph Neural Networks, GNN)是专门处理图结构数据的深度学习模型。其核心思想是通过**信息传递机制**,聚合节点及其邻居的特征,生成节点或图的表示[^1]。例如,在社交网络中,节点表示用户,边表示好友关系,GNN 可通过多层迭代更新节点的嵌入向量,捕获复杂的交互模式。 **关键概念**: - **图数据**:由节点集合 $V$ 和边集合 $E$ 构成,通常用邻接矩阵 $A$ 表示连接关系。 - **信息传递**:节点特征通过公式 $h_v^{(l+1)} = f\left(h_v^{(l)}, \sum_{u \in \mathcal{N}(v)} h_u^{(l)}\right)$ 更新,其中 $f$ 是神经网络函数[^3]。 - **输出函数**:最终节点表示用于分类或回归任务,例如 $y_v = g(h_v^{(L)})$[^3]。 #### 二、学习路径与资源推荐 1. **基础数学知识**: - 线性代数(矩阵运算) - 图论基础(度、邻接矩阵、拉普拉斯矩阵) - 深度学习基础(反向传播、梯度下降) 2. **入门学习资料**: - **书籍**:《图深度学习》(Deep Learning on Graphs)提供从理论到代码的全面讲解。 - **在线课程**:斯坦福CS224W《图机器学习》课程(含视频与讲义)。 - **经典论文**: - *Semi-Supervised Classification with Graph Convolutional Networks*(GCN 奠基性工作) - *Graph Attention Networks*(GAT 模型详解) - **代码实践**: - PyTorch Geometric 库(提供 GCN、GAT 等预实现模型) - DGL(Deep Graph Library)官方教程 3. **关键模型与公式**: - **图卷积网络(GCN)**: $$ H^{(l+1)} = \sigma\left(\tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}} H^{(l)} W^{(l)}\right) $$ 其中 $\tilde{A}=A+I$ 是添加自连接的邻接矩阵,$\tilde{D}$ 是度矩阵[^4]。 - **图注意力网络(GAT)**: 使用注意力系数 $\alpha_{ij}$ 加权聚合邻居信息: $$ h_i^{(l+1)} = \sigma\left(\sum_{j \in \mathcal{N}(i)} \alpha_{ij} W^{(l)} h_j^{(l)}\right) $$ #### 三、常见问题解答 1. **GNN 与传统神经网络的区别?** GNN 直接处理非欧几里得数据(如图),通过消息传递捕获拓扑结构,而传统NN(如CNN)需要规则网格数据[^2]。 2. **如何处理异构图(节点/边类型多样)?** 可使用异构图GNN(如RGCN),为不同关系类型分配独立的权重矩阵[^1]。 3. **GNN 的层数为什么通常较少?** 层数过多可能导致**过度平滑(Over-Smoothing)**,即不同节点的特征趋于相似[^4]。 #### 四、学习资源清单 | 类型 | 推荐内容 | |------------|--------------------------------------------------------------------------| | 理论教程 | [CS224W 课程笔记](https://web.stanford.edu/class/cs224w/) | | 代码实战 | [PyG 官方示例](https://pytorch-geometric.readthedocs.io/) | | 论文精读 | [GCN 原论文](https://arxiv.org/abs/1609.02907) | | 工具库 | DGL、PyTorch Geometric、Spektral(基于TensorFlow) |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小锋学长生活大爆炸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值