CS224W摘要17.Scaling Up GNNs

Posted oldmao_2000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CS224W摘要17.Scaling Up GNNs相关的知识,希望对你有一定的参考价值。


CS224W: Machine Learning with Graphs
公式输入请参考: 在线Latex公式
这节内容貌似也很重要,是针对大规模图数据的优化。之前对这方面的了解只知道用GraphSAGE可以分Batch,貌似还有别的方法。
针对无法对GNN进行随机梯度下降的问题,搞出了GraphSAGE;
针对无法将大图直接进行full batch计算的问题,搞出了Cluster-GCN;
针对GCN模型本身进行了简化,去掉了非线性的计算,并进行了化简。

Scaling Up GNNs to Large Graphs

当前图应用的数据量

应用数据集数据量常见任务
Recommender systemsAmazon
YouTube
Pinterest
Users(绿圆): 100M~1B
Products/Videos(红方):10M ~ 1B
Recommend items(link prediction)
Classify users/items(node classification)
Social networksFacebook
Twitter
Instagram
Users:300M~3BFriend recommendation (link-level)
User property prediction(node-level)
Academic graphMicrosoft Academic GraphPapers:120M
Authors:120M
Paper categorization(node classification)
Author collaboration recommendation
Paper citation recommendation(link prediction)
Knowledge GraphsWikidata
Freebase
Entities:80M~90MKG completion
Reasoning

特点

尺寸大:节点数从10M到10B;边数量从100M到100B。
常见任务:
节点级别:User/item/paper classification
边级别:Recommendation, completion

SGD for GNN?

对于传统的ML优化方法当然就是GD:
l ( θ ) = 1 N ∑ i = 0 N − 1 l i ( θ ) \\mathcal{l}(\\theta)=\\cfrac{1}{N}\\sum_{i=0}^{N-1}l_i(\\theta) l(θ)=N1i=0N1li(θ)
对于数据量较大的时候,要计算所有的点再进行梯度更新效率很低,因此常用随机梯度下降法,每次随机取 M ( < < N ) M(<<N) M(<<N)个样本形成mini-batches,这个时候计算 M M M个样本的梯度 l s u b ( θ ) l_{sub}(\\theta) lsub(θ)更新即可: θ ← θ − ▽ l s u b ( θ ) \\theta\\leftarrow\\theta-\\triangledown l_{sub}(\\theta) θθlsub(θ)
那用这个思路把SGD用在GNN上来解决GNN面临的大数据量的问题可以吗?
假设我们从图中随机取 M ( < < N ) M(<<N) M(<<N)独立的节点

既然是独立的节点,那么采样出来的节点就是孤立的点,这样就没有办法做消息的聚合与传递了,GNN也没法玩了。
因此,原始的SGD无法用在GNN上。

Naïve full-batch implementation for GNN?

我们再看看Naïve full-batch的方式,每次生成所有节点的表征。

可以看到
1.训练过程需要加载全图的所有节点及特征
2.在每个GNN层中,都要基于前一层的所有节点的embedding计算当前层所有节点的embedding
3.计算损失
4.做GD
当前一般的DL都是用GPU来加速运算,GPU的内存一般是(10GB–20GB)6GB显存本本默默流泪。。。。这个数据量根本加载不进来:

看了直接硬train也不行,下面看三种解决方案。

Neighbor Sampling: GraphSAGE1

之前写过2,这里看了讲解有新的领悟,重新整理一下。
这个方法改进有三个部分:

基于邻域的随机梯度下降

SGD之所以无法用在GNN上是因为单个节点的采样会丢失邻居的信息,导致GNN的消息汇聚然并卵。
从GNN的计算图中可以看到,一个K层GNN的消息汇聚只涉及到该节点的K跳邻居:

那么采样的时候不单单采样某个节点,而是直接将该节点以及其K跳邻域信息包含进来,形成mini-batch:

这样就得到了基于邻域的SGD算法,具体描述如下:
1.随机采样 M ( < < N ) M(<<N) M(<<N)个节点
2.对于每个采样节点 v v v
2.1获取其K跳邻居,并构造计算图
2.2用计算图生成节点 v v v的embedding
3.计算 M M M个节点的梯度 l s u b ( θ ) l_{sub}(\\theta) lsub(θ)
4.更新梯度: θ ← θ − ▽ l s u b ( θ ) \\theta\\leftarrow\\theta-\\triangledown l_{sub}(\\theta) θθlsub(θ)

好处与问题

这里将计算图代替单个节点,即可实现mini-batch,又能保证图的信息汇聚不变,当然是效率提高的,但是也存在一个问题。在2.1步中,生成计算图非常耗费资源,因为图的邻居节点数量增长是K跳的指数级:

另外对于一些图中的超级节点,例如某个大V的粉丝好几百万,意味该节点的邻居超多,做2.2步的时候会很慢:

邻居采样

使用邻居采样进一步压缩计算图。这个也是SAGE的由来sample+aggregate。其思想就是在每跳邻居中采样 H H H个邻居,下面是 H = 2 H=2 H=2的例子

邻居采样(相当于计算树剪枝)后在进行SGD。这里只需要将前面的2.1换成下面的步骤:
对于K层GNN的邻居采样描述如下:
1.对于 k = 1 , 2 , ⋯   , K : k=1,2,\\cdots,K: k=1,2,,K:
1.1对于每个第 k k k跳的邻居,最多随机采样 H k H_k Hk个邻居
2.得到最多包含 ∏ k = 1 K H k \\prod_{k=1}^KH_k k=1KHk个叶子节点的计算图

好处与问题

较小的 H H H可以使得邻居汇聚效率大大增加,但会使得模型的训练不够稳定,因为每次随机出来邻居不一样。
虽然有了 H H H个邻居的上限,计算图大小的上限仍然和K跳(GNN的层数也是它)呈指数关系,K增加还是会使得计算图变很大。
最大的问题是随机采样,因为图中的节点明显有不一样的重要程度,采样到不重要的邻居得到embedding的结果明显不是最优的。

邻居的选择

为了解决随机采样的问题,这块研究还有待进一步研究,目前的解决方法是采取策略来采样重要的点:

例如上图中的策略是:
从绿色点开始可回原地随机游走,并计算Restarts score: R i R_i Ri(直觉上:这个玩意越高说明该节点涉及到的内部节点越多,就是random walk with restarts,RWR算法)
在每层GNN的邻居采样中对高 R i R_i Ri的邻居采样。

小结及改进思路

该方法是目前工业上应用较成熟的方法。pintrest?阿里都在用
但是该方法仍然有一些缺点:
1.计算图的大小仍然和GNN的层数成指数关系
2.计算过程非常冗余,尤其是当邻域中多个节点共享邻居的时候(在同一个mini-batch中),该邻居会在计算图中出现多次,例如:

可以看到C和D都是AB的公共邻居,每个都计算了两次,考虑某个大V节点岂不是要计算很多次?
再回头看full-batch GNN的实现过程,所有的节点都用前一层的embedding结果来更新当前层的embedding,不存在上面的重复计算问题:

而且,从计算公式可以看到,在每一层的消息汇聚,只用计算 2 × E 次 , E 2\\times E次,E 2×E,E是边数量, u u u的消息汇聚给 v v v v v v的消息汇聚给 u u u

对于 K K K层的GNN,那么计算次数为: 2 K E 2KE 2KE,也就是说整个计算过程的复杂度分别与层数、边数成线性关系,非常快。
也就是说full-batch GNN的layer-wise node embedding update方法可重复使用前一层的embedding结果,不需要冗余的计算和邻居的采样。但是,它的问题在于内存放不下,下面看从full-batch如何解决GNN的大图训练问题。

PS:这里还有另外一个模型HAG,层次化聚合图模型也是类似思想,用的是层次化的划分思想。

Cluster-GCN

子图采样

既然上面讨论了大图有很多优势,但是由于内存方面的限制导致这个方法无法使用,那么可以考虑将大图拆分成可以放进内存的小图,然后再计算的思路:

那么这里就稍微看看这个方法的可行性如何,或者说拆分后效果会不会扑街。
由于GNN的计算是基于邻居节点的消息汇聚机制的,那么,如果切分后的子图能够最大限度的保留原图的邻域信息,那么切割后子图消息汇聚产生的embedding和原图应该是差不多的。

从上面的例子看,在子图采样要最大化保证原来的connectivity,分开但丢边少。
由于现实存在的图中包含较为丰富的社区结构,因此将图中的社区采样出来作为子图,每个子图可以包含原图的local connectivity pattern。

Cluster-GCN overview

给定图 G = ( V , E ) G=(V,E) G=(V,E),将其节点 V V V划分为 C C C个组: V 1 , V 2 , ⋯   , V C V_1,V_2,\\cdots,V_C V1,V2,,VC
为了保证社区的完整性,可以使用已有的社区检验方法,例如:Louvain, METIS3
每个小组的节点 V 1 , V 2 , ⋯   , V C V_1,V_2,\\cdots,V_C V1,V2,,VC生成对应的 C C C个子图: G 1 , G 2 , ⋯   , G C G_1,G_2,\\cdots,G_C G1,G2,,GC,每个子图有以下关系:
G C ≡ ( V C , E C ) , where  E c = { ( u , v ) ∣ u , v ∈ V c } G_C\\equiv (V_C,E_C),\\\\ \\text{where }E_c=\\{(u,v)|u,v\\in V_c\\} GC(VC,EC),where Ec={(u,v)u,vVc}
每个子图之间没有边相连:

Cluster-GCN: MIni-batch Training

1.对每个mini-batch,随机采样一个节点组: V c V_c Vc
2.构造induced subgraph: G c = ( V c , E c ) G_c= (V_c,E_c) Gc以上是关于CS224W摘要17.Scaling Up GNNs的主要内容,如果未能解决你的问题,请参考以下文章

CS224W摘要16.Advanced Topics on GNNs

CS224W(task12)GAT & GNN training tips

CS224W摘要总纲(已完结)

CS224W摘要总纲(已完结)

CS224W摘要10.Knowledge Graph Embeddings

CS224W摘要03.Node Embedding