(机器学习)快速入门 图卷积神经网络(GCN)

关键字:图神经网络(Graph Neural Network, GNN), 图卷积神经网络(Graph Convolutional Network, GCN)
本文适合:对图神经网络不了解的人,快速了解图神经网络的输入输出和计算过程. 本文讲的很浅,但可以让读者快速了解基本的图卷积网络的输入输出。
需要的背景知识:

  1. 数据结构中图的概念;
  2. 线性代数中的矩阵、矢量与矩阵乘法;
  3. 编程中数组、稀疏矩阵的概念
  4. 一点点神经网络基础

1 图神经网络中的图是什么样的图?

首先,不是图片,而是数据结构中的图结构。它包含结点和边。
其次,图上有图信号,什么是图信号?
你可以理解为,每个节点上都有一个长度为F的矢量。这个矢量也可被称为节点的特征。每个节点的特征,也就是这个矢量,长度是一样的,我们在这里假设这个矢量的长度都为F。

2 图卷积需要什么样的输入?

实际上,图卷积的输入包含两部分:

  1. 邻接矩阵
  2. 每个节点的图信号

那么具体是什么样的数据结构来输入呢?比如邻接矩阵,是用二维数组,还是用三元组呢?这取决于你的模型对输入的具体要求了。
在实际操作中,往往没有图信号,比如我们输入一个人际交往的矩阵,节点代表人,而边代表这两个人是否认识,但我们并没有一个矢量作为特征来刻画一个人。这种情况下往往使用单位阵来表示图信号。如:对于N个节点,用N*N单位阵表示图信号,其中每一行是一个节点上的图信号。

3 图卷积的计算过程,输出是什么?

很多人会说,图卷积有两种理解:空域和频域。但实际上,它操作起来没那么复杂。本文不讲那么深,直接上它的公式:


图卷积.png

其中:

N            : 节点个数
Input_dim    : 每个节点的特征(图信号)的维度
output_dim   : 模型输出的维度
Adjacency(A) : 邻接矩阵
Feature(F)   : 所有节点的特征构成的矩阵,每一行是一个节点的特征
Weight(W)    : 权重矩阵,在模型训练中不断更新该矩阵

从公式中我们可以看出来,最终的输出形状是N*Output_dim,对于每个节点,都有了一个维度为Output_dim的表示。
我们可以把整个图卷积看成两个过程:

  1. FW 是对属性信息进行仿射变换,用来学习属性特征
  2. AFW 从空域聚合邻居节点,学习节点的结构信息

后面可以再接具体的任务,比如节点分类,分7类,那就再接一个7个节点的全连接层输出,输出的结果和label计算损失函数,然后反向传播就好。

4 现成的代码

代码用pytorch实现,需要一定的pytorch基础。
具体代码,包含数据的读取,处理,见
https://github.com/FighterLYL/GraphNeuralNetwork/tree/master/chapter5
下面我们讲其中一些重要的部分:
图卷积层:

class GraphConvolution(nn.Module):
    def __init__(self, input_dim, output_dim, use_bias=True):
        super(GraphConvolution, self).__init__()
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.use_bias = use_bias
        self.weight = nn.Parameter(torch.Tensor(input_dim, output_dim))
        if self.use_bias:
            self.bias = nn.Parameter(torch.Tensor(output_dim))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()

    def reset_parameters(self):
        nn.init.kaiming_uniform_(self.weight)
        if self.use_bias:
            nn.init.zeros_(self.bias)

    def forward(self, adjacency, input_feature):
        """
        :param adjacency:
        :param input_feature:
        :return:
        """
        support = torch.mm(input_feature, self.weight)
        output = torch.sparse.mm(adjacency, support)
        if self.use_bias:
            output += self.bias
        return output

我们可以看到,卷积层就是走的上面提到的公式,但是这个只是一层卷积层,用的时候,要把这层网络加到模型里:

class GcnNet(nn.Module):
    """
    一个包含两层GraphConvolution的模型
    """
    def __init__(self, input_dim=1433, hidden_dim=16, output_dim=7):
        """
        :param input_dim: 输入结点的矢量,1433维
        :param hidden_dim: 隐藏层节点个数
        :param output_dim: 输出维度,因为我们最终是把论文分为7类,所以是7
        """
        super(GcnNet, self).__init__()
        self.gcn1 = GraphConvolution(input_dim, hidden_dim,)
        self.gcn2 = GraphConvolution(hidden_dim, output_dim)

    def forward(self, adjacency, feature):
        h = F.relu(self.gcn1(adjacency, feature))
        logits = self.gcn2(adjacency, h)
        return logits

网络写好了就可以用了,用的时候要注意,与普通的MLP、CNN等不同,GCN要输入两个东西,一个是邻接矩阵,一个是每个节点的特征,所以,要这样用:

logits = model(tensor_adjacency, tensor_x)

其中logits是模型输出,tensor_adjacency, tensor_x分别是邻接矩阵和节点特征。另外要注意,一般来说,邻接矩阵在输入模型前需要用如下方式normalization一下(相当于左乘了归一化的拉普拉斯矩阵,不懂的话直接用就好)

def normalization(adjacency):
    """计算L=(D^-0.5) * (A+I) * (D^-0.5)"""
    adjacency += sp.eye(adjacency.shape[0])
    degree = np.array(adjacency.sum(1))  # 横向求和,算度数
    d_hat = sp.diags(np.power(degree, -0.5).flatten())  # 把 degree开-0.5次方,然后变成一个对角阵
    return d_hat.dot(adjacency).dot(d_hat).tocoo()

完整的代码是分类的任务。输入是论文引用关系的图,节点是论文,边是是否有引用关系。然后每个节点都用词袋模型做了个1433维的特征。这些论文可以分为7种,给定70%的节点作为训练集,我们的任务就是预测测试集中每篇论文的类别。具体的完整代码看https://github.com/FighterLYL/GraphNeuralNetwork/tree/master/chapter5就好

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容