MindSpore Graph Learning( 三 )

mindspore-gl的简单案例我们先考虑这样一个比较基础的案例,就是最简单的一个全连接图,一个三角形 。其顶点编号分别为0、1、2,节点值分别为1、2、3,但是这里需要注意的一点是:mindspore-gl所构建的图是有向图,如果我们需要构建一个无向图,那么就需要手动copy+concat一份反方向的参数 。mindspore-gl的一种典型的使用方法,是使用稀疏形式的近邻表COO去定义一个图结构GraphField,再把图作为GNNCell的一个入参传进去 。
在计算的过程中,mindspore-gl会先执行一步编译 。mindspore-gl支持用户使用一个非常简单的for循环去对图的所有节点或者邻近节点进行遍历,然后在后台对该操作进行优化和编译 。为了展示编译成效和语法的简洁,mindspore-gl会在编译过程中把没有mindspore-gl支持下的语法都展示出来,从对比中可以看出,mindspore-gl极大程度上提高了编程的便利性 。
In [1]: import mindspore as msIn [2]: from mindspore_gl import Graph, GraphFieldIn [3]: from mindspore_gl.nn import GNNCellIn [4]: n_nodes = 3In [5]: n_edges = 3In [6]: src_idx = ms.Tensor([0, 1, 2], ms.int32)In [7]: dst_idx = ms.Tensor([1, 2, 0], ms.int32)In [8]: graph_field = GraphField(src_idx, dst_idx, n_nodes, n_edges)In [9]: node_feat = ms.Tensor([[1], [2], [3]], ms.float32)In [10]: class TestSetVertexAttr(GNNCell):...:def construct(self, x, y, g: Graph):...:g.set_src_attr({"hs": x})...:g.set_dst_attr({"hd": y})...:return [v.hd for v in g.dst_vertex] * [u.hs for u in g.src_vertex]...: In [11]: ret = TestSetVertexAttr()(node_feat[src_idx], node_feat[dst_idx], *graph_field.get_graph()).asnumpy().tolist()--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|def construct(self, x, y, g: Graph):1||1def construct(||||self,||||x,||||y,||||src_idx,||||dst_idx,||||n_nodes,||||n_edges,||||UNUSED_0=None,||||UNUSED_1=None,||||UNUSED_2=None||||):||||2SCATTER_ADD = ms.ops.TensorScatterAdd()||||3SCATTER_MAX = ms.ops.TensorScatterMax()||||4SCATTER_MIN = ms.ops.TensorScatterMin()||||5GATHER = ms.ops.Gather()||||6ZEROS = ms.ops.Zeros()||||7FILL = ms.ops.Fill()||||8MASKED_FILL = ms.ops.MaskedFill()||||9IS_INF = ms.ops.IsInf()||||10SHAPE = ms.ops.Shape()||||11RESHAPE = ms.ops.Reshape()||||12scatter_src_idx = RESHAPE(src_idx, (SHAPE(src_idx)[0], 1))||||13scatter_dst_idx = RESHAPE(dst_idx, (SHAPE(dst_idx)[0], 1))||g.set_src_attr({'hs': x})2||14hs, = [x]||g.set_dst_attr({'hd': y})3||15hd, = [y]||return [v.hd for v in g.dst_vertex] * [u.hs for u in g.src_vertex]4||16return hd * hs|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------In [12]: print (ret)[[2.0], [6.0], [3.0]]从这个结果中,我们获得的是三条边两头的节点值的积 。除了节点id和节点值之外,mindspore-gl还支持了一些如近邻节点、节点的度等参数的获取,可以参考如下图片所展示的内容(图片来自于参考链接2):
【MindSpore Graph Learning】

MindSpore Graph Learning

文章插图
除了基本的API接口之外,还可以学习下mindspore-gl的使用中有可能出现的报错信息:
MindSpore Graph Learning

文章插图
在mindspore-gl这一个框架中,还有一个对于大型数据来说非常有用的功能,当然,在文章这里只是放一下大概用法,因为暂时没有遇到这种使用的场景 。那就是把一个大型的图网络根据近邻的数量去拆分成不同大小的数据块进行存储和运算 。这样做一方面可以避免动态的shape出现,因为网络可能随时都在改变 。另一方面本身图的近邻数大部分就不是均匀分布的,有少部分特别的密集,而更多的情况是一些比较稀疏的图,那么这个时候如果要固定shape的话,就只能padding到较大数量的那一个维度,这样一来就无形之中浪费了巨大的存储空间 。这种分块模式的存储,能够最大限度上减小显存的占用,同时还能够提高运算的速度 。

经验总结扩展阅读