图神经网络-图采样Graphsage代码实现

一:为什么要图采样?

二 Graphsage 采样代码实践

GraphSage的PGL完整代码实现位于https://github.com/PaddlePaddle/PGL/tree/main/examples/graphsage,本文实现一个简单的graphsage 采样代码 。

安装依赖

# !pip install paddlepaddle==1.8.4
!pip install pgl -q

1. 构建graph

图网络的构建使用Graph类,Graph类的具体实现可以参考https://github.com/PaddlePaddle/PGL/blob/main/pgl/graph.py

import random
import numpy as np
import pgl
import display


def build_graph():
    # 定义节点的个数;每个节点用一个数字表示,即从0~9
    num_node = 16
    # 添加节点之间的边,每条边用一个tuple表示为: (src, dst)
    edge_list = [(2, 0), (1, 0), (3, 0),(4, 0), (5, 0), 
             (6, 1), (7, 1), (8, 2), (9, 2), (8, 7),
             (10, 3), (4, 3), (11, 10), (11, 4), (12, 4),
             (13, 5), (14, 5), (15, 5)]


    g = pgl.graph.Graph(num_nodes = num_node, edges = edge_list)


    return g


# 创建一个图对象,用于保存图网络的各种数据。
g = build_graph()
display.display_graph(g)

运行结果:


2. GraphSage采样函数实现

GraphSage的作者提出采样算法来使得模型能够以Mini-batch的方式进行训练,算法代码见论文附录A https://cs.stanford.edu/people/jure/pubs/graphsage-nips17.pdf。

  • 假设要利用中心节点的k阶邻居信息,则在聚合的时候,需要从第k阶邻居传递信息到k-1阶邻居,并依次传递到中心节点。

  • 采样的过程与此相反,在构造第t轮训练的Mini-batch时,从中心节点出发,在前序节点集合中采样Nt个邻居节点加入采样集合。

  • 将邻居节点作为新的中心节点继续进行第t-1轮训练的节点采样,以此类推。

  • 将采样到的节点和边一起构造得到子图。

def traverse(item):
    """traverse
    """
    if isinstance(item, list) or isinstance(item, np.ndarray):
        for i in iter(item):
            for j in traverse(i):
                yield j
    else:
        yield item


def flat_node_and_edge(nodes):
    """这个函数的目的是为了将 list of numpy array 扁平化成一个list
    例如:[array([7, 8, 9]), array([11, 12]), array([13, 15])] --> [7, 8, 9, 11, 12, 13, 15]
    """
    nodes = list(set(traverse(nodes)))
    return nodes


def graphsage_sample(graph, start_nodes, sample_num):
    subgraph_edges = []
    # pre_nodes: a list of numpy array, 
    pre_nodes = graph.sample_predecessor(start_nodes, sample_num)


    # 根据采样的子节点, 恢复边
    for dst_node, src_nodes in zip(start_nodes, pre_nodes):
        for node in src_nodes:
            subgraph_edges.append((node, dst_node))




    subgraph_nodes = flat_node_and_edge(pre_nodes)


    return subgraph_nodes, subgraph_edges


随机获取一阶邻居信息

seed = 458
np.random.seed(seed)
random.seed(seed)


start_nodes = [0]


layer1_nodes, layer1_edges = graphsage_sample(g, start_nodes, sample_num=3)
print('layer1_nodes: ', layer1_nodes)
print('layer1_edges: ', layer1_edges)
display.display_subgraph(g, {'orange': layer1_nodes}, {'orange': layer1_edges})

运行结果

layer1_nodes:  [2, 4, 5]
layer1_edges:  [(4, 0), (2, 0), (5, 0)]

继续获取二阶邻居节点信息

layer2_nodes, layer2_edges = graphsage_sample(g, layer1_nodes, sample_num=2)
print('layer2_nodes: ', layer2_nodes)
print('layer2_edges: ', layer2_edges)
display.display_subgraph(g, {'orange': layer1_nodes, 'Thistle': layer2_nodes}, {'orange': layer1_edges, 'Thistle': layer2_edges})

运行结果

layer2_nodes:  [8, 9, 11, 12, 14, 15]
layer2_edges:  [(8, 2), (9, 2), (11, 4), (12, 4), (14, 5), (15, 5)]

图节点可视化代码

#%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import networkx as nx # networkx是一个常用的绘制复杂图形的Python包。


def display_graph(g):
    nx_G = nx.Graph()
    nx_G.add_nodes_from(range(g.num_nodes))
    nx_G.add_edges_from(g.edges)


    pos = {0: [0.5, 0.5], 1:[0.6, 0.4], 2:[0.47, 0.67], 3: [0.35, 0.55], 4:[0.4, 0.4], 5:[0.5, 0.3],
           6: [0.8, 0.4], 7:[0.65, 0.65], 8:[0.6, 0.8], 9:[0.45, 0.85], 10:[0.15, 0.7], 11: [0.1, 0.4],
           12:[0.2, 0.2], 13:[0.3, 0.1], 14:[0.55, 0.15], 15:[0.7, 0.22]}
    nx.draw(nx_G, 
            pos,
            with_labels=True,
            node_color='green', 
            edge_color='green',
            node_size=1000)


    plt.show()


#display_graph(g)# 创建一个GraphWrapper作为图数据的容器,用于构建图神经网络。


def display_subgraph(g, sub_nodes, sub_edges):
    nx_G = nx.Graph()
    nx_G.add_nodes_from(range(g.num_nodes))
    nx_G.add_edges_from(g.edges)


    pos = {0: [0.5, 0.5], 1:[0.6, 0.4], 2:[0.47, 0.67], 3: [0.35, 0.55], 4:[0.4, 0.4], 5:[0.5, 0.3],
           6: [0.8, 0.4], 7:[0.65, 0.65], 8:[0.6, 0.8], 9:[0.45, 0.85], 10:[0.15, 0.7], 11: [0.1, 0.4],
           12:[0.2, 0.2], 13:[0.3, 0.1], 14:[0.55, 0.15], 15:[0.7, 0.22]}
    nx.draw(nx_G, 
            pos,
            with_labels=True,
            node_color='green',
            edge_color='green',
            node_size=1000,
            width=1)


    nx.draw_networkx_nodes(nx_G, pos, nodelist=[0], node_color='red', node_size=1000)


    for color, nodes in sub_nodes.items():
        nx.draw_networkx_nodes(nx_G, pos, nodelist=nodes, node_color=color, node_size=1000)


    for color, edges in sub_edges.items():
        nx.draw_networkx_edges(nx_G, pos, edgelist=edges, edge_color=color, width=5)


    plt.show()

注:本文图文资料来源于 AIStudio-人工智能学习与实训社区

### 回答1: M-H采样(Metropolis-Hastings sampling)是一种Markov Chain Monte Carlo (MCMC)方法,用于从分布中采样。其主要思想是通过构造一个马尔科夫链,使得该马尔科夫链的平稳分布为所需的分布,然后通过对该马尔科夫链进行随机游走,实现从该平稳分布中采样。 以下是M-H采样的MATLAB实现代码: ```matlab function [samples, accept_rate] = mh_sample(target_dist, prop_dist, n_samples, x_init) % target_dist: 目标分布函数 % prop_dist: 提议分布函数 % n_samples: 采样数量 % x_init: 初始值 % 初始化 samples = zeros(n_samples, size(x_init, 2)); x_current = x_init; accept_rate = 0; for i = 1:n_samples % 生成提议样本 x_proposed = prop_dist(x_current); % 计算接受率 a = target_dist(x_proposed) / target_dist(x_current) * ... prop_dist(x_current, x_proposed) / prop_dist(x_proposed, x_current); a = min(a, 1); % 决定是否接受 u = rand(); if u < a x_current = x_proposed; accept_rate = accept_rate + 1; end % 记录样本 samples(i, :) = x_current; end % 计算接受率 accept_rate = accept_rate / n_samples; end ``` 其中,`target_dist`为目标分布函数,`prop_dist`为提议分布函数,`n_samples`为采样数量,`x_init`为初始值。函数返回`samples`为采样结果,`accept_rate`为接受率。 需要注意的是,在实现提议分布函数时,需要保证从提议分布中生成的样本具有足够的随机性,否则可能导致采样效果不佳。 ### 回答2: M-H(Metropolis-Hastings)采样是一种基于马尔科夫链蒙特卡洛(MCMC)的采样方法,用于从复杂概率分布中抽样。以下是MATLAB实现M-H采样代码。 ```matlab % 计算概率分布的概率密度函数 function pdf = probability_density(x) % 在这里计算复杂概率分布的概率密度函数 % 根据具体的问题进行定义 pdf = exp(-x^2/2); end % Metropolis-Hastings采样函数 function samples = metropolis_hastings_sampling(num_samples, proposal_sd) % 初始化样本数组 samples = zeros(num_samples, 1); % 初始化当前样本为0 current_sample = 0; % 进行采样 for i = 1:num_samples % 从正态分布中生成候选样本 candidate_sample = current_sample + normrnd(0, proposal_sd); % 计算接受率 acceptance_ratio = min(1, probability_density(candidate_sample) / probability_density(current_sample)); % 产生一个在0到1之间的随机数 acceptance_prob = rand(); % 判断是否接受候选样本作为下一个样本 if acceptance_prob <= acceptance_ratio % 接受候选样本 current_sample = candidate_sample; end % 将样本存入样本数组中 samples(i) = current_sample; end end % 调用M-H采样函数进行抽样 num_samples = 300; % 抽样的样本数量 proposal_sd = 1; % 建议分布的标准差 samples = metropolis_hastings_sampling(num_samples, proposal_sd); % 绘制抽样结果的直方 histogram(samples, 'Normalization', 'pdf'); xlabel('样本值'); ylabel('概率密度'); title('M-H采样结果'); ``` 以上是一个简单的M-H采样的MATLAB实现示例。在实现中,我们首先定义了待抽样的概率分布的概率密度函数。然后,通过调用M-H采样函数`metropolis_hastings_sampling`进行抽样。最后,我们绘制抽样结果的直方来观察样本的分布情况。 ### 回答3: M-H采样是一种基于马尔科夫链蒙特卡洛(MCMC)的采样方法,用于从复杂的概率分布中生成样本。以下是一个MATLAB实现M-H采样的简单代码示例: ```MATLAB % 定义目标概率分布的密度函数 p = @(x) exp(-x.^2/2)/sqrt(2*pi); % 随机初始化起始点 x0 = randn(); % 设置总采样次数和丢弃的初始样本数 n_samples = 10000; burn_in = 1000; % 预分配数组保存样本 samples = zeros(n_samples, 1); % 实施M-H采样 for i = 1:n_samples+burn_in % 从建议分布中生成候选样本 x_cand = x0 + randn(); % 计算接受率 alpha = min(1, p(x_cand)/p(x0)); % 根据接受率决定是否接受候选样本 if rand() <= alpha x0 = x_cand; end % 丢弃初始样本 if i > burn_in samples(i-burn_in) = x0; end end % 画出样本的直方 histogram(samples, 'Normalization', 'pdf', 'NumBins', 20); hold on; % 画出目标概率分布曲线 x = linspace(-5, 5, 100); plot(x, p(x), 'r', 'LineWidth', 2); % 添加例和标签 legend('采样样本', '目标概率分布'); xlabel('x'); ylabel('概率密度'); ``` 在这个例子中,我们定义了一个目标概率分布的密度函数`p(x)`,这里选择了标准正态分布作为目标分布。我们通过M-H采样方法从目标分布中生成10000个样本,并丢弃了前1000个样本以避免采样的初始部分影响结果。最后,我们绘制了样本的直方和目标概率分布曲线进行对比。 需要注意的是,M-H采样方法的效果受到建议分布的选择和参数的设定影响,如果建议分布选择不合适,可能导致采样效率低下。因此,在实际使用中需要根据具体问题进行调整和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

段智华

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值