欢迎了解 GraphLearn,如果觉得还不错请它加一个小星星🌟! GraphLearn开源地址:https://github.com/alibaba/graph-learn
一、GNN背景与趋势
(一)深度学习的发展
深度学习的第一个爆发点来自于机器视觉。ImageNet竞赛引发了深度学习的热潮,CV算法的识别能力也一度超过了人类,自此之后,我们见到了成熟的CV产品的落地,比如人脸识别,而CV的发展也由研究逐渐转向到应用。
深度学习的第二个爆发点来自于NLP自然语言处理,随着Transformer、BERT等模型的不断迭代,机器翻译、阅读理解等问题的精度被屡屡刷新。
相比于前两者,图与深度学习的结合是后起之秀,近几年受到各大AI顶会的追捧。图像和自然语言更偏客观,因为图像的组成原理不变,人类的语言构成不变,对于CV和NLP的研究,是有一个上限的。但是图的构成更偏主观,我们可以把任何有关联的事物抽象成图,比如购买关系、好友关系、基因的碱基关系等,这种抽象方法是没有上限的,这赋予了我们关于图研究在时间之外的想象空间,各种图数据中蕴含着巨大的商业价值和科学价值。
(二)图与深度学习的一体化趋势
我们对图的认识是从学习图本身开始的,比如在图中找到某两点间的最短连通路径。而在商业中我们更倾向于把图纳入到一个具体场景,作为解决方案的一部分,比如在电商网站,把用户的购物行为图作为精准推荐算法的一部分,对于图的使用由学图变成了用图。
用图的难点在于图是不规则的,我们很难在不规则的数据上开展高效计算,更难把它与以深度学习为基础的面向场景的任务结合起来。Embedding技术是一个重大突破,使得我们能够把离散的、不规则的数据稠密化和向量化,这也为图与深度学习的结合提供了桥梁。
近年来,各类图神经网络算法(Graph Neural Network,GNN)的发展与应用是图与深度学习结合价值的最好证明。当然,未来还会有很大的探索空间。
图神经网络算法的快速发展,让当下主流的深度学习框架稍显不足,尤其是面向工业界的复杂场景的时候,这也在某种程度上限制了图神经网络的推广。我们相信图的重要性以及图与深度学习结合将带来的巨大价值,把图纳入到深度学习范畴,是一个自然趋势,因此,我们需要在框架上提供相应的支持。
现在我们经常提到大数据,大数据之所以称为大,是因为数据内部有了错综复杂的联系,这才是价值空间所在,不然单纯的量大也只能称为多,所以大数据在本质上其实说的是图数据。
GNN是一个图与深度神经网络结合和落地的产物,它的一个直观解释是利用深度神经网络的挖掘能力去发现蕴含丰富信息的图数据中的价值,目前主流的做法是把不规则的图数据映射到规则的向量空间,从而对接深度学习理论,如下图所示。
二、GraphLearn的理念与特性
每一个有价值的事物,必然要经过时间的检验,才能被证明它有价值和保持长久的生命力,图神经网络也不例外。因此, 我们在设计图神经网络框架的时候,至少需要考虑以下几点:
- 支持工业生产:首先考虑支持工业生产,因为工业是我们接触实际场景最近的一个环节,工业场景所要求的效率稳定性非常严格,要处理的图数据也更为复杂,这是框架的难度所在。
- 兼容开源生态:大数据和深度学习推动了工业的发展,也让开源社区达到了前所未有的繁荣。开源是技术史上的文明,让我们都从中受益,遍观当下没有哪个AI技术可以脱离开源生态而独立存在,图神经网络框架也必然要拥抱开源。
- 便于功能扩展:图神经网络处于一个快速发展阶段,算法迭代非常快,落地的应用百花齐放,作为框架也必然要跟得上节奏,甚至要做出预判,在不断变化的需求中便于扩展。
GraphLearn是一个我们自研的面向开发者的图神经网络框架,框架根植于阿里巴巴集团的业务,经过沉淀和孵化,充分考虑了数据、应用、生态等问题。目前GraphLearn已经作为云产品的一部分,大家可以通过阿里云官网机器学习平台PAI来试用。当然,框架代码也已经在开源社区公开,可以一键安装我们发布好的package,也可以根据自己的开发环境,从源码编译安装或者二次开发。
GraphLearn目前主要有以下特性:
1. 工业级数据支持
实际中的图数据非常复杂,尤其对互联网公司而言,存在着各种形式的图数据。概括来说,工业级图数据的特点主要有:
- 超大规模:工业级的数据往往可以达到千亿级别,百亿级别和TB级存储。
- 点边异构:工业级的数据不规则,点边异构化,往往有多种类型的点和多种类型的边。
- 属性多样:点和边并非只有一个单独的ID,同时也存在着多样化的属性信息,这些属性不规则,类型也不一。
对于上述的图数据,GraphLearn可以做到在几分钟内完成从文件系统的原始数据到内存索引的构建,并通过提供简单易用的API简化复杂数据的操作。
2. 统一的编程范式
数据的复杂性也影响了上层算法的编程范式。面对如此规模的数据,采样是一个必要过程,采样就是把大图变成小图,并做必要的数据对齐,以满足深度学习迭代训练的需要。不同的采样算法直接影响了上层计算的数据输入。
GraphLearn内置了多种采样算子并支持扩展,此外,GraphLearn也内置了复采样模块,作为对无监督训练的支持。采样之后是向量化,这也是和学术界的一些图神经网络框架区别比较大的地方,因为我们要处理的数据的原始数据是ID和属性,是离散的数据,而并不是已经向量化好的数据。这些离散的数据需要经过向量化的过程,把离散的特征稠密化。然后在向量化好的基础上,做邻域的聚合和自身信息的整合,这是当前最流行的图神经网络的编程框架。 上述的每一个阶段在GraphLearn中都有对应的接口支持,以简化开发的过程。
3. 可扩展的计算模式
为了可扩展,GraphLearn抽象了每个算子的计算模式,包括MAP,PROESS,REDUCE三个阶段,该范式可以覆盖关于图的大多数计算的需求。
以采样为例,当Server收到API的采样请求时,MAP阶段根据图划分策略,把ID分发到数据所对应的Server上面去。因为图是分布式存储的,每一个server只存储图的一个分片,PROESS阶段则在每个Server上执行采样计算,尽可能避免数据迁移带来的开销,REDUCE阶段则把每个Server的结果汇聚起来。
如果我们要扩展一种新的采样算法,那么只需实现这三个函数即可,因此扩展起来比较容易。
4. 支持面向业务定制化
为了便于应用,GraphLearn支持面向业务的定制化,在实际的每个场景中都有具体的深度学习模型来支撑,且模型与业务紧密结合。 我们可以从最底层的数据接入出发,在经过必要的算子和Graph Embedding算法产出图的向量化表示,然后把向量化表示接入到业务模型中,就构成了一个端到端的大模型,且训练过程中的信息也可以反向传播到大模型中的每一层。现在也已经有一些公开成果显示,这种端到端的训练在模型效果上会有更好的收益,而且在效率上也免去了中间结果落地的开销。
5. 可与PAI云产品集成
目前,GraphLearn已经在阿里云机器学习平台PAI上发布,且兼容PAI云产品,比如DLC、DSW等,打通了与MaxCompute、OSS等产品的连接。我们可以在PAI平台上利用GraphLearn和TensorFlow来开发一个图神经网络算法,也可以直接调用我们发布的算法组件。PAI后台的资源调度和安全隔离,包括深度优化的软件在内,为开发和生产提供了比较好的保障。
6. 兼容开源生态
在开源方面,GraphLearn与社区内主流的深度学习生态兼容,且比较轻量级,方便安装部署,支持单机和分布式,不同模式只需要简单的配置即可。我们可以基于GraphLearn结合TensorFlow或者Pytorch开发自己的图神经网络算法和应用,也可以在探索阶段结合Python和Numpy进行高效率的调试。
目前,在阿里内部GraphLearn已经有多个场景落地,比如搜索推荐、网络安全和知识图谱等,在各个场景中都对业务效率有了非常大的提升。
三、GraphLearn的概念与用法
上面从宏观上介绍了GraphLearn的特点,那么它具体能做什么呢?其基本概念和用法都有哪些呢?
比如下面这张图,我们把场景分到了4个象限,横轴为图和神经网络,纵轴为离线和在线,两两结合。左上角侧重图的离线场景,比如像图采样、复采样等,可以在任意一个图上进行,可以作为特征工程的一部分产出训练需要的样本,也可以对产出的图做一个召回的hitrate计算,评估效果,对于图的其他操作也可以方便的在该象限进行扩展。左下角可以看成是把左上角对应的离线操作转成了在线,比如hatrate这种计算,我们变成了向量召回,在线支持是由GraphLearn本身的Service化部署能力来提供的。
右上角是离线的模型开发与训练,GraphLearn提供了必要的图数据处理能力和简化模型开发的接口以及与PyTorch结合的能力,熟悉TF和PyTorch的同学可以更快的上手,学习成本更小。右下角是模型的在线推理和Graph Embedding召回,其中一些模型的实时推理与实时的图数据相关,这方面也是我们目前正在做的方向。
(一)安装部署
GraphLearn的主体代码由C++开发,提供Python层的封装,可以wheel包的形式进行安装;我们还提供了Ubuntu 16.04下基于g++ 5.4.0编译的安装包,可以直接下载并通过pip install的方式进行安装。对于与上述环境不兼容的其他环境,可以从源码编译、安装,整个过程也只需要简单的几行代码即可完成。安装完成后进入Python命令行,输入import graphlearn来检验安装是否正确。
GraphLearn的部署支持单机和分布式,其中分布式场景又支持Worker Mode和Server Mode。单机场景适用于数据比较小、或原型开发阶段,部署时只需要g.init()即可,不需要任何额外参数。Worker Mode的分布式部署表示图数据是分布式存储的,每个Worker存储图的一个分片,Worker之间可以两两通信。在训练时,Worker可以访问本地的图数据,对于涉及到远程数据的访问的操作,在逻辑上图是一个整体,无论从哪个Worker查询都会保证数据的正确性。在Worker Mode初始化的时候,我们需要传入当前Worker的ID以及分布式的总量count。
在使用Server Mode分布式部署时,训练的Worker和图数据的server是分开的,一般用于图数据规模和训练规模不对称的情况下。比如当前数据量我们用20个Server就可以容下,但想用100个Worker来加速模型的训练,这时候就需要用到Server Mode的部署方式。此时如果用Worker Mode来部署,那就意味着图数据会存在100个Worker上,而100个Worker之间的两两通信的代价要比20个Server两两通信的代价大得多。
在Server Mode模式下,每个Worker都与一个Server相连,作为数据连接的入口,也比较容易做到Worker的动态伸缩,在Server mode部署的时候,我们需要给g.init()传入cluster spec。
(二)数据源&数据格式
在数据方面,从文件系统加载数据到内存组织成图的结构,原始数据在文件系统是离散的,而非图形式的存在,比如一条顶点数据或者是一条边数据。文件系统的类型可以按需扩展,目前支持的有本地文件系统,阿里云的MaxCompute表,还有NFS等。如果想要扩展一种数据源,只需实现必要的读写接口即可。
为了支持典型场景下数据的需求,GraphLearn抽象了weight、label和attributes三种格式,对于顶点数据和边数据三种格式都作为可选项。例如下图中间图的左部分顶点数据源,除了必要的顶点ID以外,若有权重列,表示这个顶点是有权重的,若有label列表示顶点是有标签的,若有attributes则表示顶点是有属性的,对于边数据也是一样。数据格式是通过Decoder对象来描述,weighted和labeled只需要设置True或False就可以了。 对于attributes需要设置每个attributes的类型,如下图所示顶点有三个属性,其中第一个为string类型,第二个和第三个是int类型,属性之间是以冒号分割。
(三)图对象:数据与计算的载体
前面的介绍里都通过g作为出口,g作为全局图对象,在GraphLearn中所有关于图数据的操作都通过该对象进行。图对象的声明比较简单,只需要gl.Graph()即可返回一个图对象。有了图对象之后可以为其增加数据,比如下面代码中为图对象增加了user和movie两种类型的顶点数据,然后又增加了点击关系和相似关系,仅需几行代码就完成了拓扑关系的构建。最后,我们只需要g.init()就可以把数据从原始的文件系统载入成内存图结构并开始对外服务。图构建完成之后,就可以进行相关的计算,比如图遍历、图采样、负采样等。
import graphlearn as gl g = gl.Graph() g.node(source="path_1", node_type="user", decoder=Decoder(attr_types=["int", "float", "int"])) .node(source="path_2", node_type="movie", decoder=Decoder(labeled=True) .edge(source="table_4", edge_type=("user", "movie", "click"), decoder= Decoder(weighted=True) ) .edge(source="table_5", edge_type=("movie", "movie", "similar"), decoder=Decoder(weighted=True) ) .init() s1 = g.node_sampler("user", batch_size=512, strategy="random") s2 = g.edge_sampler("click", batch_size=512, strategy="random") s3 = g.neighbor_sampler(meta_path, expand_factor, strategy="random") s4 = g.negative_sampler(meta_path, expand_factor, strategy="random")
(四)Graph Sampling Language(GSL)
在实际场景中,模型依赖的图操作可能会很复杂。比如之前提到的用户和电影之间的推荐算法,我们为了预测用户和电影的连接关系,大致需要以下步骤:
1. 从图上按Batch获取边;
2. 对边的目的顶点采样二阶邻居,对边的原顶点采样一阶邻居,这是对边的编码过程,采样其顶点感受域;同时还要对边的原顶点,也就是所谓的user顶点采样它的负邻居,也就是没有直接关系的那些item;
3. 对负采样的结果,也需要采样它的二跳邻居作为编码。上面对图操作的过程作为模型的输入,这个过程表达起来是非常困难。 为了进一步简化这样的操作,提高运行效率,我们提出了Graph Sampling Language(GSL)作为图采样语言。GSL形式与经典的图查询语言有相近之处,本质上是将关于图的操作描述成一个DAG,由后台引擎高效的执行。关于GSL的详细用法,可以参考开源文档上的介绍。
四、GraphLearn的未来规划
接下来GraphLearn会从几个方面推进GNN及其生态的建设:
1. 首先是算法与业务。GNN的价值一定是由应用、算法、框架共同去证明,业务和算法是风向标,GNN的生命力要通过落地到场景才能保持,而实践会带来算法上的创新。
2. 另一方面是图数据和编程框架。业务和算法的变化,无论是在规模上还是图的组织方式上,必然带来不一样的数据以及连接算法与数据的编程框架,软件层的优化也主要体现在这一部分。
3. 最后是新型硬件。框架是合理的利用算力,但并不能创造算力。极致的性能最终来源于硬件的支持。深度学习已经引发了好几代GPU的变革,但GPU纯粹用于这种不规则的计算,并不经济,我们也在探索适合GNN的新型硬件。
欢迎了解 GraphLearn,如果觉得还不错请它加一个小星星🌟!
GraphLearn开源地址:https://github.com/alibaba/graph-learn