GNN入门

本文详细介绍了如何继承MessagePassing类来创建自定义图神经网络,包括GCNConv的基本操作、自定义message、aggregate和update函数,以及整合message_and_aggregate的实现。通过实例展示了如何根据需求覆盖并扩展这些核心功能。
摘要由CSDN通过智能技术生成

目录

 

task02 消息传递图神经网络

作业一:MessagePassing类

作业二:自定义图神经网络类


task02 消息传递图神经网络

作业一:MessagePassing类

请总结MessagePassing类的运行流程以及继承MessagePassing类的规范。

1. 构建领域信息,源节点向目标中心节点传递特征

2. 目标节点对接收到的特征通过聚合函数进行聚合

3. 将聚合之后的信息进行变换,更新目标节点 

import torch
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(GCNConv, self).__init__(aggr='add', flow='source_to_target')
        # Step 5:将相邻节点特征相加("求和"聚合)
        # flow='source_to_target' 表示消息从源节点传播到目标节点
        self.lin = torch.nn.Linear(in_channels, out_channels)

    def forward(self, x, edge_index):
        # x has shape [N, in_channels]
        # edge_index has shape [2, E]
        """
        x = torch.tensor(
            [[-1, 1, 2], [1, 1, 1], [3, 1, 2], [2, 1, 1], [-1, 1, 0]]
        )
        edge_index = torch.tensor(
            [[2, 3, 4, 4], [0, 1, 0, 1]]
        )
        """
        # Step 1: 向邻接矩阵添加自环边
        # 目的: 让feature在聚合的过程中加入当前节点自己的feature,没有self-loop聚合的就只有邻居节点的信息
        """
        self-loops = tensor([[0, 1, 2, 3, 4], 
        					 [0, 1, 2, 3, 4]])
        edge_index = tensor([[2, 3, 4, 4, 0, 1, 2, 3, 4], 
        					 [0, 1, 0, 1, 0, 1, 2, 3, 4]])
        """
        edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))
        # Step 2: 线性转换节点特征矩阵
        x = self.lin(x)
        # Step 3: 计算归一化系数
        """ 
        D^(-0.5) A D^(-0.5)
        out = torch.zeros((N, ), dtype=dtype, device=index.device)
        # [0, 0, 0, 0, 0]
        one = torch.ones((index.size(0), ), dtype=out.dtype, device=out.device)
        # [1, 1, 1, 1, 1, 1, 1, 1, 1]
        deg = out.scatter_add_(0, index, one)
        # [3., 3., 1., 1., 1.]
        like (adjacency matrix -> degree matrix): 
        1 0 1 0 1        3 0 0 0 0
        0 1 0 1 1        0 3 0 0 0
        0 0 1 0 0   ->   0 0 1 0 0
        0 0 0 1 0		 0 0 0 1 0
        0 0 0 0 1		 0 0 0 0 1
        """
        row, col = edge_index
        """
        row = [2, 3, 4, 4, 0, 1, 2, 3, 4]
        col = [0, 1, 0, 1, 0, 1, 2, 3, 4]
        """
        deg = degree(col, x.size(0), dtype=x.dtype)  # 转换成每个边的节点度
        """
        deg = tensor([3., 3., 1., 1., 1.])
        """
        deg_inv_sqrt = deg.pow(-0.5)
        """
        deg_inv_sqrt: tensor([0.5774, 0.5774, 1.0000, 1.0000, 1.0000])
        """
        a = deg_inv_sqrt[col]
        norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]  # 结果被保存在形状[num_edges,]的张量norm中
        """
        deg_inv_sqrt[row]: tensor([1.0000, 1.0000, 1.0000, 1.0000, 0.5774, 0.5774, 1.0000, 1.0000, 1.0000])
        deg_inv_sqrt[col]: tensor([0.5774, 0.5774, 0.5774, 0.5774, 0.5774, 0.5774, 1.0000, 1.0000, 1.0000])
        norm: tensor([0.5774, 0.5774, 0.5774, 0.5774, 0.3333, 0.3333, 1.0000, 1.0000, 1.0000])
        """
        # Step 4-5: Start propagating messages.
        return self.propagate(edge_index, x=x, norm=norm)

    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


# num_node_features==in_channels?
conv = GCNConv(3, 5)
# x: [num_nodes,num_node_features]
x = torch.tensor([[-1,1,2],[1,1,1],[3,1,2],[2,1,1],[-1,1,0]],dtype=torch.float)
edge_index = torch.tensor([[2,3,4,4],
                           [0,1,0,1]])
x = conv(x, edge_index)

作业二:自定义图神经网络类

请继承MessagePassing类来自定义以下的图神经网络类,并进行测 试:

  1. 第一个类,覆写message函数,要求该函数接收消息传递源节点属性x、目标节点度d。

  2. 第二个类,在第一个类的基础上,再覆写aggregate函数,要求不能调用 super 类的 aggregate 函数,并且不能直接复制 super 类的 aggregate 函数内容。

  3. 第三个类,在第二个类的基础上,再覆写 update 函数,要求对节点信息做一层线性变换。

  4. 第四个类,在第三个类的基础上,再覆写message_and_aggregate 函数,要求在这一个函数中实现前面 message 函数和 aggregate 函数的功能。

def message(self, x_i, norm, d):
    # x_i has shape [E, out_channels]
    # Step 4: Normalize node features.
    return norm.view(-1, 1) * d * x_i

def aggregate(self, inputs, index, dim_size):
    return scatter_add(inputs, index, dim=self.node_dim, dim_size=dim_size)

def update(self, inputs: Tensor) -> Tensor:
    lin = torch.nn.Linear(inputs.size(1), inputs.size(1))
    return lin(inputs)

def message_and_aggregate(self, adj_t, x, norm):
    inputs = norm.view(-1, 1) * d * x
    return scatter_add(inputs, adj_t, dim=self.node_dim, dim_size=dim_size)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
人工智能(AI)最近经历了复兴,在视觉,语言,控制和决策等关键领域取得了重大进展。 部分原因在于廉价数据和廉价计算资源,这些资源符合深度学习的自然优势。 然而,在不同的压力下发展的人智能的许多定义特征仍然是当前方法无法实现的。 特别是,超越一个人的经验 - 从婴儿期开始人智能的标志 - 仍然是现代人工智能的一项艰巨挑战。 以下是部分立场文件,部分审查和部分统一。我们认为组合概括必须是AI实现似人能力的首要任务,结构化表示和计算是实现这一目标的关键。就像生物学利用自然和培养合作一样,我们拒绝“手工工程”和“端到端”学习之间的错误选择,而是倡导一种从其互补优势中获益的方法。我们探索如何在深度学习架构中使用关系归纳偏差来促进对实体,关系和组成它们的规则的学习。我们为AI工具包提供了一个新的构建模块,具有强大的关系归纳偏差 - 图形网络 - 它概括和扩展了在图形上运行的神经网络的各种方法,并为操纵结构化知识和生成结构化行为提供了直接的界面。我们讨论图网络如何支持关系推理和组合泛化,为更复杂,可解释和灵活的推理模式奠定基础。作为本文的配套文件,我们还发布了一个用于构建图形网络的开源软件库,并演示了如何在实践中使用它们。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值