Advertisement

【Deep Learning 11】Graph Neural Network

阅读量:

🌞欢迎来到图神经网络的世界
🌈博客主页:卿云阁

💌欢迎关注🎉点赞👍收藏⭐️留言📝

🌟本文由卿云阁原创!

📆首发时间:🌹2024年3月20日🌹

✉️希望可以和大家一起完成进阶之路!

🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢!


目录

GNN起源

图的矩阵表示

层内与层间的消息传递

GCN

GraphSAGE

代码实战

GAT

代码实战


GNN起源

(1)数学中的空间有很多种,大部分都是定义在欧氏里德空间的,比如图像,文本。除此之外还存在着大量的非欧空间,比如分子结构。

(2) 图嵌入常⻅模型有DeepWalk,Node2Vec等,然而,这些方法方法有两种严重的缺点,首先就是节点编码中权重未共享,导致权重数量随着节点增多而线性增大,另外就是直接嵌入方法缺乏泛化能力,意味着无法处理动态图以及泛化到新的图。

如何把这种图结构嫁接到神经网络上,图神经网络就诞生了。和传统的神经网络结构相比,它解决了两个问题。

  • 图结构的矩阵画表示
  • 层内与层间的消息传递
图的矩阵表示
  • 借用邻接矩阵
  • 考虑稀疏性,还可以使用邻接表。
层内与层间的消息传递

聚合

简单来说一个节点或者边的特征,不光看它自己,还要由它相邻元素的加权求和决定。层内的聚合常常被称之为池化

层级间的关系传递,通过节点的连接关系进行,也可以看成是一种聚合,根据聚合方法的差异形成了不同的算法,最简单的是图卷积网络GCN 。就是在层间经过邻域聚合实现卷积特征提取。左乘于邻接矩阵表示对每个节点来说,该节点的特征为邻域节点的特征,相加之后的结果。

如果聚合的时候没有用全部的邻域节点,而是先采样再聚合,就是GraphSAGE算法。

如果聚合的时候考虑了领域节点的权重,也就是运用了注意力机制,那么就是图注意力网络GAT

聚合还可以用在非监督模型上,比如把图和变自分编码器相结合,形成GAE算法

除此之外还有更复杂的图生成网络 ,和图时空网络


GCN

原理解析:

代码实战:

复制代码
>       1. import torch

>  
>       2. import torch.nn as nn
>  
>       3. import dgl
>  
>       4. import dgl.function as fn
>  
>       5. import networkx as nx
>  
>       6. import matplotlib.pyplot as plt
>  
>       7. from rdkit import Chem
>  
>       8. from rdkit.Chem import Draw
>  
>       9.  
>  
>       10. # 构建阿司匹林分子
>  
>       11. aspirin_smiles = "CC(=O)OC1=CC=CC=C1C(=O)O"
>  
>       12. aspirin_mol = Chem.MolFromSmiles(aspirin_smiles)
>  
>       13.  
>  
>       14. # 构建分子图
>  
>       15. aspirin_graph = dgl.from_networkx(nx.Graph(Chem.rdmolops.GetAdjacencyMatrix(aspirin_mol)))
>  
>       16.  
>  
>       17. # 可视化分子结构
>  
>       18. Draw.MolToImage(aspirin_mol)
>  
>       19.  
>  
>       20. # 定义GCN模型
>  
>       21. class GCN(nn.Module):
>  
>       22.     def __init__(self, in_feats, hidden_size, num_classes):
>  
>       23.         super(GCN, self).__init__()
>  
>       24.         self.conv1 = dgl.nn.GraphConv(in_feats, hidden_size)
>  
>       25.         self.conv2 = dgl.nn.GraphConv(hidden_size, num_classes)
>  
>       26.  
>  
>       27.     def forward(self, g, features):
>  
>       28.         h = self.conv1(g, features)
>  
>       29.         h = torch.relu(h)
>  
>       30.         h = self.conv2(g, h)
>  
>       31.         return h
>  
>       32.  
>  
>       33. # 初始化GCN模型
>  
>       34. input_dim = 1  # 输入特征维度为1,因为我们只考虑一个原子的属性
>  
>       35. hidden_size = 64
>  
>       36. num_classes = 2  # 为简单起见,假设我们的任务是二分类
>  
>       37. gcn_model = GCN(input_dim, hidden_size, num_classes)
>  
>       38.  
>  
>       39. # 可视化GCN模型结构
>  
>       40. print(gcn_model)
>  
>       41.  
>  
>       42. # 可视化分子图
>  
>       43. plt.figure(figsize=(8, 6))
>  
>       44. nx.draw(aspirin_graph.to_networkx(), with_labels=True, node_color='skyblue', node_size=800, font_size=12, font_weight='bold', edge_color='gray')
>  
>       45. plt.title('Molecular Graph')
>  
>       46. plt.show()
>  
>  
>  
>  
>     
>  
>     ![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-14/x0KjSi4sHubAITFBQJeZEgDakOwd.png)

GraphSAGE

代码实战

我们来实现了一个简单的 GraphSAGE 模型,并对阿司匹林的分子结构进行预测。首先,我们需要构建一个简单的图结构来表示阿司匹林的分子。然后,我们将定义一个GraphSAGE 模型,并使用该模型对阿司匹林分子的属性进行预测。

复制代码
>       1. import torch

>  
>       2. import torch.nn as nn
>  
>       3. import dgl
>  
>       4. import dgl.function as fn
>  
>       5. import networkx as nx
>  
>       6. import matplotlib.pyplot as plt
>  
>       7. import numpy as np
>  
>       8.  
>  
>       9. # 构建一个简单的分子图来表示阿司匹林的结构
>  
>       10. aspirin_graph = dgl.graph(([0, 1, 1, 2], [1, 0, 2, 1]))  # 定义边的连接关系
>  
>       11.  
>  
>       12. # 可视化分子图
>  
>       13. plt.figure(figsize=(4, 4))
>  
>       14. nx.draw(aspirin_graph.to_networkx(), with_labels=True, node_color='skyblue', node_size=800, font_size=12, font_weight='bold', edge_color='gray')
>  
>       15. plt.title('Molecular Graph')
>  
>       16. plt.show()
>  
>       17.  
>  
>       18. # 定义GraphSAGE模型
>  
>       19. class GraphSAGE(nn.Module):
>  
>       20.     def __init__(self, in_feats, hidden_size, num_classes):
>  
>       21.         super(GraphSAGE, self).__init__()
>  
>       22.         self.conv1 = dgl.nn.SAGEConv(in_feats, hidden_size, 'mean')
>  
>       23.         self.conv2 = dgl.nn.SAGEConv(hidden_size, num_classes, 'mean')
>  
>       24.  
>  
>       25.     def forward(self, g, features):
>  
>       26.         h = self.conv1(g, features)
>  
>       27.         h = torch.relu(h)
>  
>       28.         h = self.conv2(g, h)
>  
>       29.         return h
>  
>       30.  
>  
>       31. # 初始化GraphSAGE模型
>  
>       32. input_dim = 1  # 输入特征维度为1,因为我们只考虑一个原子的属性
>  
>       33. hidden_size = 64
>  
>       34. num_classes = 2  # 为简单起见,假设我们的任务是二分类
>  
>       35. graphsage_model = GraphSAGE(input_dim, hidden_size, num_classes)
>  
>       36.  
>  
>       37. # 生成随机的示例数据
>  
>       38. num_samples = aspirin_graph.number_of_nodes()
>  
>       39. node_features = torch.randn(num_samples, input_dim)
>  
>       40.  
>  
>       41. # 随机生成二分类标签(示例)
>  
>       42. labels = torch.randint(0, 2, (num_samples,))
>  
>       43.  
>  
>       44. # 将标签添加到图中的节点
>  
>       45. aspirin_graph.ndata['features'] = node_features
>  
>       46. aspirin_graph.ndata['labels'] = labels
>  
>       47.  
>  
>       48. # 定义损失函数
>  
>       49. loss_fn = nn.CrossEntropyLoss()
>  
>       50.  
>  
>       51. # 模型训练
>  
>       52. optimizer = torch.optim.Adam(graphsage_model.parameters(), lr=0.001)
>  
>       53. epochs = 50
>  
>       54.  
>  
>       55. for epoch in range(epochs):
>  
>       56.     logits = graphsage_model(aspirin_graph, aspirin_graph.ndata['features'])
>  
>       57.     loss = loss_fn(logits, aspirin_graph.ndata['labels'])
>  
>       58.     optimizer.zero_grad()
>  
>       59.     loss.backward()
>  
>       60.     optimizer.step()
>  
>       61.  
>  
>       62.     if (epoch + 1) % 10 == 0:
>  
>       63.         print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item()}')
>  
>       64.  
>  
>       65. # 使用模型进行预测(示例)
>  
>       66. with torch.no_grad():
>  
>       67.     predicted_labels = torch.argmax(graphsage_model(aspirin_graph, aspirin_graph.ndata['features']), dim=1)
>  
>       68.  
>  
>       69. print("Predicted Labels:", predicted_labels)
>  
>  
>  
>  
>     
>  
>     ![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-14/XLCmigu0TqrxYjVQdnI7ebGAtMa1.png)

GAT

代码实战
复制代码
>       1. import torch

>  
>       2. import torch.nn as nn
>  
>       3. import dgl
>  
>       4. import dgl.function as fn
>  
>       5. import networkx as nx
>  
>       6. import matplotlib.pyplot as plt
>  
>       7.  
>  
>       8. # 构建阿司匹林分子的简单图结构
>  
>       9. aspirin_graph = dgl.graph(([0, 0, 0, 1, 2], [1, 2, 3, 3, 3]))  # 使用边列表构建图
>  
>       10.  
>  
>       11. # 定义节点特征
>  
>       12. node_features = torch.tensor([
>  
>       13.     [0.1, 0.2],
>  
>       14.     [0.2, 0.3],
>  
>       15.     [0.3, 0.4],
>  
>       16.     [0.4, 0.5]
>  
>       17. ], dtype=torch.float)
>  
>       18.  
>  
>       19. # 将节点特征设置到图中
>  
>       20. aspirin_graph.ndata['feat'] = node_features
>  
>       21.  
>  
>       22. # 可视化分子图
>  
>       23. plt.figure(figsize=(8, 6))
>  
>       24. nx.draw(aspirin_graph.to_networkx(), with_labels=True, node_color='skyblue', node_size=800, font_size=12, font_weight='bold', edge_color='gray')
>  
>       25. plt.title('Molecular Graph')
>  
>       26. plt.show()
>  
>  
>  
>  
>     
>  
>     ![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-14/O3ha2jLIJPUi146eBQyADzZCX0uK.png)
复制代码
>       1. class GAT(nn.Module):

>  
>       2.     def __init__(self, in_dim, hidden_dim, out_dim, num_heads):
>  
>       3.         super(GAT, self).__init__()
>  
>       4.         self.conv1 = dgl.nn.GATConv(in_dim, hidden_dim, num_heads)
>  
>       5.         self.conv2 = dgl.nn.GATConv(hidden_dim * num_heads, out_dim, num_heads)
>  
>       6.  
>  
>       7.     def forward(self, g, features):
>  
>       8.         h = self.conv1(g, features)
>  
>       9.         h = torch.relu(h)
>  
>       10.         h = self.conv2(g, h)
>  
>       11.         return h
>  
>       12.  
>  
>       13. # 初始化 GAT 模型
>  
>       14. input_dim = 2  # 输入特征维度
>  
>       15. hidden_dim = 64
>  
>       16. out_dim = 1  # 输出维度,这里假设我们只需要一个输出维度进行二分类
>  
>       17. num_heads = 2
>  
>       18. gat_model = GAT(input_dim, hidden_dim, out_dim, num_heads)
>  
>       19.  
>  
>       20. # 输出 GAT 模型结构
>  
>       21. print(gat_model)
>  
>  
>  
>  
>     
>  
>     ![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-14/iopA3ZfY0HDvbsjlz8qTPE7w9UnB.png)

全部评论 (0)

还没有任何评论哟~