图神经网络 | (5) GraphSAGE实战

近期买了一本图神经网络的入门书,最近几篇博客对书中的一些实战案例进行整理,具体的理论和原理部分可以自行查阅该书,该书购买链接:《深入浅出的图神经网络》

该书配套代码

本节我们通过代码来介绍GraphSAGE以加深读者对相关知识的理解,如书中介绍的那样,GraphSAGE包括两方面,一是对邻居的采样;二是对邻居的聚合操作。

目录

1. 对邻居采样

2. 对邻居聚合

3. 定义SageGCN

4. GraphSage模型

5. 数据预处理

6. 主程序


1. 对邻居采样

首先来看下对邻居的采样方法,为了实现更高效低地采样,可以将节点及其邻居存放在一起,即维护一个节点与其邻居对应关系的表。可以通过两个函数sampling和multihop_sampling来实现采样的具体操作。其中sampling是进行一阶采样,根据源节点采样指定数量的邻居节点,multihop_sampling则是利用sampling实现多阶采样的功能。

def sampling(src_nodes, sample_num, neighbor_table):
    """根据源节点采样指定数量的邻居节点,注意使用的是有放回的采样;
    某个节点的邻居节点数量少于采样数量时,采样结果出现重复的节点

    Arguments:
        src_nodes {list, ndarray} -- 源节点列表
        sample_num {int} -- 需要采样的节点数
        neighbor_table {dict} -- 节点到其邻居节点的映射表,邻接矩阵

    Returns:
        np.ndarray -- 采样结果构成的列表
    """
    results = []
    for sid in src_nodes:
        # 从节点的邻居中进行有放回地进行采样 
        res = np.random.choice(neighbor_table[sid], size=(sample_num,))
        results.append(res)
    return np.asarray(results).flatten() #拉伸为1维


def multihop_sampling(src_nodes, sample_nums, neighbor_table):
    """根据源节点进行多阶采样

    Arguments:
        src_nodes {list, np.ndarray} -- 源节点id
        sample_nums {list of int} -- 每一阶需要采样的个数
        neighbor_table {dict} -- 节点到其邻居节点的映射 /邻接矩阵

    Returns:
        [list of ndarray] -- 每一阶采样的结果
    """
    sampling_result = [src_nodes] #首先包含源节点 
    for k, hopk_num in enumerate(sample_nums): #先对源节点进行1阶采样 在与源节点距离为1的节点中采样hopk_num个节点; 再对源节点进行2阶采样,即对源节点的所有1阶邻居进行1阶采样
        hopk_result = sampling(sampling_result[k], hopk_num, neighbor_table)
        sampling_result.append(hopk_result) #追加源节点的1阶邻居 和 2阶邻居(2层网络,代表采样到2阶)
    return sampling_result

这样采样得到的结果仅仅是节点的ID,还需要根据节点ID去查询每个节点的特征(向量),以进行聚合操作更新特征。

 

2. 对邻居聚合

接下里根据两种聚类算子对邻居的状态(特征向量)进行聚合:

1)平均/加和聚合算子

                                    Agg^{sum} = \sigma(SUM\{Wh_j+b,\forall v_j \in N(v_i)})

2)池化聚合算子

                                   Agg^{pool} = MAX\{\sigma(Wh_j+b),\forall v_j \in N(v_i)\}

计算过程定义在forward函数中,输入neighbor_feature表示每个节点需要聚合的邻接节点的特征(向量),维度为N_{src} \times N_{neighbor} \times D_{in},其中N_{src}表示源节点的数量,N_{neighbor}表示邻居节点的数量,D_{in}表示输入的特征维度。将这些邻居节点的特征经过一个线性变换得到隐层特征,就可以沿着N_{neighbor}维度进行聚合操作了,包括求和、均值和最大值,得到维度N_{src} \times D_{in}的输出。

class NeighborAggregator(nn.Module):
    def __init__(self, input_dim, output_dim,
                 use_bias=False, aggr_method="mean"):
        """聚合节点邻居

        Args:
            input_dim: 输入特征的维度
            output_dim: 输出特征的维度
            use_bias: 是否使用偏置 (default: {False})
            aggr_method: 邻居聚合方式 (default: {mean})
        """
        super(NeighborAggregator, self).__init__()
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.use_bias &
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值