Last but not least
运行系统:macOS Sequoia 15.0
Python编译器:PyCharm 2024.1.4 (Community Edition)
Python版本:3.12
TensorFlow版本:2.17.0
Pytorch版本:2.4.1
往期链接:
| 1-5 | 6-10 | 11-20 | 21-30 | 31-40 | 41-50 |
|---|
| 51-60:函数 | 61-70:类 | 71-80:编程范式及设计模式 |
|---|
| 81-90:Python编码规范 | 91-100:Python自带常用模块-1 |
|---|
| 101-105:Python自带模块-2 | 106-110:Python自带模块-3 |
|---|
| 111-115:Python常用第三方包-频繁使用 | 116-120:Python常用第三方包-深度学习 |
|---|
| 121-125:Python常用第三方包-爬取数据 | 126-130:Python常用第三方包-为了乐趣 |
|---|
| 131-135:Python常用第三方包-拓展工具1 | 136-140:Python常用第三方包-拓展工具2 |
|---|
Python项目实战
| 141-145 | 146-150 | 151-155 | 156-160 | 161-165 | 166-170 | 171-175 |
|---|
| 176-180:卷积结构 | 181-182:卷积结构(续) | 183-185:时间、序列数据1 | 186-190:时间、序列数据2 | 191-195:Python资源 |
|---|
前言–图神经网络(Graph Neural Networks, GNNs)
定义
图神经网络是一类专门处理图结构数据的深度学习模型。图是一种数据结构,由节点(顶点)和边(连接节点的关系)组成,广泛应用于社交网络、推荐系统、知识图谱、生物信息学等领域。GNN 通过节点的特征和图的拓扑结构来学习节点、边或整个图的表示。
图的基本概念
- 节点:图中的基本单元,表示对象。
- 边:连接节点的关系,可以是有向的或无向的,表示节点之间的交互。
- 图结构:图的整体形状和连接模式,决定了节点之间的信息传递方式。
GNN 的工作原理
GNN 通过迭代更新节点的表示(embedding),利用其邻居节点的信息来增强自身的特征表示。基本步骤如下:
- 消息传递(Message Passing):
- 每个节点从其邻居节点接收特征信息。
- 通过聚合(aggregation)操作,汇总邻居节点的信息。
- 更新(Update):
- 根据接收到的信息更新节点的表示。
- 更新过程通常使用非线性函数(如 ReLU)和可学习的参数。
- 读取(Readout):
- 在图的任务(如图分类)中,最终会将节点表示整合为图的整体表示。
GNN 的类型
- 图卷积网络(GCN):
通过局部卷积操作聚合邻居节点信息,从而学习节点表示。 - 图注意力网络(GAT):
通过自注意力机制,动态地为邻居节点分配不同的权重,增强重要节点的影响。 - 图同构网络(GIN):
通过设计强大的聚合函数,使模型在图同构性方面表现更佳。
应用领域
- 社交网络分析:预测用户行为、推荐好友等。
- 推荐系统:基于用户和物品的图结构,提供个性化推荐。
- 生物信息学:药物发现、蛋白质交互预测等。
- 自然语言处理:知识图谱的构建和推理。
优势与挑战
- 优势
- 处理复杂结构:GNN 能够有效处理图数据中复杂的结构信息。
- 利用邻居信息:通过聚合邻居节点的特征,提升节点表示的质量。
- 挑战
- 计算复杂性:在大规模图中,消息传递和聚合操作可能导致计算开销增大。
- 图的动态性:如何处理动态变化的图结构仍然是一个研究难点。
P196-- Graph Convolutional Networks (GCNs)
模型说明
Thomas Kipf 和 Max Welling 在2016年提出了论文《Semi-Supervised Classification with Graph Convolutional Networks》,这是 GCN 的基础理论。
核心思想:
通过卷积操作在图结构上进行特征学习,尤其适用于半监督学习任务。
基本架构:
(1)GCN 使用层次化的结构,允许节点通过其邻居的信息进行特征更新。
(2)提出了通过邻接矩阵的归一化来处理图的稀疏性。
影响:
(1)GCN 成为众多图神经网络的基础,为后来的研究奠定了重要的理论基础。
(2)其思想和框架被广泛应用于节点分类、图分类、链接预测等任务。
模型主要特征
- 局部特征聚合:
GCN 通过邻居节点的特征聚合来更新目标节点的特征,实现信息传递。 - 谱图卷积:
使用谱图理论,计算图的拉普拉斯矩阵,从频域上进行卷积操作。 - 半监督学习能力:
GCN 可以在部分标签数据的情况下进行学习,适合大规模图数据。 - 可扩展性:
GCN 通过层次化的方法,能够有效处理大规模图,避免了全图计算的高昂成本。 - 简单易用:
GCN 的结构相对简单,易于实现和扩展,成为后续研究的基础模型。
Python示例
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import GCNConv
import torch.optim as optim
# 定义 GCN 模型
class GCN(torch.nn.Module):
def __init__(self, num_node_features, num_classes):
super(GCN, self).__init__()
self.conv1 = GCNConv(num_node_features, 16)
self.conv2 = GCNConv(16, num_classes)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
# 加载数据集
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 初始化模型、损失函数和优化器
model = GCN(num_node_features=dataset.num_node_features, num_classes=dataset.num_classes)
optimizer = optim.Adam(model.parameters(), lr=0.01)
criterion = F.nll_loss
# 训练模型
def train():
model.train()
optimizer.zero_grad()
out = model(data)
loss = criterion(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
return loss.item()
# 测试模型
def test():
model.eval()
with torch.no_grad():
out = model(data)
pred = out.argmax(dim=1) # 获取预测的类别
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() # 计算正确预测的数量
accuracy = int(correct) / int(data.test_mask.sum()) # 计算准确率
return accuracy
# 训练和测试循环
num_epochs = 200
for epoch in range(num_epochs):
loss = train()
if (epoch + 1) % 20 == 0:
acc = test()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}, Test Accuracy: {acc:.4f}')
# 最终测试
final_accuracy = test()
print(f'Final Test Accuracy: {final_accuracy:.4f}')
首次运行会下载程序所用的数据集。
Epoch [20/200], Loss: 0.1071, Test Accuracy: 0.7800
Epoch [40/200], Loss: 0.0086, Test Accuracy: 0.7750
Epoch [60/200], Loss: 0.0035, Test Accuracy: 0.7750
Epoch [80/200], Loss: 0.0024, Test Accuracy: 0.7750
Epoch [100/200], Loss: 0.0019, Test Accuracy: 0.7770
Epoch [120/200], Loss: 0.0015, Test Accuracy: 0.7780
Epoch [140/200], Loss: 0.0013, Test Accuracy: 0.7800
Epoch [160/200], Loss: 0.0011, Test Accuracy: 0.7830
Epoch [180/200], Loss: 0.0009, Test Accuracy: 0.7830
Epoch [200/200], Loss: 0.0008, Test Accuracy: 0.7830
Final Test Accuracy: 0.7830
P197-- Graph Attention Networks (GATs)
模型说明
GAT 由 Petar Veličković 等人在2018年的论文《Graph Attention Networks》中提出,首次引入了图中的自注意力机制。GAT 通过自注意力机制为不同邻居节点分配不同的权重,从而增强信息聚合的灵活性和有效性。
模型主要特征
- 自注意力机制:
GAT 通过计算节点之间的注意力权重,允许模型在聚合邻居特征时自适应地关注不同的邻居。 - 节点特征聚合:
每个节点在更新特征时考虑其邻居节点的特征及其权重,实现信息的动态聚合。 - 多头注意力:
GAT 引入了多头注意力机制,允许模型在不同的子空间中学习多个注意力分布,从而提高特征表达能力。 - 灵活性:
GAT 可以处理不同类型的图和动态变化的图结构,适用于多种实际场景。 - 无须图的全局结构:
与传统的图卷积网络不同,GAT 不需要全局的图结构信息,能够在局部范围内进行有效的特征学习。
Python示例
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import GATConv
import torch.optim as optim
# 定义 GAT 模型
class GAT(torch.nn.Module):
def __init__(self, num_node_features, num_classes):
super(GAT, self).__init__()
self.conv1 = GATConv(num_node_features, 8, heads=8) # 第一层
self.conv2 = GATConv(8 * 8, num_classes, heads=1, concat=False) # 第二层
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.elu(x) # 使用 ELU 激活函数
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
# 加载数据集
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 初始化模型、损失函数和优化器
model = GAT(num_node_features=dataset.num_node_features, num_classes=dataset.num_classes)
optimizer = optim.Adam(model.parameters(), lr=0.005)
criterion = F.nll_loss
# 训练模型
def train():
model.train()
optimizer.zero_grad()
out = model(data)
loss = criterion(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
return loss.item()
# 测试模型
def test():
model.eval()
with torch.no_grad():
out = model(data)
pred = out.argmax(dim=1) # 获取预测的类别
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() # 计算正确预测的数量
accuracy = int(correct) / int(data.test_mask.sum()) # 计算准确率
return accuracy
# 训练和测试循环
num_epochs = 200
for epoch in range(num_epochs):
loss = train()
if (epoch + 1) % 20 == 0:
acc = test()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}, Test Accuracy: {acc:.4f}')
# 最终测试
final_accuracy = test()
print(f'Final Test Accuracy: {final_accuracy:.4f}')
结果
Epoch [20/200], Loss: 0.0281, Test Accuracy: 0.7520
Epoch [40/200], Loss: 0.0012, Test Accuracy: 0.7290
Epoch [60/200], Loss: 0.0005, Test Accuracy: 0.7240
Epoch [80/200], Loss: 0.0004, Test Accuracy: 0.7220
Epoch [100/200], Loss: 0.0003, Test Accuracy: 0.7230
Epoch [120/200], Loss: 0.0003, Test Accuracy: 0.7220
Epoch [140/200], Loss: 0.0002, Test Accuracy: 0.7220
Epoch [160/200], Loss: 0.0002, Test Accuracy: 0.7210
Epoch [180/200], Loss: 0.0002, Test Accuracy: 0.7210
Epoch [200/200], Loss: 0.0002, Test Accuracy: 0.7200
Final Test Accuracy: 0.7200
P198-- GraphSAGE (Graph Sample and Aggregation)
模型说明
GraphSAGE 由 William L. Hamilton 等人在2017年的论文《Inductive Representation Learning on Large Graphs》中提出,首次引入了基于采样的图卷积网络。GraphSAGE 旨在处理大规模图,并允许模型在未见过的节点上进行归纳学习。通过采样邻居节点来聚合特征,实现高效学习。
GraphSAGE 的设计使其能够在新节点上进行推理,这对于动态和不断变化的图结构非常重要。GraphSAGE 提出了多种聚合方法,如均值聚合、LSTM 聚合和池化聚合,以适应不同的应用场景。
模型的主要特征
- 采样邻居:
GraphSAGE 使用采样技术,从每个节点的邻居中随机选择一部分进行特征聚合,避免了全图计算的高昂成本。 - 多种聚合函数:
支持多种聚合函数(如均值、LSTM、池化等),可根据具体任务选择最合适的聚合方式。 - 归纳学习能力:
能够在未见过的节点上进行推理,适合动态变化的图结构。 - 可扩展性:
适合大规模图,具有良好的计算效率和存储效率。 - 灵活性:
可以轻松适应各种类型的图数据,包括异构图和动态图。
Python示例
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import SAGEConv
import torch.optim as optim
# 定义 GraphSAGE 模型
class GraphSAGE(torch.nn.Module):
def __init__(self, num_node_features, num_classes):
super(GraphSAGE, self).__init__()
self.conv1 = SAGEConv(num_node_features, 16) # 第一层
self.conv2 = SAGEConv(16, num_classes) # 第二层
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x) # 使用 ReLU 激活函数
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
# 加载数据集
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 初始化模型、损失函数和优化器
model = GraphSAGE(num_node_features=dataset.num_node_features, num_classes=dataset.num_classes)
optimizer = optim.Adam(model.parameters(), lr=0.01)
criterion = F.nll_loss
# 训练模型
def train():
model.train()
optimizer.zero_grad()
out = model(data)
loss = criterion(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
return loss.item()
# 测试模型
def test():
model.eval()
with torch.no_grad():
out = model(data)
pred = out.argmax(dim=1) # 获取预测的类别
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() # 计算正确预测的数量
accuracy = int(correct) / int(data.test_mask.sum()) # 计算准确率
return accuracy
# 训练和测试循环
num_epochs = 200
for epoch in range(num_epochs):
loss = train()
if (epoch + 1) % 20 == 0:
acc = test()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}, Test Accuracy: {acc:.4f}')
# 最终测试
final_accuracy = test()
print(f'Final Test Accuracy: {final_accuracy:.4f}')
结果
Epoch [20/200], Loss: 0.0025, Test Accuracy: 0.7230
Epoch [40/200], Loss: 0.0001, Test Accuracy: 0.7250
Epoch [60/200], Loss: 0.0001, Test Accuracy: 0.7250
Epoch [80/200], Loss: 0.0001, Test Accuracy: 0.7290
Epoch [100/200], Loss: 0.0000, Test Accuracy: 0.7290
Epoch [120/200], Loss: 0.0000, Test Accuracy: 0.7280
Epoch [140/200], Loss: 0.0000, Test Accuracy: 0.7260
Epoch [160/200], Loss: 0.0000, Test Accuracy: 0.7280
Epoch [180/200], Loss: 0.0000, Test Accuracy: 0.7280
Epoch [200/200], Loss: 0.0000, Test Accuracy: 0.7330
Final Test Accuracy: 0.7330
P199-- ChebNet
模型说明
ChebNet 由 Michaël Defferrard 等人在2016年的论文《Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering》中提出,首次引入了图卷积的谱方法。ChebNet 通过切比雪夫多项式来近似图卷积操作,提供了一种高效的计算方式,避免了昂贵的特征计算。ChebNet 采用谱图卷积的思想,利用图拉普拉斯算子及其特征分解,进行特征提取和卷积操作。
通过切比雪夫多项式,ChebNet 能够实现高效的局部化图卷积,同时减少计算复杂度,使得大规模图的处理成为可能。
模型主要特征
- 切比雪夫多项式:
ChebNet 使用切比雪夫多项式来近似卷积操作,提供了快速的局部化滤波。 - 谱图卷积:
通过将卷积操作转化到谱域,ChebNet 实现了对图数据的有效特征提取。 - 局部化特征提取:
ChebNet 能够在图的局部结构中提取特征,适合处理大规模稀疏图。 - 高效计算:
相较于传统的谱方法,ChebNet 在计算上更为高效,适用于实时和大规模应用。 - 灵活性:
ChebNet 可以轻松适应不同类型的图数据,并在多种任务中表现良好。
Python示例
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import ChebConv
import torch.optim as optim
# 定义 ChebNet 模型
class ChebNet(torch.nn.Module):
def __init__(self, num_node_features, num_classes, K=3):
super(ChebNet, self).__init__()
self.conv1 = ChebConv(num_node_features, 16, K) # 第一层
self.conv2 = ChebConv(16, num_classes, K) # 第二层
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x) # 使用 ReLU 激活函数
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
# 加载数据集
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 初始化模型、损失函数和优化器
model = ChebNet(num_node_features=dataset.num_node_features, num_classes=dataset.num_classes)
optimizer = optim.Adam(model.parameters(), lr=0.01)
criterion = F.nll_loss
# 训练模型
def train():
model.train()
optimizer.zero_grad()
out = model(data)
loss = criterion(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
return loss.item()
# 测试模型
def test():
model.eval()
with torch.no_grad():
out = model(data)
pred = out.argmax(dim=1) # 获取预测的类别
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() # 计算正确预测的数量
accuracy = int(correct) / int(data.test_mask.sum()) # 计算准确率
return accuracy
# 训练和测试循环
num_epochs = 200
for epoch in range(num_epochs):
loss = train()
if (epoch + 1) % 20 == 0:
acc = test()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}, Test Accuracy: {acc:.4f}')
# 最终测试
final_accuracy = test()
print(f'Final Test Accuracy: {final_accuracy:.4f}')
结果
Epoch [20/200], Loss: 0.0002, Test Accuracy: 0.7730
Epoch [40/200], Loss: 0.0000, Test Accuracy: 0.7710
Epoch [60/200], Loss: 0.0000, Test Accuracy: 0.7770
Epoch [80/200], Loss: 0.0000, Test Accuracy: 0.7770
Epoch [100/200], Loss: 0.0000, Test Accuracy: 0.7810
Epoch [120/200], Loss: 0.0000, Test Accuracy: 0.7820
Epoch [140/200], Loss: 0.0000, Test Accuracy: 0.7830
Epoch [160/200], Loss: 0.0000, Test Accuracy: 0.7790
Epoch [180/200], Loss: 0.0000, Test Accuracy: 0.7800
Epoch [200/200], Loss: 0.0000, Test Accuracy: 0.7810
Final Test Accuracy: 0.7810
P200-- Relational Graph Convolutional Networks (R-GCNs)
模型说明
R-GCN 由 Schlichtkrull 等人在2017年的论文《Modeling Relational Data with Graph Convolutional Networks》中提出,首次引入了针对多关系图的卷积网络。R-GCN 扩展了传统的图卷积网络(GCN),能够有效处理具有多种关系类型的图数据(如知识图谱),并通过使用不同的权重矩阵来学习每种关系的重要性。R-GCN 提出了针对不同关系类型的聚合方式,使得模型能够学习到更丰富的节点表示。
模型主要特征
- 多关系处理:
R-GCN 设计了专门的机制来处理多种类型的边(关系),每种关系都有独立的权重矩阵。 - 局部聚合:
与 GCN 类似,R-GCN 使用局部聚合的方式更新节点特征,避免全图计算的高昂成本。 - 归一化机制:
R-GCN 引入了归一化机制,以防止邻居节点数量不同所带来的影响,保证特征聚合的稳定性。 - 可扩展性:
R-GCN 能够处理大规模图数据,适合用于动态和复杂的关系网络。 - 灵活性:
能够应用于多种任务,包括节点分类、链接预测和图分类等。
Python示例
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import RGCNConv
import torch.optim as optim
# 定义 R-GCN 模型
class RGCN(torch.nn.Module):
def __init__(self, num_node_features, num_classes, num_relations):
super(RGCN, self).__init__()
self.conv1 = RGCNConv(num_node_features, 16, num_relations) # 第一层
self.conv2 = RGCNConv(16, num_classes, num_relations) # 第二层
def forward(self, data):
x, edge_index, edge_type = data.x, data.edge_index, data.edge_type
x = self.conv1(x, edge_index, edge_type)
x = F.relu(x) # 使用 ReLU 激活函数
x = self.conv2(x, edge_index, edge_type)
return F.log_softmax(x, dim=1)
# 加载数据集(以 Cora 为例)
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 由于 Cora 是无关系图,这里我们简单模拟关系
data.edge_type = torch.zeros(data.edge_index.size(1), dtype=torch.long)
# 初始化模型、损失函数和优化器
num_relations = 1 # Cora 数据集仅有一种关系
model = RGCN(num_node_features=dataset.num_node_features, num_classes=dataset.num_classes, num_relations=num_relations)
optimizer = optim.Adam(model.parameters(), lr=0.01)
criterion = F.nll_loss
# 训练模型
def train():
model.train()
optimizer.zero_grad()
out = model(data)
loss = criterion(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
return loss.item()
# 测试模型
def test():
model.eval()
with torch.no_grad():
out = model(data)
pred = out.argmax(dim=1) # 获取预测的类别
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() # 计算正确预测的数量
accuracy = int(correct) / int(data.test_mask.sum()) # 计算准确率
return accuracy
# 训练和测试循环
num_epochs = 200
for epoch in range(num_epochs):
loss = train()
if (epoch + 1) % 20 == 0:
acc = test()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}, Test Accuracy: {acc:.4f}')
# 最终测试
final_accuracy = test()
print(f'Final Test Accuracy: {final_accuracy:.4f}')
结果
Epoch [20/200], Loss: 0.0023, Test Accuracy: 0.7490
Epoch [40/200], Loss: 0.0001, Test Accuracy: 0.7520
Epoch [60/200], Loss: 0.0001, Test Accuracy: 0.7520
Epoch [80/200], Loss: 0.0001, Test Accuracy: 0.7500
Epoch [100/200], Loss: 0.0001, Test Accuracy: 0.7490
Epoch [120/200], Loss: 0.0000, Test Accuracy: 0.7480
Epoch [140/200], Loss: 0.0000, Test Accuracy: 0.7500
Epoch [160/200], Loss: 0.0000, Test Accuracy: 0.7520
Epoch [180/200], Loss: 0.0000, Test Accuracy: 0.7500
Epoch [200/200], Loss: 0.0000, Test Accuracy: 0.7480
Final Test Accuracy: 0.7480
1109

被折叠的 条评论
为什么被折叠?



