图神经网络实战(6)——使用PyTorch构建图神经网络

图神经网络实战(6)——使用PyTorch构建图神经网络

    • 0. 前言
    • 1. 传统机器学习与人工智能
    • 2. 人工神经网络基础
      • 2.1 人工神经网络组成
      • 2.2 神经网络的训练
    • 3. 图神经网络
    • 4. 使用香草神经网络执行节点分类
      • 4.1 数据集构建
      • 4.2 模型构建
      • 4.3 模型训练
    • 5. 实现香草图神经网络执行节点分类
      • 5.1 图神经网络基本原理
      • 5.2 实现香草图神经网络
    • 小结
    • 系列链接

0. 前言

图数据集通常比简单的连接集合更加丰富,因为节点和边可以具有表示分数、颜色、单词等特征。包含这些额外信息在输入数据中对于生成最佳嵌入至关重要。由于节点和边的特征与非图数据集具有相似的结构,这意味着经典技术如神经网络可以应用于这些数据。在本节中,我们将使用 Cora 和 Facebook Page-Page 数据集,首先将它们视为表格数据集,观察香草神经网络 (vanilla neural networks) 在节点特征上的表现如何。然后,尝试在神经网络中加入拓扑信息,实现图神经网络 (Graph Neural Networks, GNN) 架构:一个同时考虑节点特征和边的简单模型。最后,我们将比较两种架构的性能。

1. 传统机器学习与人工智能

传统应用程序中,系统是通过使用程序员编写的复杂算法来实现智能化的。例如,假设我们希望识别照片中是否包含狗。在传统的机器学习 (Machine Learning, ML) 中,需要机器学习研究人员首先确定需要从图像中提取的特征,然后提取这些特征并将它们作为输入传递给复杂算法,算法解析给定特征以判断图像中是否包含狗:

传统机器学习

然而,如果要为多种类别图像分类手动提取特征,其数量可能是指数级的,因此,传统方法在受限环境中效果很好(例如,识别证件照片),而在不受限制的环境中效果不佳,因为每张图像之间都有较大差异。
我们可以将相同的思想扩展到其他领域,例如文本或结构化数据。过去,如果希望通过编程来解决现实世界的任务,就必须了解有关输入数据的所有内容并编写尽可能多的规则来涵盖所有场景,并且不能保证所有新场景都会遵循已有规则。
而神经网络内含了特征提取的过程,并将这些特征用于分类/回归,几乎不需要手动特征工程,只需要标记数据(例如,哪些图片是狗,哪些图片不是狗)和神经网络架构,不需要手动提出规则来对图像进行分类,这减轻了传统机器学习技术强加给程序员的大部分负担。
训练神经网络需要提供大量样本数据。例如,在前面的例子中,我们需要为模型提供大量的狗和非狗图片,以便它学习特征。神经网络用于分类任务的流程如下,其训练与测试是端到端 (end-to-end) 的:

神经网络训练

2. 人工神经网络基础

2.1 人工神经网络组成

ANN 是张量(权重, weights )和数学运算的集合,其排列方式近似于松散的人脑神经元排列。可以将其视为一种数学函数,它将一个或多个张量作为输入并预测相应输出(一个或多个张量)。将输入连接到输出的操作方式称为神经网络的架构,我们可以根据不同的任务构建不同架构,即基于问题是包含结构化数据还是非结构化(图像,文本,语音)数据,这些数据就是输入和输出张量的列表。ANN 由以下部分组成:

  • 输入层:将自变量作为输入
  • 隐藏(中间)层:连接输入和输出层,在输入数据之上执行转换;此外,隐藏层利用节点单元(下图中的圆圈)将其输入值修改为更高/更低维的值;通过修改中间节点的激活函数可以实现复杂表示函数
  • 输出层:输入变量产生的值

综上,神经网络的典型结构如下:

神经网络架构
输出层中节点的数量(上图中的圆圈)取决于实际任务以及我们是在尝试预测连续变量还是分类变量。如果输出是连续变量,则输出有一个节点。如果输出是具有 m 个可能类别的分类,则输出层中将有 m 个节点。接下来,我们深入介绍节点/神经元的工作原理,神经元按如下方式转换其输入:

神经元

其中, x 1 x_1 x1 x 2 x_2 x2,…, x n x_n xn 是输入变量, w 0 w_0 w0 是偏置项(类似于线性/逻辑回归中的偏差); w 1 w_1 w1 w 2 w_2 w2,…, w n w_n wn 是赋予每个输入变量的权重,输出值 a a a 计算如下:

a = f ( w 0 + ∑ w i N w i x i ) a=f(w_0+\sum _{w_i} ^N w_ix_i) a=f(w0+wiNwixi)

可以看到, a a a 是权重和输入对的乘积之和,之后使用一个附加函数 f ( w 0 + ∑ w i N w i x i ) f(w_0+\sum _{w_i} ^N w_ix_i) f(w0+wiNwixi),函数 f f f 是在乘积之和之上应用的非线性激活函数,用于在输入和它们相应的权重值的总和上引入非线性,可以通过使用多个隐藏层实现更强的非线性能力。
整体而言,神经网络是节点的集合,其中每个节点都有一个可调整的浮点值(权重),并且节点间相互连接,返回由网络架构决定的输出。网络由三个主要部分组成:输入层、隐藏层和输出层。我们可以使用多层 (n) 隐藏层,深度学习通常表示具有多个隐藏层的神经网络。通常,当神经网络需要学习具有复杂上下文或上下文不明显的任务(例如图像识别)时,就必须具有更多隐藏层。

2.2 神经网络的训练

训练神经网络实际上就是通过重复两个关键步骤来调整神经网络中的权重:前向传播和反向传播。

  1. 在前向传播 (feedforward propagation) 中,我们将一组权重应用于输入数据,将其传递给隐藏层,对隐藏层计算后的输出使用非线性激活,通过若干个隐藏层后,将最后一个隐藏层的输出与另一组权重相乘,就可以得到输出层的结果。对于第一次正向传播,权重的值将随机初始化
  2. 在反向传播 (backpropagation) 中,尝试通过测量输出的误差,然后相应地调整权重以降低误差。神经网络重复正向传播和反向传播以预测输出,直到获得令误差较小的权重为止

3. 图神经网络

图神经网络 (Graph Neural NetworkGNN) 是一种专门用于处理图数据的深度学习模型。传统的神经网络主要用于处理向量或序列数据,而图神经网络则可以有效地处理非结构化的图形数据,如社交网络、推荐系统中的用户-物品关系、生物信息学中的蛋白质相互作用网络等。
图神经网络通过学习节点之间的连接模式和拓扑结构来捕捉图数据中的信息传播和相互作用。它通过将每个节点及其邻居节点的特征进行聚合和更新,从而实现对整个图的表示学习。在图神经网络中,通常会定义节点表示 (node embedding) 和边表示 (edge embedding),以便更好地表示节点之间的关系和特征。
图神经网络的基本原理是通过多层神经网络结构来逐步传播和更新节点的特征信息,从而实现对整个图的全局信息的学习和表示。这种方式可以帮助图神经网络在保留局部结构信息的同时,也考虑了全局图的拓扑结构和特征之间的关系,从而提高了对图数据的建模能力。
图神经网络已经在许多领域得到广泛应用,包括社交网络分析、推荐系统、生物信息学、知识图谱等。它为处理复杂的非结构化数据提供了一种强大的工具,有助于挖掘数据中的潜在模式和关联,从而推动了深度学习在图数据分析领域的发展和应用。

4. 使用香草神经网络执行节点分类

与 Zachary’s Karate Club 数据集相比,Cora 和 Facebook Page-Page 数据集包含了额外信息——节点特征,提供了图中节点的额外信息,例如用户的年龄、性别或兴趣爱好等。在香草神经网络( vanilla neural networks, 也称为多层感知器, multilayer perceptron )中,嵌入会直接用于模型,以执行节点分类等下游任务。

4.1 数据集构建

在本节中,我们将节点特征视为常规的表格数据集,并在这个数据集上训练一个简单的神经网络来对节点进行分类。需要注意的是,这种架构没有考虑到网络的拓扑结构。以 Cora 数据集为例,通过创建数据对象可以轻松访问节点特征的表格数据集。
首先,通过合并 data.x (包含节点特征)和 data.y (包含七个类别中每个节点的类别标签),将该对象转换为普通的 pandas DataFrame

import pandas as pd
df_x = pd.DataFrame(data.x.numpy())
df_x['label'] = pd.DataFrame(data.y)
print(df_x)

得到的数据集如下所示:

        0    1    2    3    4    5  ...  1428  1429  1430  1431  1432  label
0     0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3
1     0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      4
2     0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      4
3     0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      0
4     0.0  0.0  0.0  1.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3
...   ...  ...  ...  ...  ...  ...  ...   ...   ...   ...   ...   ...    ...
2703  0.0  0.0  0.0  0.0  0.0  1.0  ...   0.0   0.0   0.0   0.0   0.0      3
2704  0.0  0.0  1.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3
2705  0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3
2706  0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3
2707  0.0  0.0  0.0  0.0  0.0  0.0  ...   0.0   0.0   0.0   0.0   0.0      3[2708 rows x 1434 columns]

这是一个包含数据和标签的经典数据集,据此,我们可以构建一个简单的多层感知器 (Multilayer Perceptron, MLP),用 data.y 提供的标签对 data.x 进行训练。
创建 MLP 类,包含以下四个方法:

  • __init__() 用于初始化实例
  • forward() 用于执行前向传播
  • fit() 用于执行反向传播训练模型
  • test() 用于评估模型

在训练模型之前,我们必须定义模型评价指标。多分类问题有多种评价指标,包括准确率 (accuracy)、F1 分数 (F1 score)、ROC AUC ( Area Under the Receiver Operating Characteristic Curve) 等。在本节中,我们采用准确率作为评价指标,即正确预测的百分比。虽然这并不是多分类模型的最佳评价指标,但它更容易理解,我们也可以使用其他指标来代替它:

def accuracy(y_pred, y_true):"""Calculate accuracy."""return torch.sum(y_pred == y_true) / len(y_true)

4.2 模型构建

接下来,我们使用 PyTorch 构建 MPL 模型。

(1)PyTorch 中导入所需的函数和类:

import torch
from torch.nn import Linear
import torch.nn.functional as F

(2) 创建一个名为 MLP 的新类,它继承自 torch.nn.Module

class MLP(torch.nn.Module):

(3) __init__() 方法有三个参数 (dim_indim_hdim_out),分别表示输入层、隐藏层和输出层的神经元数量,在 __init__() 方法中还需要定义两个线性层:

    def __init__(self, dim_in, dim_h, dim_out):super().__init__()self.linear1 = Linear(dim_in, dim_h)self.linear2 = Linear(dim_h, dim_out)

(4) forward() 方法用于执行前向传递。输入通过 ReLU (Rectified Linear Unit) 激活函数馈送到第一个线性层,之后计算结果传递到第二个线性层。最后,返回分类结果的 log_softmax 值:

    def forward(self, x):x = self.linear1(x)x = torch.relu(x)x = self.linear2(x)return F.log_softmax(x, dim=1)

(5) fit() 方法用于模型训练。首先,初始化一个损失函数和一个优化器用于训练过程:

    def fit(self, data, epochs):criterion = torch.nn.CrossEntropyLoss()optimizer = torch.optim.Adam(self.parameters(),lr=0.01,weight_decay=5e-4)

(6) 循环训练 MPL 模型,在损失函数之上使用 accuracy() 函数:

        self.train()for epoch in range(epochs+1):optimizer.zero_grad()out = self(data.x)loss = criterion(out[data.train_mask], data.y[data.train_mask])acc = accuracy(out[data.train_mask].argmax(dim=1),data.y[data.train_mask])loss.backward()optimizer.step()

(7) 在同一个循环中,每 20epoch 打印一次训练数据和测试数据的损失和准确率:

            if(epoch % 20 == 0):val_loss = criterion(out[data.val_mask], data.y[data.val_mask])val_acc = accuracy(out[data.val_mask].argmax(dim=1),data.y[data.val_mask])print(f'Epoch {epoch:>3} | Train Loss: {loss:.3f} | Train Acc:'f' {acc*100:>5.2f}% | Val Loss: {val_loss:.2f} | 'f'Val Acc: {val_acc*100:.2f}%')

(8) test() 方法用于在测试集上对模型进行评估,并返回模型准确率:

    @torch.no_grad()      def test(self, data):self.eval()out = self(data.x)acc = accuracy(out.argmax(dim=1)[data.test_mask], data.y[data.test_mask])return acc

4.3 模型训练

对于不同数据集需要单独训练模型,由于我们想要分别在 CoraFacebook Page-Page 数据集上执行节点分类任务,因此需要一个专门用于 Cora 的模型,和一个专门用于 Facebook Page-Page 的模型。首先,在 Cora 上训练 MLP 模型。

(1) 创建一个 MLP 模型并打印模型简要信息,以检查模型构建是否正确:

mlp = MLP(dataset.num_features, 16, dataset.num_classes)
print(mlp)

输出结果如下所示:

MLP((linear1): Linear(in_features=1433, out_features=16, bias=True)(linear2): Linear(in_features=16, out_features=7, bias=True)
)

(2) 可以看到,我们得到了正确的特征数量,接下来,对这个模型进行 100epoch 训练:

mlp.fit(data, epochs=100)

在训练循环中打印的指标变化情况如下所示:

Epoch   0 | Train Loss: 1.953 | Train Acc: 13.57% | Val Loss: 1.97 | Val Acc: 16.00%
Epoch  20 | Train Loss: 0.081 | Train Acc: 100.00% | Val Loss: 1.49 | Val Acc: 50.20%
Epoch  40 | Train Loss: 0.009 | Train Acc: 100.00% | Val Loss: 1.63 | Val Acc: 50.20%
Epoch  60 | Train Loss: 0.006 | Train Acc: 100.00% | Val Loss: 1.62 | Val Acc: 48.80%
Epoch  80 | Train Loss: 0.007 | Train Acc: 100.00% | Val Loss: 1.49 | Val Acc: 51.00%
Epoch 100 | Train Loss: 0.008 | Train Acc: 100.00% | Val Loss: 1.42 | Val Acc: 51.20%

(3) 最后,评估评估的准确率:

acc = mlp.test(data)
print(f'\nMLP test accuracy: {acc*100:.2f}%')

在测试数据上,模型准确率如下所示:

MLP test accuracy: 52.40%

(4)Facebook Page-Page 数据集重复同样的过程,输出结果如下:

Epoch   0 | Train Loss: 1.400 | Train Acc: 26.00% | Val Loss: 1.41 | Val Acc: 25.86%
Epoch  20 | Train Loss: 0.651 | Train Acc: 74.33% | Val Loss: 0.66 | Val Acc: 73.89%
Epoch  40 | Train Loss: 0.575 | Train Acc: 77.14% | Val Loss: 0.62 | Val Acc: 75.49%
Epoch  60 | Train Loss: 0.547 | Train Acc: 78.07% | Val Loss: 0.60 | Val Acc: 75.79%
Epoch  80 | Train Loss: 0.531 | Train Acc: 78.83% | Val Loss: 0.60 | Val Acc: 75.54%
Epoch 100 | Train Loss: 0.517 | Train Acc: 79.52% | Val Loss: 0.59 | Val Acc: 75.69%MLP test accuracy: 74.89%

尽管这两个数据集在某些方面非常相似,但可以看到,使用相同的模型训练后的模型准确率却大相径庭。接下来,我们将同时考虑图数据的节点特征和拓扑结构构建香草图神经网络 (Vanilla Graph Neural Network, Vanilla GNN)。

5. 实现香草图神经网络执行节点分类

5.1 图神经网络基本原理

在介绍图神经网络 (Graph Neural Network, GNN) 架构前,尝试从零开始构建 GNN 模型以了解 GNN 的核心思想。首先,我们回顾简单线性层的定义。
一个香草神经网络层对应于一个线性变换关系 h A = x A W T h_A=x_AW^T hAxAWT,其中 x A x_A xA 是节点 A A A 的输入向量, W W W 是网络层的权重矩阵。在 PyTorch 中,可以使用 torch.mm() 函数或 nn.Linear 类来实现上述变换,而后者还可以添加偏置等其他参数。
对于图数据集,输入向量是节点特征,这意味着节点之间是完全独立的,因此 MPL 模型还不足以很好地理解图,与图像中的像素一样,节点的上下文对于理解节点至关重要。在图像中,我们只有在观察一组像素而不是单个像素时,才能够识别出边缘、模式等,同样,要了解一个节点,就需要查看它的邻居。
使用 N A \mathcal N_A NA 表示节点 A A A 的邻居集,则图线性层 (Graph Linear Layer) 可以表示为:
h A = ∑ i ∈ N A x i W T h_A=\sum_{i\in \mathcal N_A} x_iW^T hA=iNAxiWT
也可以对上述公式进行简单的变换。例如,可以为中心节点设置一个权重矩阵 W 1 W_1 W1,为邻居设置另一个权重矩阵 W 2 W_2 W2。需要注意的是,我们不能为每个邻居设置一个权重矩阵,因为邻居节点数量会因节点不同而变化。
在神经网络中,为了高效的计算,不能将上述等式应用于每个节点,而应使用矩阵乘法。例如,线性层的方程可以改写为 H = X W T H=XW^T H=XWT,其中 X X X 是输入矩阵。
CoraFacebook Page-Page 数据集中,邻接矩阵 A A A 包含图中每个节点之间的连接。将输入矩阵与邻接矩阵相乘,就能直接求出邻居节点的特征。可以在邻接矩阵中加入自循环,这样中心节点的特征也会被考虑在内。更新后的邻接矩阵可以表示为 A ~ = A + I \tilde A=A+I A~=A+I,图线性层可以重写如下:
H = A ~ T X W T H=\tilde A^TXW^T H=A~TXWT

5.2 实现香草图神经网络

PyTorch 中实现上述图线性层并进行测试,然后,将它作为常规网络层来构建一个香草图神经网络 (Vanilla Graph Neural Network, Vanilla GNN)。

(1) 首先,创建一个新类 VanillaGNNLayer,继承自 torch.nn.Module 类:

class VanillaGNNLayer(torch.nn.Module):

(2)VanillaGNNLayer 的初始化需要两个参数,dim_indim_out,分别表示输入和输出的特征数,在 __init__() 方法中初始化一个无偏置线性变换:

    def __init__(self, dim_in, dim_out):super().__init__()self.linear = Linear(dim_in, dim_out, bias=False)

(3)forward() 方法中执行两个操作,首先执行线性变换,然后与邻接矩阵 A ~ \tilde A A~ 相乘:

    def forward(self, x, adjacency):x = self.linear(x)x = torch.sparse.mm(adjacency, x)return x

(4) 在创建 vanilla GNN 之前,还需要将数据集中的边索引 (data.edge_index) 以坐标格式转换为邻接矩阵,此外,还需要加入自循环;否则,中心节点的特征将不会被它们自己的嵌入所考虑。使用 to_den_adj()torch.eye() 函数能够快速实现上述操作:

from torch_geometric.utils import to_dense_adjadjacency = to_dense_adj(data.edge_index)[0]
adjacency += torch.eye(len(adjacency))
print(adjacency)

输出邻接矩阵如下所示:

tensor([[1., 0., 0.,  ..., 0., 0., 0.],[0., 1., 1.,  ..., 0., 0., 0.],[0., 1., 1.,  ..., 0., 0., 0.],...,[0., 0., 0.,  ..., 1., 0., 0.],[0., 0., 0.,  ..., 0., 1., 1.],[0., 0., 0.,  ..., 0., 1., 1.]])

但由于它是一个稀疏矩阵,因此在这个张量中大部分元素 0,节点之间存在连接时元素为 1。有了图线性层和邻接矩阵后, 我们就可以用与实现 MLP 类似的方法实现 vanilla GNN

(5) 创建一个包含两个图线性层的新类:

class VanillaGNN(torch.nn.Module):"""Vanilla Graph Neural Network"""def __init__(self, dim_in, dim_h, dim_out):super().__init__()self.gnn1 = VanillaGNNLayer(dim_in, dim_h)self.gnn2 = VanillaGNNLayer(dim_h, dim_out)

(6) 图神经网络层会将之前计算的邻接矩阵作为额外输入:

    def forward(self, x, adjacency):h = self.gnn1(x, adjacency)h = torch.relu(h)h = self.gnn2(h, adjacency)return F.log_softmax(h, dim=1)

(7) fit()test() 方法与 MLP 模型完全相同:

    def fit(self, data, epochs):criterion = torch.nn.CrossEntropyLoss()optimizer = torch.optim.Adam(self.parameters(),lr=0.01,weight_decay=5e-4)self.train()for epoch in range(epochs+1):optimizer.zero_grad()out = self(data.x, adjacency)loss = criterion(out[data.train_mask], data.y[data.train_mask])acc = accuracy(out[data.train_mask].argmax(dim=1),data.y[data.train_mask])loss.backward()optimizer.step()if(epoch % 20 == 0):val_loss = criterion(out[data.val_mask], data.y[data.val_mask])val_acc = accuracy(out[data.val_mask].argmax(dim=1),data.y[data.val_mask])print(f'Epoch {epoch:>3} | Train Loss: {loss:.3f} | Train Acc:'f' {acc*100:>5.2f}% | Val Loss: {val_loss:.2f} | 'f'Val Acc: {val_acc*100:.2f}%')@torch.no_grad()def test(self, data):self.eval()out = self(data.x, adjacency)acc = accuracy(out.argmax(dim=1)[data.test_mask], data.y[data.test_mask])return acc

(8) 创建、训练并评估模型:

gnn = VanillaGNN(dataset.num_features, 16, dataset.num_classes)
print(gnn)
# Train
gnn.fit(data, epochs=100)
# Test
acc = gnn.test(data)
print(f'\nGNN test accuracy: {acc*100:.2f}%')

输出结果如下所示:

VanillaGNN((gnn1): VanillaGNNLayer((linear): Linear(in_features=1433, out_features=16, bias=False))(gnn2): VanillaGNNLayer((linear): Linear(in_features=16, out_features=7, bias=False))
)
Epoch   0 | Train Loss: 2.626 | Train Acc: 16.43% | Val Loss: 2.56 | Val Acc: 7.40%
Epoch  20 | Train Loss: 0.274 | Train Acc: 95.71% | Val Loss: 1.22 | Val Acc: 67.60%
Epoch  40 | Train Loss: 0.046 | Train Acc: 100.00% | Val Loss: 1.40 | Val Acc: 74.60%
Epoch  60 | Train Loss: 0.015 | Train Acc: 100.00% | Val Loss: 1.60 | Val Acc: 74.00%
Epoch  80 | Train Loss: 0.008 | Train Acc: 100.00% | Val Loss: 1.65 | Val Acc: 73.40%
Epoch 100 | Train Loss: 0.005 | Train Acc: 100.00% | Val Loss: 1.68 | Val Acc: 72.00%GNN test accuracy: 74.40%

Facebook Page-Page 数据集重复相同的训练过程。为了获得具有可比性的结果,我们在每个数据集上对每个模型重复了 100 次相同的实验,实验结果如下表所示:

MLPGNN
Cora53.52%(±1.79%)75.01%(±1.53%)
Facebook75.22%(±0.51%)85.01%(±1.55%)

可以看到,MLPCora 上的准确率较低,在 Facebook Page-Page 数据集上的表现较好,但在这两种情况下 MLP 的性能均被 vanilla GNN 所超越。这些结果表明了在节点特征中包含拓扑信息的重要性,由于 GNN 不使用表格数据集训练,而是考虑了每个节点的整个邻域,因此准确率提高了 10~20%

小结

在本节中,我们了解了 Vanilla 神经网络和图神经网络 (Graph Neural Network, GNN)之间的差异,利用了一些简单的线性代数知识构建了香草图神经网络 (Vanilla Graph Neural Network, Vanilla GNN) 架构,同时使用了两个不同的图数据集,以便比较两种不同的架构。最后,使用 PyTorch 中实现了两种架构,并评估了它们的性能。结果表明,在这两个数据集上,即使是最简单的 Vanilla GNN 也完全优于 MLP

系列链接

图神经网络实战(1)——图神经网络(Graph Neural Networks, GNN)基础
图神经网络实战(2)——图论基础
图神经网络实战(3)——基于DeepWalk创建节点表示
图神经网络实战(4)——基于Node2Vec改进嵌入质量
图神经网络实战(5)——常用图数据集

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

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

相关文章

Vuepress 2从0-1保姆级进阶教程——美化与模板

Vuepress 2 专栏目录 1. 入门阶段 Vuepress 2从0-1保姆级入门教程——环境配置篇Vuepress 2从0-1保姆级入门教程——安装流程篇Vuepress 2从0-1保姆级入门教程——文档配置篇Vuepress 2从0-1保姆级入门教程——范例与部署 2.进阶阶段 Vuepress 2从0-1保姆级进阶教程——全文搜索…

一文即可帮助你认识进程和线程~

本文的重点:什么是:进程、进程调度、线程和他们之间的联系。主讲概念知识,不讲代码实现 目录 一、认识进程 1.什么是进程 2.进程的信息 3.进程调度(***) 4.进程调度的基本过程 二、线程 1.线程的引入 2.什么是线程 3.进程于线程的联…

Kubernetes常用命令汇总大全(备忘清单)

文章目录 1、查看资源信息1.1、节点1.2、容器组1.3、命名空间1.4、无状态服务1.5、服务1.6、守护进程集1.7、事件1.8、日志1.9、服务帐户1.10、副本集1.11、角色1.12、保密字典1.13、配置项1.14、路由1.15、持久卷1.16、持久卷声明1.17、存储类1.18、多个资源1.19、查看和查找资…

如何解决了“该虚拟机似乎正在使用中”问题

一、问题描述 1、在用VMware虚拟机的时候,有时会发现打开虚拟机时提示“该虚拟机似乎正在使用中。如果该虚拟机未在使用,请按“获取所有权(T)”按钮获取它的所有权。否则,请按“取消©”按钮以防损坏。配置文件: D:\win10x64\Windows 10…

ABC346 A-G 题解

ABC346 A-G题解 A题目AC Code:时间复杂度 B题目时间复杂度AC Code: C题目时间复杂度AC Code: D题目时间复杂度AC Code: E题目时间复杂度AC Code: F题目时间复杂度AC Code: G题目时间复杂度AC Code&#xff…

C语言牛客网BC-37 牛牛的圆(求面积)

题目如下 代码实现 #include<stdio.h> int main() { float r 0;float s 0;scanf("%f",&r);s 3.14*r*r;printf("%.2f",s);return 0; } 创作不易&#xff0c;点点关注&#xff0c;感谢支持&#xff01;&#xff01;&#xff01;

element表格 加滚动,监听底部实现分页加载

表格要实现滚动很简单&#xff0c;给他加一个高度即可 height"300" 然后是监听事件 mounted() {this.lazyLoading();}, methods:{lazyLoading(){let dom document.querySelector(".el-table__body-wrapper");dom.addEventListener("scroll", (…

ROS2从入门到精通0-4:ROS2核心架构与常用指令大全

目录 0 专栏介绍1 ROS2核心架构1.1 工作空间1.2 功能包 2 ROS2常用指令2.1 功能包相关2.2 节点运行相关2.3 话题相关2.4 参数相关2.4 录制包、播放包相关2.5 服务相关2.6 动作相关2.7 生命周期相关 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布…

【绘图案例-自定义进度条 Objective-C语言】

一、好,我们接着来说这个自定义进度条 1.这个Slider啊,简单的这个value属性,介绍完了,以后,监听也可以监听的到了,接下来,我们来做这个自定义进度条啊, 那么,首先啊,我是这么想的,在这个slider的最小值、和、最大值、我给它改成0、到、1、 因为如果这样的话,到时候…

展示大屏-24小时天气预报

一、项目说明 展示大屏显示未来一周天气和24小时天气详情。 二、技术工具 1.语言&框架&#xff1a;java、springboot 2.UI界面&#xff1a;jQuery、HTML、CSS、 VUE 3.开发工具&#xff1a;IntelliJ IDEA、Eclipse 三、实现步骤 后端步骤 1.调取免费或收费的API接口。 …

2024最赚钱的副业!一月轻松上万!实操分享快来学习!

​​每个人都玩抖音吧&#xff0c;我相信大家的手机上必有的两个软件&#xff0c;除了微信&#xff0c;就是抖音 但微信只有上班或者亲戚朋友来信息时才会打开看&#xff0c;而抖音是我们蹲厕所都要打开刷一刷的东西 那找兼职或副业的人有没有想过在抖音上赚钱 抖音最赚钱的…

【前端学习——js篇】11.元素可见区域

具体见&#xff1a;https://github.com/febobo/web-interview 11.元素可见区域 ①offsetTop、scrollTop offsetTop&#xff0c;元素的上外边框至包含元素的上内边框之间的像素距离&#xff0c;其他offset属性如下图所示&#xff1a; 下面再来了解下clientWidth、clientHeight…