当前位置: 首页 > news >正文

图神经网络实战(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)——常用图数据集

相关文章:

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

图神经网络实战(6)——使用PyTorch构建图神经网络 0. 前言1. 传统机器学习与人工智能2. 人工神经网络基础2.1 人工神经网络组成2.2 神经网络的训练 3. 图神经网络4. 使用香草神经网络执行节点分类4.1 数据集构建4.2 模型构建4.3 模型训练 5. 实现香草图神…...

【Flutter】windows环境配置

windows 11 环境 官方教程 配置了flutter 环境变量在系统的path里 bin 路径。 死活没反应 关闭了git关闭了dart.exe关闭了vs还是不行卸载重新来 新版git flutter doctor 还需要android 环境...

毕马威:《智慧之眼:开启汽车感知新时代》

在全球科技飞速发展和产业革新的大潮中,汽车产业正在以前所未有的速度向网联化、智能化的方向转型。汽车传感器作为智能联网汽车发展的关键环节之一,扮演着举足轻重的角色。 毕马威一直关注汽车产业的变化与发展,为了更好地为汽车行业赋能&a…...

每日三个JAVA经典面试题(三十四)

1.Mybatis的一级、二级缓存 MyBatis提供了两种缓存机制来提高查询效率:一级缓存和二级缓存。 一级缓存(Session级别) 作用范围:一级缓存是基于SqlSession的。这意味着,如果你在同一个SqlSession中执行两次相同的查询…...

C# 学习第五弹——语句

一、if语句 —简单if语句 —if else 语句 —if else if else 语句 1、简单if语句 if(表达式){语句} (1)表达式必须使用圆括号括起来; (2)表达式:关系表达式或逻辑表达…...

什么是Java中的JVM(Java虚拟机)?它如何工作?

Java中的JVM,全称Java Virtual Machine(Java虚拟机),是Java程序的运行环境,也是Java语言的核心和基础。它是一个虚拟的计算机,具有完善的硬体架构,如处理器、堆栈、寄存器等,以及相应…...

OmniGraffle Pro for mac 出色的图形设计软件

OmniGraffle Pro是一款非常出色的图形设计软件,它主要适用于Mac和iPad平台,可以用来轻松绘制各种精美的图表、示意图和界面设计。 软件下载:OmniGraffle Pro for mac中文注册激活版 以下是OmniGraffle Pro的一些主要特点和功能: 界…...

代码随想录阅读笔记-二叉树【合并二叉树】

题目 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节…...

Day35:学习尚上优选项目

学习计划:完成尚硅谷的尚上优选项目 学习进度:尚上优选项目 知识点: 四、 搭建平台管理端前端环境 权限管理模块-用户管理 开发为用户分配角色接口用户管理前端测试 权限管理模块-菜单管理 菜单管理需求菜单表设计开发菜单管理CRUD接口开…...

c模板编程c/c++20240401

c模板编程 #include<iostream> //#include<string> //#include<algorithm> template <typename T> T max(T a, T b) { return (a > b) ? a : b; } int main() { int i max(1, 2); // 返回 2 float f max(3.14f, 2.72f); // 返回 3…...

【TI毫米波雷达】IWR6843AOP的官方文件资源名称BUG,选择xwr68xx还是xwr64xx,及需要注意的问题

【TI毫米波雷达】IWR6843AOP的官方文件资源名称BUG&#xff0c;选择xwr68xx还是xwr64xx&#xff0c;及需要注意的问题 文章目录 demo工程out_of_box文件调试bin文件名称需要注意的问题附录&#xff1a;结构框架雷达基本原理叙述雷达天线排列位置芯片框架Demo工程功能CCS工程导…...

连接Redis不支持集群错误,ERR This instance has cluster support disabled,解决方案

1. 问题背景 调整redis的配置后&#xff0c;启动程序时&#xff0c; 会报如下错误&#xff1a; [redis://172.16.0.8xxx]: ERR This instance has cluster support disabledSuppressed: io.lettuce.core.RedisCommandExecutionException: ERR This instance has cluster supp…...

什么是json?json可以存放哪几种数据类型

JSON指的是JavaScript对象表示法(avaScript Object Notation)&#xff0c;是轻量级的文本数据交换格式&#xff0c;独立于语言: JSON使用JavaScript语法来描述数据对象&#xff0c;但是JSON仍然独立于语言和平台&#xff0c;JSON解析器和JSON库支持许多不同的编程语言&#xff…...

网络编程套接字应用分享【Linux C/C++ 】【UDP应用 | TCP应用 | TCP线程池小项目】

目录 前提知识 1. 理解源ip&#xff0c;目的ip和Macip 2. 端口号 3. 初识TCP&#xff0c;UDP协议 4. 网络字节序 5. socket 编程 sockaddr类型 一&#xff0c;基于udp协议编程 1. socket——创建套接字 2. bind——将套接字强绑定 3. recvfrom——接受数据 4. s…...

有关数据开发项目中使用HIVE由于无法update和delete的场景下,如何解决数据增量的思路

解决数据增量问题的思路在Hive中 在数据开发项目中&#xff0c;使用Hive进行数据处理时&#xff0c;由于Hive不支持update和delete语句&#xff0c;处理数据增量可能会变得有些棘手。然而&#xff0c;有几种策略和技术可以帮助我们解决这个问题&#xff0c;并确保数据增量的高…...

两数之和-考察哈希表的运用

题目 给定一个整数数组 n u m s nums nums和一个整数目标值 t a r g e t target target&#xff0c;请你在该数组中找出和为目标值 t a r g e t target target的那 两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同…...

视觉检测系统,外观细节无可挑剔

在传统行业中&#xff0c;利用人工检测来检测产品外观缺陷依然是主流&#xff0c;但由于竞争的加剧&#xff0c;对企业生产效率的要求也越来越高。传统的检测产品外观缺陷问题的方法就是透过人工目检&#xff0c;或者工人采用游标卡尺等工具检测&#xff0c;此种方式检测速度慢…...

C++中string容器的字符串操作

目录 1.c_str() 返回C常量字符串 2.date() 返回C常量字符串 3.substr() 构造子串 4.find() 正向查找&#xff08;查找失败返回npos&#xff09; 5.rfind() 逆向查找&#xff08;查找失败返回npos&#xff09; 6.find_first_of() 正向查找匹配的字符 7.find_last_of() 逆向…...

Java编程使用CGLIB动态代理介绍与实战演示

文章目录 前言技术积累核心概念主要功能适用场景与JDK动态代理的对比 实战演示定义待代理的目标类实现MethodInterceptor接口使用代理对象 测试结果写在最后 前言 在Java编程中&#xff0c;CGLIB (Code Generation Library) 是一个强大的高性能代码生成库&#xff0c;它通过生…...

vue3 渲染一个后端返回的图片字段渲染、table表格内放置图片

一、后端直接返回图片url 当图片字段接口直接返回的是图片url&#xff0c;可以直接放到img标签上 <img v-if"thumbLoader" class"r-image-loader-thumb" :src"resUrl" /> 二、当图片字段接口直接返回的是图片Id 那么就需要去拼一下图片…...

iOS开发进阶(十三):脚手架创建iOS项目

文章目录 一、前言二、xcode-select 命令三、拓展阅读 一、前言 项目初期&#xff0c;需要搭建项目基本框架&#xff0c;为此离不开辅助工具&#xff0c;即脚手架。当然&#xff0c;IDE也可以实现新建空白项目&#xff0c;但是其新建后的项目结构可能不符合预期设计&#xff0…...

手机无线投屏到windows11电脑

1 安装无线投影组件 2 电脑端打开允许其他设备投影的开关 3 手机找到投屏选项 4 手机搜索可用设备连接即可 这里的官方文档给的不太好,给了一些让人眼花撩乱的信息,以下是经过整合的有效信息...

linux 环境安装配置

安装java17 1.下载安装包 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 2.解压到自定义目录/usr/local/java mkdir /usr/local/java tar zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java 3.配置环境变量 echo export PATH$PATH:/…...

Git常用语句

设置用户名 git config --global user.name "用户名" git config --global user.email "邮箱"查看git用户信息 cat ~/.gitconfig初始化本地库 git initclone指定分支的代码 git clone -b my_branch gitgitlabxxxxxxxxxxxxxxxxxxxxxx.gitpush三件套 gi…...

坦克大战_java源码_swing界面_带毕业论文

一. 演示视频 坦克大战_java源码_swing界面_带毕业论文 二. 实现步骤 完整项目获取 https://githubs.xyz/y22.html 部分截图 启动类是 TankClinet.java&#xff0c;内置碰撞检测算法&#xff0c;线程&#xff0c;安全集合&#xff0c;一切皆对象思想等&#xff0c;是java进阶…...

JVM 记录

记录 工具 https://gceasy.io 资料 尚硅谷宋红康JVM全套教程&#xff08;详解java虚拟机&#xff09; https://www.bilibili.com/video/BV1PJ411n7xZ?p361 全套课程分为《内存与垃圾回收篇》《字节码与类的加载篇》《性能监控与调优篇》三个篇章。 上篇《内存与垃圾回收篇…...

Linux学习笔记————C 语言版 LED 灯实验

这里写目录标题 一、实验程序编写二、 汇编部分实验程序编写三、C 语言部分实验程序编写四、编译下载验证 汇编 LED 灯实验中&#xff0c;我们讲解了如何使用汇编来编写 LED 灯驱动&#xff0c;实际工作中是很少用到汇编去写嵌入式驱动的&#xff0c;毕竟汇编太难&#xff0c;而…...

Spring Boot 配置文件

1. 配置文件的作用 配置文件主要是为了解决硬件编码带来的问题&#xff0c;把可能会发生改变的信息&#xff0c;放在一个集中的地方&#xff0c;当我们启动某个程序时&#xff0c;程序从配置文件中读取一些数据&#xff0c;并加载运行。 硬编码是将数据直接放在源代码中&…...

IPKISS ------ 查看器件默认端口名称

IPKISS ------ 查看器件默认端口名称 正文正文 我们这里以 Grating Coupler 举例。 import si_fab.all as pdk import ipkiss3.all as i3class MyGratingCoupler(i3.circuit):gc = i3.childcellProperty(<...

uni-app踩坑记录

uni-app踩坑记录 Failed to load local image resource xxx the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) Failed to load local image resource xxx the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) 文…...

河北邯郸网站建设公司/厦门seo排名优化

装饰器系列&#xff1a; [1]. Python装饰器(decorator)系列 — 面向对象以及装饰器 [2]. Python装饰器(decorator)系列 — 编写无参数的装饰器 [3]. Python装饰器(decorator)系列 — 编写带参数的装饰器 类(class)&#xff1a;是对现实世界中一些事物的封装 类中包含类的属性和…...

西安市建设和住房保障局网站/平台营销

Oracle GoldenGate管理包针对OGG提供企业级的监控和管理&#xff0c;包含有如下模块&#xff1a;Oracle Enterprise Manager Plug-in. 利用OEM框架查看、管理和预警OGGOracle GoldenGate Monitor. 一个独立查看、管理、预警OGG的产品&#xff0c;同时提供点对点的拓扑查看&…...

平台网站开发公司/中国搜索引擎排名2021

我想知道如何区分具有相同名称的静态和非静态方法引用.在我的例子中,我有一个名为StringCollector的类,它有以下三种方法&#xff1a;StringCollector append(String string)static StringCollector append(StringCollector stringCollector,String string)StringCollector con…...

商业网站制作教程/广州百度关键词搜索

什么是API设计&#xff1f; 优秀的设计是产品变得卓越的原因。设计API意味着提供有效的接口&#xff0c;可以帮助API使用者更好地了解、使用和集成&#xff0c;同时帮助人们有效地维护它。每个产品都需要使用手册&#xff0c;API也不例外。 在API领域&#xff0c;可以将设计视…...

云主机搭建网站/网页点击量统计

文章目录前言分布式系统升级的状态转化关于Upgrade需要注意的点关于Downgrade需要注意的点引用前言 对于一个系统来说&#xff0c;进行定期的升级维护是一件比较常见的事情。但是对于复杂分布式系统的升级&#xff0c;系统管理员系统考虑更多的因素来做升级这个事情。同时对于分…...

网络广告推广平台有哪些/seo分析

原文地址&#xff1a;https://www.2cto.com/kf/201610/560348.html Logstash的使用 logstash支持把配置写入文件 xxx.conf&#xff0c;然后通过读取配置文件来采集数据./bin/logstash –f xxx.conflogstash最终会把数据封装成json类型&#xff0c;默认会添加timestamp时间字段、…...