图论介绍和PyTorch Geometric(PyG)库基础知识

 

一个图看起来是由一些小圆点(称为顶点结点)和连接这些圆点的直线或曲线(称为)组成的            

图的定义:

  • 图G是由两个集合V和E组成(记做 G = (V, E)):

    V = {v1,v2,v3,...vn,} 是由G的结点(vertex)组成的集合

    E = {e1,e2,e3,...en} 是由连接两个结点的边(edge)组成的集合

  • (无向图)若边e(唯一的边)连接结点v1和v2, 则表示为 e = (v1,v2)或 e = (v2,v1),表示连接结点v1和结点v2的边

  • (有向图)若边e(唯一的边)连接有序结点对v1和v2, 则表示为 e = (v1,v2),

    表示一条结点v1结点v2的边

  • (有向图和无向图)G中的一条边连接结点v1和结点v2,则称结点v1和结点v2相关联,结点v1和结点v2是相邻结点

  • (有向图和无向图)一般情况下,E 和 V 都是有限的集合,且 V 为非空

     

     

在此无边图中

结点v1、结点v2、结点v3和结点v4都没有边与之相连,所以称这四个结点为孤立顶点(isolated vertex)

图的分类:

图的分类很多种,包括有/无向图,简单图/多重图等等

  • 有向图(directed graph):图的每一条边带有一个箭头,表示一个方向

  • 无向图(undirected graph):图的每一条边不带箭头,没有方向

  • 简单图(simple graph):既没有也没有平行边的图称为简单图

  • 多重图(multigraph):含有平行边的图,支持两结点间的边数多于一条

一般情况下所称的无向图平行边的定义将在下文给出。

 

 

在此多重图中

  • 边e2和边e3都连接了结点v2和结点v3,所以称边e2和边e3为平行边(parallel edge)。
  • 边e5 = (v4,v4),所以称边e5为圈(loop)。

图的结构

 

将以此图举例解释以下内容

路径

  • 路径(path):从一个结点v1到另一个结点vn所经过的路程,表示为(v1,e1,v2,e2,...en,vn)
    例如:(v1,e10,v7,e7,v6,e5,v5,e4,v4,e6,v7)

  •  

  • 简单路径(simple path):从结点vi到vj的不存在重复结点的路径
    例如:(v1,e1,v2,e2,v3)
  •  

回路

  • 回路(cycle):从vi到vi的路径,长度非0,不存在重复边的路径
    例如:(v1,e10,v7,e7,v6,e5,v5,e4,v4,e6,v7,e9,v8,e11,v1)
  •  

  • 简单回路(simple cycle):从vi到vi的回路,除了开始和结束的结点相同之外,不存在相同的结点
    例如:(v1,e10,v7,e9,v8,e11,v1)
  •  

连通图(connected graph)

  • 存在从任意一个结点vi到另外一个任意结点vj的路径的图(所有结点都是连通的图),反之,就是非连通图,上述的简单图和多重图都是连通图

子图

  • 在非联通图G中,通常有多个部分,每个部分都称为G的子图

     

  • G1 = (V, E), V = {v1,,v2,v3}, E = {e1,e2,e3}
    G2 = (V, E), V = {v4,v5}, E = {e4}
    G3 = (V, E), V = {v6}, E为空集

 

PyTorch Geometric 基础知识

这一部分我们介绍一下 PyG 的基础知识,主要包括 torch_geometric.data  部分。另外,还会介绍怎么设计自己的 消息传递(Message Passing)范式

Data 类

Data类的官方文档为torch_geometric.data.Data

Data类的构造函数

class Data(object):

    def __init__(self, x=None, edge_index=None, edge_attr=None, y=None, **kwargs):
    r"""
    Args:
        x (Tensor, optional): 节点属性矩阵,大小为`[num_nodes, num_node_features]`
        edge_index (LongTensor, optional): 边索引矩阵,大小为`[2, num_edges]`,第0行为尾节点,第1行为头节点,头指向尾
        edge_attr (Tensor, optional): 边属性矩阵,大小为`[num_edges, num_edge_features]`
        y (Tensor, optional): 节点或图的标签,任意大小(,其实也可以是边的标签)
	
    """
    self.x = x
    self.edge_index = edge_index
    self.edge_attr = edge_attr
    self.y = y

    for key, item in kwargs.items():
        if key == 'num_nodes':
            self.__num_nodes__ = item
        else:
            self[key] = item

 

torch_geometric.data 包里有一个 Data 类,通过 Data 类我们可以很方便的创建图结构。

定义一个图结构,需要以下变量:

  1. 每个节点(node)的 features
  2. 边的连接关系或者边的 features

我们以下面的图结构为例,看看怎么用 Data 类创建图结构

  • 图的节点x可以根据其值进行向量表示,而节点与节点间使用邻接矩阵(这里用的边表edge_index)来表示。
  • 邻接矩阵dege_index主要由源节点(第一列)和目标节点(第二列)组成。源节点和目标节点顺序对应。比如 ,在图中,节点0的目标节点(指向的点)有节点1和节点3,因此节点0可以用[[0,0],[1,3]]来表示。所以,邻接矩阵的关键是,源节点列和目标节点列的对应关系表示。

 

在上图中,一共有四个节点 v1,v2,v3,v4,其中每个节点都有一个二维的特征向量和一个标签 y。这个特征向量和标签可以用 FloatTensor 来表示:

x = torch.tensor([[2,1], [5,6], [3,7], [12,0]], dtype=torch.float)

y = torch.tensor([0, 1, 0, 1], dtype=torch.float)

图的连接关系(边)可以用 COO 格式表示。COO 格式的维度是 [2, num_edges],其中第一个列表是所有边上起始节点的 index,第二个列表是对应边上目标节点的 index:

edge_index = torch.tensor([[0, 1, 2, 0, 3],

[1, 0, 1, 3, 2]], dtype=torch.long)

注意上面的数据里定义边的顺序是无关紧要的,这个数据仅仅用来计算邻接矩阵用的,比如上面的定义和下面的定义是等价的:

edge_index = torch.tensor([[0, 2, 1, 0, 3],

[3, 1, 0, 1, 2]], dtype=torch.long)

综上所述,我们可以这样定义上面的图结构:

import torch

from torch_geometric.data import Data



x = torch.tensor([[2,1], [5,6], [3,7], [12,0]], dtype=torch.float)

y = torch.tensor([0, 1, 0, 1], dtype=torch.float)


edge_index = torch.tensor([[0, 2, 1, 0, 3],

[3, 1, 0, 1, 2]], dtype=torch.long)



data = Data(x=x, y=y, edge_index=edge_index)

>>> Data(edge_index=[2, 5], x=[4, 2], y=[4])

 

作业

  • 请通过继承Data类实现一个类,专门用于表示“机构-作者-论文”的网络。该网络包含“机构“、”作者“和”论文”三类节点,以及“作者-机构“和“作者-论文“两类边。

  • 对要实现的类的要求:

  • 1)用不同的属性存储不同节点的属性;

  • 2)用不同的属性存储不同的边(边没有属性);

  • 3)逐一实现获取不同节点数量的方法。

class Net(Data):
    def __init__(self, institution_x, author_x, paper_x, work_edge_index, publish_edge_index, work_edge_attr, publish_edge_attr, y, **kwargs):
        super().__init__(**kwargs)
        
        self.institution_x = institution_x
        self.author_x = author_x
        self.paper_x = paper_x
        self.work_edge_index = work_edge_index
        self.publish_edge_index = publish_edge_index
        self.work_edge_attr = work_edge_attr
        self.publish_edge_attr = publish_edge_attr
        self.y = y
        
    @property
    def institution_nums(self):
        return self.institution_x.shape[0]
    
    @property
    def author_nums(self):
        return self.author_x.shape[0]
        
    @property
    def paper_nums(self):
        return self.paper_x.shape[0]

 

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值