项目链接:aistudio.baidu.com/aistudio/pr…
如遇到问题查看原项目解决
图学习温故以及初探Paddle Graph Learning (PGL)构建归于你的图【系列三】
相关项目参阅:
图机器学习(GML)&图神经网络(GNN)原理和代码完成(前置学习系列二):aistudio.baidu.com/aistudio/pr…
关于图核算&图学习的基础常识概览:前置常识点学习(PGL)[系列一] aistudio.baidu.com/aistudio/pr…
0.常识点回顾
依据图的节点间是否有方向,可将图分为无向图与有向图;图的边是否有权重,能够将图分为无权图和有权图;图的边和点是否具有多种类型,能够将图分为同构图和异构图
-
度是图上一节点,其边的条数
-
街坊指的是图上一节点的相邻节点
无向图的临界矩阵便是对称矩阵
邻接表:其实便是直接记录着每个节点的街坊信息
能够将依据图能做的使命进行一个分类。
-
这个点的类别或者其他的特性,那么这便是一个节点等级的使命;
-
猜测这条边的权值,或者猜测这条边是否存在,等等,那么这便是一个边等级的使命;
-
猜测整张图的一个类别,或者想比较两张图之间的类似性等等,这便是一个图等级的使命了。
节点等级使命:金融欺诈检测
在建图的时分,它的节点是用户和商家,一起还包括了各自共有的信息作为节点。
其间,每个用户或者商家都有着各自的特征,也具有着某些相同的特征,一起也有着与别人的交互。传统办法一般是直接运用用户和商家的特征来练习一个分类网络,而没有运用节点与节点之间的交互,因而运用图学习, 能够一起学习图结构以及节点特征,更好的进行分类,从而更好地找到金融欺诈分子。
方针检测:点云
点云是经过激光扫描等来获得的点数据,而3D点云这个结构能够建模为图结构。
在点云中构建好图之后,将图结构和图特征经过这个叫 Point-GNN 的模型,从而猜测出点云中每个点所对应的 object,也便是方针对象,一起要猜测出对应方针的地点三维鸿沟,也便是 bounding box。
由于猜测对象是每个点,因而这是一个节点等级的使命。
引荐系统
比方, 想要向用户引荐新闻,以左面这个图为例, 已经知道了用户 ABC的历史点击行为,那么接下来,想要猜测用户B会不会点击某条广告,其实就相当于猜测这条边是否存在,因而这便是一个边猜测的使命。
具体完成的时分,会把用户行为图联络经过图表明学习后,得到用户、商品或内容的向量表明;得到对应这些节点的 Embeddings 之后, 就能够运用这些 embeddings 来做各种的引荐使命。
这儿分为了三大类:游走类算法、图神经网络算法、以及常识图谱嵌入算法。
由于常识图谱也是一种典型的图,因而把它也参加到了这个分类里边。
其间,图神经网络算法还能够进行愈加具体的差异,比方分为卷积网络和递归网络,等等。
图游走类算法,任意挑选一个出发点,然后随机地挑选下一个意图地,不断地走,经过不断地游走,得到了多个序列,而游走类算法便是在得到这些序列之后,对它们运用图表明学习,再进行接下来的其他操作。
图神经网络算法相对来说则杂乱一点,它的一种完成办法是音讯传递。
音讯传递,其实质便是把当时节点的街坊发送到本身,将这些信息聚合后,再运用这些信息更新本身的表明。
-
图游走类算法:经过在图上的游走,获得多个节点序列,再运用 Skip Gram 模型练习得到节点表明
-
图神经网络算法:端到端模型,运用音讯传递机制完成。
-
常识图谱嵌入算法:专门用于常识图谱的相关算法。
1.Paddle Graph Learning (PGL) 简介
github.com/PaddlePaddl…
Paddle Graph Learning (PGL)是一个依据PaddlePaddle的高效易用的图学习结构
PGL的长处:
- 易用性:建图便利
- 高效性:运转速度快
- 大规划:支撑十亿节点百亿边
- 丰富性:预置了干流的图学习算法
在最新发布的PGL中引入了异构图的支撑,新增MetaPath采样支撑异构图表明学习,新增异构图Message Passing机制支撑依据音讯传递的异构图算法,运用新增的异构图接口,能轻松建立前沿的异构图学习算法。而且,在最新发布的PGL中,一起也增加了分布式图存储以及一些分布式图学习练习算法,例如,分布式deep walk和分布式graphsage。结合PaddlePaddle深度学习结构, 的结构根本能够掩盖大部分的图网络运用,包括图表明学习以及图神经网络。
1.1 特征:高效性——支撑Scatter-Gather及LodTensor音讯传递
比照于一般的模型,图神经网络模型最大的优势在于它运用了节点与节点之间衔接的信息。可是,怎么经过代码来完成建模这些节点衔接十分的费事。PGL采用与DGL类似的音讯传递范式用于作为构建图神经网络的接口。用于只需求简略的编写send
还有recv
函数就能够轻松的完成一个简略的GCN网络。如下图所示,首先,send函数被界说在节点之间的边上,用户自界说send函数e\phi^e会把音讯从源点发送到方针节点。然后,recv函数v\phi^v负责将这些音讯用会聚函数⊕\oplus 会聚起来。
如下面左图所示,为了去适配用户界说的会聚函数,DGL运用了Degree Bucketing来将相同度的节点组合在一个块,然后将会聚函数⊕\oplus效果在每个块之上。而关于PGL的用户界说会聚函数, 则将音讯以PaddlePaddle的LodTensor的方法处理,将若干音讯看作一组变长的序列,然后运用LodTensor在PaddlePaddle的特性进行快速平行的音讯聚合。
用户只需求下面简略几行代码,就能够完成一个求和聚合函数了。
import pgl
import paddle
import numpy as np
num_nodes = 5
edges = [(0, 1), (1, 2), (3, 4)]
feature = np.random.randn(5, 100).astype(np.float32)
g = pgl.Graph(num_nodes=num_nodes,
edges=edges,
node_feat={
"h": feature
})
g.tensor()
def send_func(src_feat, dst_feat, edge_feat):
return src_feat
def recv_func(msg):
return msg.reduce_sum(msg["h"])
msg = g.send(send_func, src_feat=g.node_feat)
ret = g.recv(recv_func, msg)
尽管DGL用了一些内核交融(kernel fusion)的办法来将常用的sum,max等聚合函数用scatter-gather进行优化。可是关于杂乱的用户界说函数,他们运用的Degree Bucketing算法,仅仅运用串行的计划来处理不同的分块,并不会充分运用GPU进行加快。然而,在PGL中 运用依据LodTensor的音讯传递能够充分地运用GPU的并行优化,在杂乱的用户界说函数下,PGL的速度在 的实验中乃至能够达到DGL的13倍。即便不运用scatter-gather的优化,PGL仍然有高效的功能表现。当然, 也是供给了scatter优化的聚合函数。
功能测试
用Tesla V100-SXM2-16G测试了下列一切的GNN算法,每一个算法跑了200个Epoch来核算均匀速度。准确率是在测试集上核算出来的,并且 没有运用Early-stopping策略。
数据集 | 模型 | PGL准确率 | PGL速度 (epoch) | DGL 0.3.0 速度 (epoch) |
---|---|---|---|---|
Cora | GCN | 81.75% | 0.0047s | 0.0045s |
Cora | GAT | 83.5% | 0.0119s | 0.0141s |
Pubmed | GCN | 79.2% | 0.0049s | 0.0051s |
Pubmed | GAT | 77% | 0.0193s | 0.0144s |
Citeseer | GCN | 70.2% | 0.0045 | 0.0046s |
Citeseer | GAT | 68.8% | 0.0124s | 0.0139s |
假如 运用杂乱的用户界说聚合函数,例如像GraphSAGE-LSTM那样忽略街坊信息的获取顺序,运用LSTM来聚合节点的街坊特征。DGL所运用的音讯传递函数将退化成Degree Bucketing模式,在这个情况下DGL完成的模型会比PGL的慢的多。模型的功能会跟着图规划而变化,在 的实验中,PGL的速度乃至能够能达到DGL的13倍。
数据集 | PGL速度 (epoch) | DGL 0.3.0 速度 (epoch time) | 加快比 |
---|---|---|---|
Cora | 0.0186s | 0.1638s | 8.80x |
Pubmed | 0.0388s | 0.5275s | 13.59x |
Citeseer | 0.0150s | 0.1278s | 8.52x |
1.2特征:易用性——原生支撑异质图
图能够很便利的表明实在世界中事物之间的联络,可是事物的类别以及事物之间的联络多种多样,因而,在异质图中, 需求对图网络中的节点类型以及边类型进行差异。PGL针对异质图包括多种节点类型和多种边类型的特色进行建模,能够描绘不同类型之间的杂乱联络。
1.2.1 支撑异质图MetaPath walk采样
上图左面描绘的是一个购物的社交网络,上面的节点有用户和商品两大类,联络有用户和用户之间的联络,用户和商品之间的联络以及商品和商品之间的联络。上图的右边是一个简略的MetaPath采样进程,输入metapath为UPU(user-product-user),采出结果为
然后在此基础上引入word2vec等办法,支撑异质图表明学习metapath2vec等算法。
1.2.2 支撑异质图Message Passing机制
在异质图上由于节点类型不同,音讯传递也办法也有所不同。如上图左面,它有五个街坊节点,归于两种不同的节点类型。如上图右边,在音讯传递的时分需求把归于不同类型的节点分开聚合,然后在合并成最终的音讯,从而更新方针节点。在此基础上PGL支撑依据音讯传递的异质图算法,如GATNE等算法。
1.3 特征:规划性——支撑分布式图存储以及分布式学习算法
在大规划的图网络学习中,一般需求多机图存储以及多机分布式练习。如下图所示,PGL供给一套大规划练习的解决计划, 运用PaddleFleet(支撑大规划分布式Embedding学习)作为 参数服务器模块以及一套简易的分布式存储计划,能够轻松在MPI集群上建立分布式大规划图学习办法。
1.4 特征:丰富性——掩盖业界大部分图学习网络
下列是结构中已经自带完成的十三种图网络学习模型。详情请参阅这儿
模型 | 特色 |
---|---|
ERNIESage | 能一起建模文本以及图结构的ERNIE SAmple aggreGatE |
GCN | 图卷积网络 |
GAT | 依据Attention的图卷积网络 |
GraphSage | 依据街坊采样的大规划图卷积网络 |
unSup-GraphSage | 无监督学习的GraphSAGE |
LINE | 依据一阶、二阶街坊的表明学习 |
DeepWalk | DFS随机游走的表明学习 |
MetaPath2Vec | 依据metapath的表明学习 |
Node2Vec | 结合DFS及BFS的表明学习 |
Struct2Vec | 依据结构类似的表明学习 |
SGC | 简化的图卷积网络 |
GES | 参加节点特征的图表明学习办法 |
DGI | 依据图卷积网络的无监督表明学习 |
GATNE | 依据MessagePassing的异质图表明学习 |
上述模型包括图表明学习,图神经网络以及异质图三部分,而异质图里边也分图表明学习和图神经网络。
2.运用PGL构建同质图–小试牛刀
2.1 用 PGL 来创立一张图
为了让用户快速上手,本教程的首要意图是:
理解PGL是怎么在图网络上进行核算的。
运用PGL完成一个简略的图神经网络模型,用于对图网络中的节点进行二分类。
假定咱们有下面的这一张图,其间包括了10个节点以及14条边。
咱们的意图是,练习一个图模型,使得该图模型能够差异图上的黄色节点和绿色节点。
!pip install pgl==1.2.1
#需求留意的是,Paddle2.x+是动态图了,为了进一步简化运用,将GraphWrapper的概念去掉了,现在能够直接在Graph上进行Send/Recv
from pgl import graph # 导入 PGL 中的图模块
import paddle.fluid as fluid # 导入飞桨结构
import numpy as np
import paddle
def build_graph():
# 界说图中的节点数目,咱们运用数字来表明图中的每个节点,每个节点用一个数字表明,即从0~9
num_nodes = 10
# 界说图中的边集,增加节点之间的边,每条边用一个tuple表明为: (src, dst)
edge_list = [(2, 0), (2, 1), (3, 1),(4, 0), (5, 0),
(6, 0), (6, 4), (6, 5), (7, 0), (7, 1),
(7, 2), (7, 3), (8, 0), (9, 7)]
# 随机初始化节点特征,特征维度为 d
# 每个节点能够用一个d维的特征向量作为表明,这儿随机产生节点的向量表明.
# 在PGL中,咱们能够运用numpy来增加节点的向量表明。
d = 16
feature = np.random.randn(num_nodes, d).astype("float32")
# 随机地为每条边赋值一个权重
# 关于边,也同样能够用一个特征向量表明。
edge_feature = np.random.randn(len(edge_list), 1).astype("float32")
# 创立图对象,最多四个输入
# 依据节点,边以及对应的特征向量,创立一个完好的图网络。
# 在PGL中,节点特征和边特征都是存储在一个dict中。
g = graph.Graph(num_nodes = num_nodes,
edges = edge_list,
node_feat = {'feature':feature},
edge_feat ={'edge_feature': edge_feature})
return g
# 创立一个图对象,用于保存图网络的各种数据。
g = build_graph()
print('图中合计 %d 个节点' % g.num_nodes)
print('图中合计 %d 条边' % g.num_edges)
%matplotlib inline
import matplotlib.pyplot as plt
import networkx as nx # networkx是一个常用的制作杂乱图形的Python包。
def display_graph(g):
nx_G = nx.Graph()
nx_G.add_nodes_from(range(g.num_nodes))
for line in g.edges:
nx_G.add_edge(*line)
nx.draw(nx_G, with_labels=True,
node_color=['y','g','g','g','y','y','y','g','y','g'], node_size=1000)
foo_fig = plt.gcf() # 'get current figure'
foo_fig.savefig('gcn.png', format='png', dpi=1000)
#foo_fig.savefig('./foo.pdf', format='pdf') # 也能够保存成pdf
plt.show()
display_graph(g)# 创立一个GraphWrapper作为图数据的容器,用于构建图神经网络。
2.2 界说图模型
界说下面的一个简略图模型层,这儿的结构是增加了边权重信息的类 GCN 层。
在本教程中,咱们运用图卷积网络模型(Kipf和Welling)来完成节点分类器。为了便利,这儿咱们运用最简略的GCN结构。假如读者想愈加深化了解GCN,能够参阅原始论文。
- 在第ll层中,每个节点uilu_i^l都有一个特征向量hilh_i^l;
- 在每一层中,GCN的想法是下一层的每个节点uil+1u_i^{l+1}的特征向量hil+1h_i^{l+1}是由该节点的一切街坊节点的特征向量加权后经过一个非线性变换后得到的。
GCN模型契合音讯传递模式(message-passing paradigm),当一个节点的一切街坊节点把音讯发送出来后,这个节点就能够依据上面的界说更新自己的特征向量了。
在PGL中,咱们能够很容易完成一个GCN层。如下所示:
def model_layer(gw, nfeat, efeat, hidden_size, name, activation):
'''
gw: GraphWrapper 图数据容器,用于在界说模型的时分运用,后续练习时再feed入实在数据 # gw是一个GraphWrapper;feature是节点的特征向量。
nfeat: 节点特征
efeat: 边权重
hidden_size: 模型躲藏层维度
activation: 运用的激活函数
'''
# 界说 send 函数,界说message函数,
def send_func(src_feat, dst_feat, edge_feat):
# 将源节点的节点特征和边权重一起作为音讯发送
# 留意: 这儿三个参数是固定的,尽管咱们只用到了第一个参数。
# 在本教程中,咱们直接返回源节点的特征向量作为message。用户也能够自界说message函数的内容。
return src_feat['h'] * edge_feat['e']
# # 界说reduce函数,参数feat其实是从message函数那里获得的。
def recv_func(feat):
# 方针节点接纳源节点音讯,采用 sum 的聚合办法
# 这儿经过将源节点的特征向量进行加和。
# feat为LodTensor,关于LodTensor的介绍参照Paddle官网。
return fluid.layers.sequence_pool(feat, pool_type='sum')
# 触发音讯传递机制
# send函数触发message函数,发送音讯,并将返回音讯。
msg = gw.send(send_func, nfeat_list=[('h', nfeat)], efeat_list=[('e', efeat)])
# recv函数接纳音讯,并触发reduce函数,对音讯进行处理。
output = gw.recv(msg, recv_func)
# 以activation为激活函数的全衔接输出层。
output = fluid.layers.fc(output,
size=hidden_size,
bias_attr=False,
act=activation,
name=name)
return output
2.3 模型界说
在PGL中,图对象用于保存各种图数据。咱们还需求用到GraphWrapper作为图数据的容器,用于构建图神经网络。
这儿咱们简略的把上述界说好的模型层堆叠两层,作为咱们的最终模型。
# 在界说好GCN层之后,咱们能够构建一个更深的GCN模型,如下咱们定一个两层GCN。
class Model(object):
def __init__(self, graph):
"""
graph: 咱们前面创立好的图
"""
# 创立 GraphWrapper 图数据容器,用于在界说模型的时分运用,后续练习时再feed入实在数据
self.gw = pgl.graph_wrapper.GraphWrapper(name='graph',
node_feat=graph.node_feat_info(),
edge_feat=graph.edge_feat_info())
# 效果同 GraphWrapper,此处用作节点标签的容器,创立一个标签层作为节点类别标签的容器。
self.node_label = fluid.layers.data("node_label", shape=[None, 1],
dtype="float32", append_batch_size=False)
def build_model(self):
# 界说两层model_layer
# 第一层GCN将特征向量从16维映射到8维,激活函数运用relu。
output = model_layer(self.gw,
self.gw.node_feat['feature'],
self.gw.edge_feat['edge_feature'],
hidden_size=8,
name='layer_1',
activation='relu')
# 第二层GCN将特征向量从8维映射导2维,对应咱们的二分类。不运用激活函数。
output = model_layer(self.gw,
output,
self.gw.edge_feat['edge_feature'],
hidden_size=1,
name='layer_2',
activation=None)
# 关于二分类使命,能够运用以下 API 核算丢失 运用带sigmoid的交叉熵函数作为丢失函数
loss = fluid.layers.sigmoid_cross_entropy_with_logits(x=output,
label=self.node_label)
# 核算均匀丢失
loss = fluid.layers.mean(loss)
# 核算准确率
prob = fluid.layers.sigmoid(output)
pred = prob > 0.5
pred = fluid.layers.cast(prob > 0.5, dtype="float32")
correct = fluid.layers.equal(pred, self.node_label)
correct = fluid.layers.cast(correct, dtype="float32")
acc = fluid.layers.reduce_mean(correct)
return loss, acc
GCN的练习进程跟练习其它依据paddlepaddle的模型是一样的。
- 首先咱们构建丢失函数;
- 接着创立一个优化器;
- 最后创立履行器并履行练习进程。
import paddle
use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
#2.x版本动态转换为静态图
paddle.enable_static()
# 界说程序,也便是咱们的 Program
startup_program = fluid.Program() # 用于初始化模型参数
train_program = fluid.Program() # 练习时运用的主程序,包括前向核算和反向梯度核算
test_program = fluid.Program() # 测试时运用的程序,只包括前向核算
with fluid.program_guard(train_program, startup_program):
model = Model(g)
# 创立模型和核算 Loss
loss, acc = model.build_model()
# 挑选Adam优化器,学习率设置为0.01
adam = fluid.optimizer.Adam(learning_rate=0.01)
adam.minimize(loss) # 核算梯度和履行梯度反向传达进程
# 复制结构 test_program,与 train_program的差异在于不需求梯度核算和反向进程。
test_program = train_program.clone(for_test=True)
# 界说一个在 place(CPU)上的Executor来履行program, 创立履行器
exe = fluid.Executor(place)
# 参数初始化
exe.run(startup_program)
# 获取实在图数据,获取图数据
feed_dict = model.gw.to_feed(g)
# 获取实在标签数据
# 由于咱们是做节点分类使命,因而能够简略的用0、1表明节点类别。其间,黄色点标签为0,绿色点标签为1。
y = [0,1,1,1,0,0,0,1,0,1]
label = np.array(y, dtype="float32")
label = np.expand_dims(label, -1)
feed_dict['node_label'] = label
print(feed_dict)
2.4 模型练习&测试
for epoch in range(100):
train_loss = exe.run(train_program,
feed=feed_dict, # feed入实在练习数据
fetch_list=[loss], # fetch出需求的核算结果
return_numpy=True)[0]
print('Epoch %d | Loss: %f' % (epoch, train_loss))
print("Test Acc: %f" % test_acc)
Test Acc: 0.700000
3.总结
本项目首要解说了图的根本概念、图学习的概念、图的运用场景、以及图算法有哪些,最后介绍了PGL图学习结构,并给出demo实践。
Paddle Graph Learning (PGL)是一个依据PaddlePaddle的高效易用的图学习结构
PGL的长处:
- 易用性:建图便利
- 高效性:运转速度快
- 大规划:支撑十亿节点百亿边
- 丰富性:预置了干流的图学习算法
项目链接:aistudio.baidu.com/aistudio/pr…
如遇到问题查看原项目解决