MindSpore Graph Learning

时间:2022-11-14 12:07:38

MindSpore Graph Learning是一个基于MindSpore的高效易用的图学习框架。得益于MindSpore的图算融合能力,MindSpore Graph Learning能够针对图模型特有的执行模式进行编译优化,帮助开发者缩短训练时间。 MindSpore Graph Learning 还创新提出了以点为中心编程范式,提供更原生的图神经网络表达方式,并内置覆盖了大部分应用场景的模型,使开发者能够轻松搭建图神经网络。

这是一个关于mindspore-gl的官方介绍,其定位非常接近于dgl,而且从文章(参考链接3)中的数据来看,mindspore-gl的运算效率还要高于dgl。

在传统的机器学习中,我们可以对各种Tensor进行高效的运算、卷积等。但是如果是一个图结构的网络,除了把图结构转换成Tensor数据,再对Tensor进行处理之外,有没有可能用一种更加便捷的运算方式,能够直接在图的基础上去计算呢?在这里mindSpore-gl也给出了自己的答案。我们可以一起来看一下mindspore-gl是如何安装和使用的。

mindspore-gl的安装

虽然官方有提供pip的安装方法,但是在库中能够提供的软件版本是非常有限的,这里我们推荐使用源码编译安装,这样也可以跟自己本地的MindSpore的版本更好的对应上。首先把仓库clone下来,并进入到graphlearning目录下:

$ git clone https://gitee.com/mindspore/graphlearning.git
正克隆到 'graphlearning'...
remote: Enumerating objects: 1275, done.
remote: Counting objects: 100% (221/221), done.
remote: Compressing objects: 100% (152/152), done.
remote: Total 1275 (delta 116), reused 127 (delta 68), pack-reused 1054
接收对象中: 100% (1275/1275), 1.41 MiB | 316.00 KiB/s, 完成.
处理 delta 中: 100% (715/715), 完成.
$ cd graphlearning/
$ ll
总用量 112
drwxrwxr-x 12 dechin dechin  4096 11月  9 17:19 ./
drwxrwxr-x 10 dechin dechin  4096 11月  9 17:19 ../
-rwxrwxr-x  1 dechin dechin  1429 11月  9 17:19 build.sh*
drwxrwxr-x  2 dechin dechin  4096 11月  9 17:19 examples/
-rwxrwxr-x  1 dechin dechin  3148 11月  9 17:19 FAQ_CN.md*
-rwxrwxr-x  1 dechin dechin  4148 11月  9 17:19 faq.md*
drwxrwxr-x  8 dechin dechin  4096 11月  9 17:19 .git/
-rwxrwxr-x  1 dechin dechin  1844 11月  9 17:19 .gitignore*
drwxrwxr-x  2 dechin dechin  4096 11月  9 17:19 images/
drwxrwxr-x  3 dechin dechin  4096 11月  9 17:19 .jenkins/
-rw-rw-r--  1 dechin dechin 11357 11月  9 17:19 LICENSE
drwxrwxr-x 11 dechin dechin  4096 11月  9 17:19 mindspore_gl/
drwxrwxr-x 11 dechin dechin  4096 11月  9 17:19 model_zoo/
-rwxrwxr-x  1 dechin dechin    52 11月  9 17:19 OWNERS*
-rwxrwxr-x  1 dechin dechin  3648 11月  9 17:19 README_CN.md*
-rwxrwxr-x  1 dechin dechin  4570 11月  9 17:19 README.md*
drwxrwxr-x  4 dechin dechin  4096 11月  9 17:19 recommendation/
-rwxrwxr-x  1 dechin dechin   922 11月  9 17:19 RELEASE.md*
-rwxrwxr-x  1 dechin dechin   108 11月  9 17:19 requirements.txt*
drwxrwxr-x  2 dechin dechin  4096 11月  9 17:19 scripts/
-rwxrwxr-x  1 dechin dechin  4164 11月  9 17:19 setup.py*
drwxrwxr-x  5 dechin dechin  4096 11月  9 17:19 tests/
drwxrwxr-x  5 dechin dechin  4096 11月  9 17:19 tools/

然后执行官方提供的编译构建的脚本:

$ bash build.sh 
mkdir: 已创建目录 '/home/dechin/projects/mindspore/graphlearning/output'
Collecting Cython>=0.29.24
  Downloading Cython-0.29.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (2.0 MB)
     |████████████████████████████████| 2.0 MB 823 kB/s 
Collecting ast-decompiler>=0.6.0
  Downloading ast_decompiler-0.7.0-py3-none-any.whl (13 kB)
Collecting astpretty>=2.1.0
  Downloading astpretty-3.0.0-py2.py3-none-any.whl (4.9 kB)
Collecting scikit-learn>=0.24.2
  Downloading scikit_learn-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (30.8 MB)
     |████████████████████████████████| 30.8 MB 2.6 MB/s 
Requirement already satisfied: numpy>=1.21.2 in /home/dechin/anaconda3/envs/mindspore16/lib/python3.9/site-packages (from -r /home/dechin/projects/mindspore/graphlearning/requirements.txt (line 5)) (1.23.2)
Collecting networkx>=2.6.3
  Downloading networkx-2.8.8-py3-none-any.whl (2.0 MB)
     |████████████████████████████████| 2.0 MB 4.6 MB/s 
Requirement already satisfied: scipy>=1.3.2 in /home/dechin/anaconda3/envs/mindspore16/lib/python3.9/site-packages (from scikit-learn>=0.24.2->-r /home/dechin/projects/mindspore/graphlearning/requirements.txt (line 4)) (1.5.3)
Collecting threadpoolctl>=2.0.0
  Downloading threadpoolctl-3.1.0-py3-none-any.whl (14 kB)
Collecting joblib>=1.0.0
  Downloading joblib-1.2.0-py3-none-any.whl (297 kB)
     |████████████████████████████████| 297 kB 2.2 MB/s 
Installing collected packages: threadpoolctl, joblib, scikit-learn, networkx, Cython, astpretty, ast-decompiler
Successfully installed Cython-0.29.32 ast-decompiler-0.7.0 astpretty-3.0.0 joblib-1.2.0 networkx-2.8.8 scikit-learn-1.1.3 threadpoolctl-3.1.0
running bdist_wheel
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.9
...
removing build/bdist.linux-x86_64/wheel
mindspore_gl_gpu-0.1-cp39-cp39-linux_x86_64.whl
------Successfully created mindspore_gl package------

如果看到以上的消息,那就表示编译构建成功了,接下来只要把生成的whl包使用pip进行安装即可:

$ python3 -m pip install ./output/mindspore_gl_gpu-0.1-cp39-cp39-linux_x86_64.whl
Processing ./output/mindspore_gl_gpu-0.1-cp39-cp39-linux_x86_64.whl
Requirement already satisfied: Cython in /home/dechin/.local/lib/python3.9/site-packages (from mindspore-gl-gpu==0.1) (0.29.32)
Requirement already satisfied: astpretty in /home/dechin/.local/lib/python3.9/site-packages (from mindspore-gl-gpu==0.1) (3.0.0)
Requirement already satisfied: ast-decompiler>=0.3.2 in /home/dechin/.local/lib/python3.9/site-packages (from mindspore-gl-gpu==0.1) (0.7.0)
Requirement already satisfied: scikit-learn>=0.24.2 in /home/dechin/.local/lib/python3.9/site-packages (from mindspore-gl-gpu==0.1) (1.1.3)
Requirement already satisfied: threadpoolctl>=2.0.0 in /home/dechin/.local/lib/python3.9/site-packages (from scikit-learn>=0.24.2->mindspore-gl-gpu==0.1) (3.1.0)
Requirement already satisfied: joblib>=1.0.0 in /home/dechin/.local/lib/python3.9/site-packages (from scikit-learn>=0.24.2->mindspore-gl-gpu==0.1) (1.2.0)
Requirement already satisfied: scipy>=1.3.2 in /home/dechin/anaconda3/envs/mindspore16/lib/python3.9/site-packages (from scikit-learn>=0.24.2->mindspore-gl-gpu==0.1) (1.5.3)
Requirement already satisfied: numpy>=1.17.3 in /home/dechin/anaconda3/envs/mindspore16/lib/python3.9/site-packages (from scikit-learn>=0.24.2->mindspore-gl-gpu==0.1) (1.23.2)
Installing collected packages: mindspore-gl-gpu
Successfully installed mindspore-gl-gpu-0.1

我们可以用如下指令验证一下mindspore-gl是否安装成功(后面的告警信息是MindSpore产生的,不是mindspore-gl产生的,一般情况下,我们可以忽视掉):

$ python3 -c 'import mindspore_gl'
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.348.03 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.350.73 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.351.54 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.352.40 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.352.94 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.353.43 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install
[WARNING] ME(3662914:140594637309120,MainProcess):2022-11-09-17:22:29.353.91 [mindspore/run_check/_check_version.py:189] Cuda ['10.1', '11.1'] version(need by mindspore-gpu) is not found, please confirm that the path of cuda is set to the env LD_LIBRARY_PATH, please refer to the installation guidelines: https://www.mindspore.cn/install

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 ms

In [2]: from mindspore_gl import Graph, GraphField

In [3]: from mindspore_gl.nn import GNNCell

In [4]: n_nodes = 3

In [5]: n_edges = 3

In [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   ||  1      def construct(                                                                           |
|                                                                                                  ||             self,                                                                                |
|                                                                                                  ||             x,                                                                                   |
|                                                                                                  ||             y,                                                                                   |
|                                                                                                  ||             src_idx,                                                                             |
|                                                                                                  ||             dst_idx,                                                                             |
|                                                                                                  ||             n_nodes,                                                                             |
|                                                                                                  ||             n_edges,                                                                             |
|                                                                                                  ||             UNUSED_0=None,                                                                       |
|                                                                                                  ||             UNUSED_1=None,                                                                       |
|                                                                                                  ||             UNUSED_2=None                                                                        |
|                                                                                                  ||         ):                                                                                       |
|                                                                                                  ||  2          SCATTER_ADD = ms.ops.TensorScatterAdd()                                              |
|                                                                                                  ||  3          SCATTER_MAX = ms.ops.TensorScatterMax()                                              |
|                                                                                                  ||  4          SCATTER_MIN = ms.ops.TensorScatterMin()                                              |
|                                                                                                  ||  5          GATHER = ms.ops.Gather()                                                             |
|                                                                                                  ||  6          ZEROS = ms.ops.Zeros()                                                               |
|                                                                                                  ||  7          FILL = ms.ops.Fill()                                                                 |
|                                                                                                  ||  8          MASKED_FILL = ms.ops.MaskedFill()                                                    |
|                                                                                                  ||  9          IS_INF = ms.ops.IsInf()                                                              |
|                                                                                                  ||  10         SHAPE = ms.ops.Shape()                                                               |
|                                                                                                  ||  11         RESHAPE = ms.ops.Reshape()                                                           |
|                                                                                                  ||  12         scatter_src_idx = RESHAPE(src_idx, (SHAPE(src_idx)[0], 1))                           |
|                                                                                                  ||  13         scatter_dst_idx = RESHAPE(dst_idx, (SHAPE(dst_idx)[0], 1))                           |
|        g.set_src_attr({'hs': x})                                                             2   ||  14         hs, = [x]                                                                            |
|        g.set_dst_attr({'hd': y})                                                             3   ||  15         hd, = [y]                                                                            |
|        return [v.hd for v in g.dst_vertex] * [u.hs for u in g.src_vertex]                    4   ||  16         return hd * hs                                                                       |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

In [12]: print (ret)
[[2.0], [6.0], [3.0]]

从这个结果中,我们获得的是三条边两头的节点值的积。除了节点id和节点值之外,mindspore-gl还支持了一些如近邻节点、节点的度等参数的获取,可以参考如下图片所展示的内容(图片来自于参考链接2):

MindSpore Graph Learning

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

MindSpore Graph Learning

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

MindSpore Graph Learning
MindSpore Graph Learning

那么最后我们再展示一个聚合的简单案例,其实就是获取节点的近邻节点值的加和:

import mindspore as ms
from mindspore import ops
from mindspore_gl import Graph, GraphField
from mindspore_gl.nn import GNNCell

n_nodes = 3
n_edges = 3

src_idx = ms.Tensor([0, 1, 2, 3, 4], ms.int32)
dst_idx = ms.Tensor([1, 2, 0, 1, 2], ms.int32)

graph_field = GraphField(src_idx, dst_idx, n_nodes, n_edges)
node_feat = ms.Tensor([[1], [2], [3], [4], [5]], ms.float32)

class GraphConvCell(GNNCell):
    def construct(self, x, y, g: Graph):
        g.set_src_attr({"hs": x})
        g.set_dst_attr({"hd": y})
        return [g.sum([u.hs for u in v.innbs]) for v in g.dst_vertex]

ret = GraphConvCell()(node_feat[src_idx], node_feat[dst_idx], *graph_field.get_graph()).asnumpy().tolist()
print (ret)

那么这里只要使用一个graph.sum这样的接口就可以实现,非常的易写方便,代码可读性很高。

$ python3 test_msgl_01.py
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|    def construct(self, x, y, g: Graph):                                                      1   ||  1      def construct(                                                                           |
|                                                                                                  ||             self,                                                                                |
|                                                                                                  ||             x,                                                                                   |
|                                                                                                  ||             y,                                                                                   |
|                                                                                                  ||             src_idx,                                                                             |
|                                                                                                  ||             dst_idx,                                                                             |
|                                                                                                  ||             n_nodes,                                                                             |
|                                                                                                  ||             n_edges,                                                                             |
|                                                                                                  ||             UNUSED_0=None,                                                                       |
|                                                                                                  ||             UNUSED_1=None,                                                                       |
|                                                                                                  ||             UNUSED_2=None                                                                        |
|                                                                                                  ||         ):                                                                                       |
|                                                                                                  ||  2          SCATTER_ADD = ms.ops.TensorScatterAdd()                                              |
|                                                                                                  ||  3          SCATTER_MAX = ms.ops.TensorScatterMax()                                              |
|                                                                                                  ||  4          SCATTER_MIN = ms.ops.TensorScatterMin()                                              |
|                                                                                                  ||  5          GATHER = ms.ops.Gather()                                                             |
|                                                                                                  ||  6          ZEROS = ms.ops.Zeros()                                                               |
|                                                                                                  ||  7          FILL = ms.ops.Fill()                                                                 |
|                                                                                                  ||  8          MASKED_FILL = ms.ops.MaskedFill()                                                    |
|                                                                                                  ||  9          IS_INF = ms.ops.IsInf()                                                              |
|                                                                                                  ||  10         SHAPE = ms.ops.Shape()                                                               |
|                                                                                                  ||  11         RESHAPE = ms.ops.Reshape()                                                           |
|                                                                                                  ||  12         scatter_src_idx = RESHAPE(src_idx, (SHAPE(src_idx)[0], 1))                           |
|                                                                                                  ||  13         scatter_dst_idx = RESHAPE(dst_idx, (SHAPE(dst_idx)[0], 1))                           |
|        g.set_src_attr({'hs': x})                                                             2   ||  14         hs, = [x]                                                                            |
|        g.set_dst_attr({'hd': y})                                                             3   ||  15         hd, = [y]                                                                            |
|        return [g.sum([u.hs for u in v.innbs]) for v in g.dst_vertex]                         4   ||  16         SCATTER_INPUT_SNAPSHOT1 = GATHER(hs, src_idx, 0)                                     |
|                                                                                                  ||  17         return SCATTER_ADD(                                                                  |
|                                                                                                  ||                 ZEROS(                                                                           |
|                                                                                                  ||                     (n_nodes,) + SHAPE(SCATTER_INPUT_SNAPSHOT1)[1:],                             |
|                                                                                                  ||                     SCATTER_INPUT_SNAPSHOT1.dtype                                                |
|                                                                                                  ||                 ),                                                                               |
|                                                                                                  ||                 scatter_dst_idx,                                                                 |
|                                                                                                  ||                 SCATTER_INPUT_SNAPSHOT1                                                          |
|                                                                                                  ||             )                                                                                    |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[[3.0], [5.0], [7.0]]

下图是上面这个案例所对应的拓扑图:

MindSpore Graph Learning

总结概要

对于从元素运算到矩阵运算再到张量运算,最后抽象到图运算,这个预算模式的发展历程,在每个阶段都需要有配套的工具来进行支持。比如矩阵时代的numpy,张量时代的mindspore,还有图时代的mindspore-gl。我们未必说哪种运算模式就一定更加先进,但是对于coder来说,“公式即代码”这是一个永恒的话题,而mindspore-gl在这一个工作上确实做的很好。不仅仅是图模式的编程可读性更高,在GPU运算的性能上也有非常大的优化。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/mindspore_gl.html

作者ID:DechinPhy

更多原著文章请参考:https://www.cnblogs.com/dechinphy/

打赏专用链接:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

腾讯云专栏同步:https://cloud.tencent.com/developer/column/91958

CSDN同步链接:https://blog.csdn.net/baidu_37157624?spm=1008.2028.3001.5343

51CTO同步链接:https://blog.51cto.com/u_15561675

参考链接

  1. https://gitee.com/mindspore/graphlearning
  2. https://www.bilibili.com/video/BV14a411976w/
  3. Seastar: Vertex-Centric Progamming for Graph Neural Networks. Yidi Wu and other co-authors.