千字好文,依据未采样GraphSage算子和DGL完成的图上 Edge 回归


前史图算法相关文章:

(1)一文揭开图机器学习的面纱,你确定不来看看吗

(2) graphSage还是HAN ?吐血力作总述Graph Embeding 经典好文

(3) 看这儿,运用docker部署图深度学习结构GraphLearn运用说明

(4) GraphSage与DGL完成同构图 Link 猜测,通俗易懂好文强推

(5) 依据GCN和DGL完成的图上 node 分类, 值得一看!!!

书接上文,在前面的几篇文章中,咱们对在 图上跑机器学习/深度学习模型 有了一个大概的了解,并从 代码层面 一同 分别依据 DGL和 Graph Learn 结构完成了 链接猜测 , 节点分类与回归使命 。下面让咱们开端 图上边(Edge) 的回归与分类使命 的介绍吧~


(1) 图常识升华理解

在 依据GCN和DGL完成的图上 node 分类, 值得一看!!! 文章中,咱们了解到,不管在图上对 链接存在与否 进行 链接猜测 还是对 节点进行定性性质分类回归 使命,其实咱们都是 依据某个节点与它周围街坊节点的联系 来进行判别的,咱们 试图让模型去学习节点周围的局部特性以及图上空间结构上的大局类似或相异模式 ,以达到依据图上联系来完成 机器学习使命 的目的。

不管在图上进行什么性质的使命,图上的 音讯传达 永远是剖析的 核心点 。怎么构图、彼此节点的特点之间与边的特点之间各种联系怎么进行交融、怎么初始化节点与边的特点值、音讯传达的过程怎么细化运用等,这些都需求经验与技巧,才干让咱们的模型学习到咱们使命所需求的东西,提升模型作用。

留意: 曾经的前史文章中,关于分类回归使命作者并没有能够的去进行区别,因为至少在代码完成上没什么难度,仅仅是输入和丢失的更换罢了。而 重点去着重 了图上的有监督与无监督,链接还是节点的猜测,以及本文所说的边的回归与分类等这些模块,是因为这些模块涉及到了一些 底层的采样思维 ,针对节点和边的不同操作以及图上音讯传达的理解等,这些更有 价值 一些。

其实,通过前面一些列文章的解说, 图算法的面纱 在咱们面前现已一点点的被揭下来了,至少不再是许多人眼中那么的 高不可攀 了。跟着对 图结构 的认识的深化,结合事务的运用,咱们也应该能够了解到:其完成实中许多问题,天然适合用图算法来进行联系建模,而有许多问题,则并不适合用图来进行处理。而还有许多问题,尽管不适合直接用图来处理,但是能够用图使命做辅佐使命,来产出有意义的中间结果 Embeding,为终究的目标使命服务

实践才是查验真理的唯一标准,实践出真知 ,接下来让咱们一同学习而且运用好图机器学习相关的常识吧~


(2) 图上边分类与回归理解

在前史文章 GraphSage与DGL完成同构图 Link 猜测,通俗易懂好文强推 中,咱们讲到 边分类与回归,就是去猜测图上的边是属于哪种类型的边,以及去猜测边上的特点值。例如:图上的边分类与回归猜测的能够是购买了衣服还是搜藏的衣服,以及会买几件的这个数值,分别对应着 图上边的分类与回归 使命。

依据图的结构咱们知道,边是链接着两个节点的而且边也能够带着特点特征 的。既然边能够带着特点特征,那么边也就能够导出 边的embeding 。中间咱们要清晰一点就是,因为边是起着 桥梁 的作用,所以边的embeding必定也是和边两端的节点有着密切联系的,咱们能够在更新节点的embeding过程中,顺带着就把边的embeding更新了。当然,你要固定着初始值不练习也能够。

直接一些: 假如用户运用上一节文章中的模型核算了节点的表明,那么用户只需求再编写一个用 apply_edges() 办法核算边猜测的组件即可进行边分类/回归使命。

例如,关于本文中解说的 边回归 使命,假如用户想为每条边核算一个分数,可对每一条边核算它的两端节点隐藏表明的点积来作为分数,也能够再接入几层DNN也是能够的。


(3) 代码韶光

老规矩,开篇先吼一嗓子 , talk is cheap , show me the code !!!

通过 前面 几篇文章 的介绍,想来作者对 dgl来编写图上机器学习使命 现已十分清晰了。本章的代码相对简略,下面就让咱们开端吧 ~

(3.1) 导包

留意: dgl 包选择 0.9 版别,只需求下面这些包就能够了。

@欢迎重视微信大众号:算法全栈之路
importtorch
importtorch.nnasnn
importdgl
importnumpyasnp
importdgl.functionasfn
importdgl.nn.pytorch.convasconv
importtorch.nnasnn
importtorch.nn.functionalasF

(3.2) 构图与赋予初始特征

留意: 这儿的数据咱们能够运用 numpy 或则pandas 进行赋予初始值。假如要想embeding跟着网络更新,能够选用 nn.Parameter 或则 Variable 变量的形式,并让模型的梯度更新优化算法能够包括更新这个变量即可。


@欢迎重视微信大众号:算法全栈之路
src=np.random.randint(0,100,500)
dst=np.random.randint(0,100,500)
#一起树立反向边
edge_pred_graph=dgl.graph((np.concatenate([src,dst]),np.concatenate([dst,src])))
#树立点和边特征,以及边的标签
edge_pred_graph.ndata['feature']=torch.randn(100,10)
edge_pred_graph.edata['feature']=torch.randn(1000,10)
edge_pred_graph.edata['label']=torch.randn(1000)
#进行练习、验证和测验集区别
edge_pred_graph.edata['train_mask']=torch.zeros(1000,dtype=torch.bool).bernoulli(0.6)

这儿,咱们依然构建的是同构图使命。

留意:最终的mask部分,torch.zeros(1000, dtype=torch.bool).bernoulli(0.6) 运用的这个接口进行赋值bernoulli(0.6) 必不可少,不然会报数据类型对不住的错,都是泪啊!!!


(3.3) 模型结构界说

运用 dgl 图深度学习结构 界说的,前史文章均有介绍,这儿不再打开。

@欢迎重视微信大众号:算法全栈之路
classDotProductPredictor(nn.Module):
defforward(self,graph,h):
#h是GNN模型中核算出的节点表明
withgraph.local_scope():
graph.ndata['h']=h
graph.apply_edges(fn.u_dot_v('h','h','score'))
returngraph.edata['score']
classSAGE(nn.Module):
def__init__(self,in_feats,hid_feats,out_feats):
super().__init__()
#实例化SAGEConve,in_feats是输入特征的维度,out_feats是输出特征的维度,aggregator_type是聚合函数的类型
self.conv1=conv.SAGEConv(
in_feats=in_feats,out_feats=hid_feats,aggregator_type='mean')
self.conv2=conv.SAGEConv(
in_feats=hid_feats,out_feats=out_feats,aggregator_type='mean')
defforward(self,graph,inputs):
#输入是节点的特征
h=self.conv1(graph,inputs)
h=F.relu(h)
h=self.conv2(graph,h)
returnh
classModel(nn.Module):
def__init__(self,in_features,hidden_features,out_features):
super().__init__()
self.sage=SAGE(in_features,hidden_features,out_features)
self.pred=DotProductPredictor()
defforward(self,g,x):
h=self.sage(g,x)
returnself.pred(g,h)

从这儿的代码咱们能够看到: 首要的函数依然是 Sage 算子DotProductPredictor办法 ,这个咱们在 GraphSage与DGL完成同构图 Link 猜测,通俗易懂好文强推 有了介绍,这儿就不再赘述了。

这儿要 着重 的一点就是:图上边的 predict的值 是由 DotProductPredictor 这个办法点积核算得到的。咱们也能够选用 几层DNN来交融两个节点的embeding , 就像这样 :

@欢迎重视微信大众号:算法全栈之路
classMLPPredictor(nn.Module):
def__init__(self,in_features,out_classes):
super().__init__()
self.W=nn.Linear(in_features*2,out_classes)
defapply_edges(self,edges):
h_u=edges.src['h']
h_v=edges.dst['h']
score=self.W(torch.cat([h_u,h_v],1))
#这儿是不是能够得到一个一定维度的边的embeding
return{'score':score}
defforward(self,graph,h):
#h是从5.1节的GNN模型中核算出的节点表明
withgraph.local_scope():
graph.ndata['h']=h
graph.apply_edges(self.apply_edges)
returngraph.edata['score']

留意: 在上面的 apply_edges 办法里,咱们是不是能够 得到一个一定维度的边的embeding呢,然后把它存入到边的特点特征中,跟着网络更新而更新。那这样,咱们是不是最终就能够到处图上边的embeding了呢。


(3.4) 模型练习

接下来,就是 模型练习了。留意,这儿以边的回归算法为例进行说明,更改为边的分类算法也十分简略,读者能够下去自己修改下~

@欢迎重视微信大众号:算法全栈之路
#modeltrain
#在练习模型时能够运用布尔掩码区别练习、验证和测验数据集。该比如里省掉了练习早停和模型保存部分的代码。
node_features=edge_pred_graph.ndata['feature']
edge_label=edge_pred_graph.edata['label']
train_mask=edge_pred_graph.edata['train_mask']
model=Model(10,20,5)
opt=torch.optim.Adam(model.parameters())
forepochinrange(10):
pred=model(edge_pred_graph,node_features)
#mseloss丢失
loss=((pred[train_mask]-edge_label[train_mask])**2).mean()
opt.zero_grad()
loss.backward()
opt.step()
print(loss.item())

这儿首要需求留意下 train mask和丢失相关 的内容,代码通俗易懂,我就不再赘述了。

到这儿,千字好文,依据未采样GraphSage算子和DGL完成的图上 Edge 回归 的全文就写完了。上面的代码demo 在环境没问题的情况下,悉数复制到一个python文件里,就能够完美运转起来。

接下来会针对异构体写一篇复杂使命的文章,欢迎重视~


码字不易,觉得有收获就动动小手转载一下吧,你的支持是我写下去的最大动力 ~

更多更全更新内容,欢迎重视作者的大众号: 算法全栈之路

  • END –