PyG(torch_geometric)的MessagePassing详解

1. 提出MessagePassing的目的

MessagePassing是图神经网络(Graph Neural Networks,GNNs)的一个基础组件,它被设计用来处理图形数据的问题。在图形数据中,数据点(节点)之间的关系(边)是非常重要的信息。MessagePassing通过在节点之间传递和聚合信息,使得每个节点都能获取其邻居节点的信息,从而更好地理解图形的结构和特性。

具体来说,MessagePassing的工作方式是这样的:对于每个节点,它会收集其所有邻居节点的信息(这个过程称为消息传递),然后将这些信息聚合起来(这个过程称为消息聚合)。这样,每个节点都能获取到其邻居节点的信息,从而更好地理解图形的结构和特性。

在许多图形相关的任务中,如社交网络分析、分子结构预测、推荐系统等,MessagePassing都发挥了重要的作用。

2. MessagePassing基类解析

用户自定义算子的时候,需要继承MessagePassing基类并重写propagate函数、message函数和update函数。

在图神经网络中,propagate、message、aggregate和update函数是实现信息传递(Message Passing)机制的关键部分。

propagate函数

这是信息传递过程的主要驱动函数。它负责调用message、aggregate和update函数,并将结果传递给下一层。propagate函数通常会接收图的边索引(edge_index)和节点特征(node features)作为输入,然后通过message函数计算出每条边的消息,接着通过aggregate函数聚合这些消息,最后通过update函数更新每个节点的特征。

def propagate(self, edge_index, size=None, **kwargs):

message函数

这个函数负责计算每条边的消息。它通常会接收源节点和目标节点的特征作为输入,然后计算出一个消息。这个消息通常是源节点和目标节点特征的函数。

def message(self, x_j: Tensor) -> Tensor:

aggregate函数

这个函数负责聚合每个节点的所有消息。它通常会接收一个节点的所有邻居节点的消息作为输入,然后计算出一个聚合的消息。这个聚合的消息通常是所有邻居节点消息的函数。

def aggregate(self, inputs: Tensor, index: Tensor, dim_size: Optional[int] = None) -> Tensor:

update函数

这个函数负责更新每个节点的特征。它通常会接收一个节点的旧特征和该节点所有邻居的消息的聚合(通过aggregate函数实现)作为输入,然后计算出一个新的特征。

def update(self, inputs: Tensor) -> Tensor:

这四个函数一起实现了图神经网络的信息传递机制,使得每个节点都能获取其邻居节点的信息,从而更好地理解图形的结构和特性。

forward函数

MessagePassing是继承自torch.nn.Module的,所以推理时会调用forward函数,自然也要重写forward函数。

在forward函数中,通常会定义图神经网络层的输入和输出,以及调用propagate函数。

propagate函数是信息传递的主要驱动函数,它会调用message、aggregate和update函数,并将结果传递给下一层。

这个调用栈是典型的图神经网络的信息传递过程,但具体的实现可能会根据不同的图神经网络模型有所不同。

继承MessagePassing基类定义自定义GNN的层

例子1:GCNConv

Steps 1-3 are typically computed before message passing takes place. Steps 4-5 can be easily processed using the MessagePassing base class.

import torch
from torch.nn import Linear, Parameter
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degree

class GCNConv(MessagePassing):
    def __init__(self, in_channels, out_channels):
        super().__init__(aggr='add')  # "Add" aggregation (Step 5).
        self.lin = Linear(in_channels, out_channels, bias=False)
        self.bias = Parameter(torch.empty(out_channels))

        self.reset_parameters()

    def reset_parameters(self):
        self.lin.reset_parameters()
        self.bias.data.zero_()

    def forward(self, x, edge_index):
        # x has shape [N, in_channels]
        # edge_index has shape [2, E]

        # Step 1: Add self-loops to the adjacency matrix.
        edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))

        # Step 2: Linearly transform node feature matrix.
        x = self.lin(x)

        # Step 3: Compute normalization.
        row, col = edge_index
        deg = degree(col, x.size(0), dtype=x.dtype)
        deg_inv_sqrt = deg.pow(-0.5)
        deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0
        norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]

        # Step 4-5: Start propagating messages.
        out = self.propagate(edge_index, x=x, norm=norm)

        # Step 6: Apply a final bias vector.
        out += self.bias

        return out

    def message(self, x_j, norm):
        # x_j has shape [E, out_channels]

        # Step 4: Normalize node features.
        return norm.view(-1, 1) * x_j

conv = GCNConv(16, 32)
x = conv(x, edge_index)

例子2:EdgeConv

import torch
from torch.nn import Sequential as Seq, Linear, ReLU
from torch_geometric.nn import MessagePassing

class EdgeConv(MessagePassing):
    def __init__(self, in_channels, out_channels):
        super().__init__(aggr='max') #  "Max" aggregation.
        self.mlp = Seq(Linear(2 * in_channels, out_channels),
                       ReLU(),
                       Linear(out_channels, out_channels))

    def forward(self, x, edge_index):
        # x has shape [N, in_channels]
        # edge_index has shape [2, E]

        return self.propagate(edge_index, x=x)

    def message(self, x_i, x_j):
        # x_i has shape [E, in_channels]
        # x_j has shape [E, in_channels]

        tmp = torch.cat([x_i, x_j - x_i], dim=1)  # tmp has shape [E, 2 * in_channels]
        return self.mlp(tmp)

from torch_geometric.nn import knn_graph

class DynamicEdgeConv(EdgeConv):
    def __init__(self, in_channels, out_channels, k=6):
        super().__init__(in_channels, out_channels)
        self.k = k

    def forward(self, x, batch=None):
        edge_index = knn_graph(x, self.k, batch, loop=False, flow=self.flow)
        return super().forward(x, edge_index)

conv = DynamicEdgeConv(3, 128, k=6)
x = conv(x, batch)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
torch_geometric.loader.DataLoader是PyG中的一个类,用于加载和处理图数据。它可以将多个图批处理成单个巨型图,并提供了一些方便的功能。\[2\] 您可以使用torch_geometric.loader.DataLoader来加载和处理图数据集。例如,您可以创建一个包含torch_geometric.data.Data对象的常规Python列表,并将其传递给DataLoader来批处理这些图数据。\[1\] DataLoader还可以接受一些参数,例如batch_size和shuffle,以控制批处理的大小和数据的顺序。您还可以使用其他可以传递给PyTorch DataLoader的参数,例如num_workers。\[2\] 使用DataLoader加载图数据集的示例代码如下:\[3\] ```python from torch_geometric.datasets import TUDataset from torch_geometric.loader import DataLoader dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES', use_node_attr=True) loader = DataLoader(dataset, batch_size=32, shuffle=True) for batch in loader: # 在这里对批处理的图数据进行处理 # 例如,计算每个图的节点维度中的平均节点特征 x = scatter_mean(batch.x, batch.batch, dim=0) print(x.size()) # 输出每个图的节点特征的大小 ``` 通过使用torch_geometric.loader.DataLoader,您可以方便地加载和处理图数据集。它提供了一种简单而有效的方式来处理大规模的图数据。\[3\] #### 引用[.reference_title] - *1* *3* [【PyG】文档总结以及项目经验(持续更新](https://blog.csdn.net/weixin_45928096/article/details/125501673)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [第十九课.Pytorch-geometric扩展](https://blog.csdn.net/qq_40943760/article/details/120265255)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

EnjoyCodingAndGame

愿我的知识,成为您的财富!

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

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

打赏作者

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

抵扣说明:

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

余额充值