图神经网络(GNN)的基本原理
本文结合一个具体的无向图来对最简单的一种GNN进行推导。本文第一部分是数据介绍,第二部分为推导过程中需要用的变量的定义,第三部分是GNN的具体推导过程,最后一部分为自己对GNN的一些看法与总结。
前言
本文结合一个具体的无向图来对最简单的一种GNN进行推导。本文第一部分是数据介绍,第二部分为推导过程中需要用的变量的定义,第三部分是GNN的具体推导过程,最后一部分为自己对GNN的一些看法与总结。
1. 数据
利用networkx简单生成一个无向图:
python
复制代码
# -*- coding: utf-8 -*-
"""
@Time : 2021/12/21 11:23
@Author :KI
@File :gnn_basic.py
@Motto:Hungry And Humble
"""
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
G = nx.Graph()
node_features = [[2, 3], [4, 7], [3, 7], [4, 5], [5, 5]]
edges = [(1, 2), (1, 3), (2, 4), (2, 5), (1, 3), (3, 5), (3, 4)]
edge_features = [[1, 3], [4, 1], [1, 5], [5, 3], [5, 6], [5, 4], [4, 3]]
colors = []
edge_colors = []
# add nodes
for i in range(1, len(node_features) + 1):
G.add_node(i, feature=str(i) + ':(' + str(node_features[i-1][0]) + ',' + str(node_features[i-1][1]) + ')')
colors.append('#DCBB8A')
# add edges
for i in range(1, len(edge_features) + 1):
G.add_edge(edges[i-1][0], edges[i-1][1], feature='(' + str(edge_features[i-1][0]) + ',' + str(edge_features[i-1][1]) + ')')
edge_colors.append('#3CA9C4')
# draw
fig, ax = plt.subplots()
pos = nx.spring_layout(G)
nx.draw(G, pos=pos, node_size=2000, node_color=colors, edge_color='black')
node_labels = nx.get_node_attributes(G, 'feature')
nx.draw_networkx_labels(G, pos=pos, labels=node_labels, node_size=2000, node_color=colors, font_color='r', font_size=14)
edge_labels = nx.get_edge_attributes(G, 'feature')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=14, font_color='#7E8877')
ax.set_facecolor('deepskyblue')
ax.axis('off')
fig.set_facecolor('deepskyblue')
plt.show()
如下所示: 其中,每一个节点都有自己的一些特征,比如在社交网络中,每个节点(用户)有性别以及年龄等特征。
5个节点的特征向量依次为:
python
复制代码
[[2, 3], [4, 7], [3, 7], [4, 5], [5, 5]]
同样,6条边的特征向量为:
python
复制代码
[[1, 3], [4, 1], [1, 5], [5, 3], [5, 6], [5, 4], [4, 3]]
2. 变量定义
- 节点特征向量lvl_vlv:节点vvv的特征向量,如l1=(2,3)l_1=(2, 3)l1=(2,3)。
- 节点状态向量xvx_vxv:节点vvv的状态向量。关于节点初始的状态向量,不同的GNN有不同的定义:循环GNN中随机初始化,NN4N中初始时为零向量,而在Gated GNN也就是门控GNN中,初始时的状态向量就为特征向量。最终的状态向量也就是我们学到的节点的高级表示。
- 边特征向量l(v,u)l_{(v, u)}l(v,u),边(v,u)(v, u)(v,u)的特征向量,如l(1,2)=(1,3)l_{(1, 2)}=(1, 3)l(1,2)=(1,3)。
特征向量实际上也就是节点或者边的标签,这个是图本身的属性,一直保持不变。
3. GNN算法
GNN算法的完整描述如下:Forward向前计算状态,Backward向后计算梯度,主函数通过向前和向后迭代调用来最小化损失。
主函数中:
- 首先初始化参数www
- 通过Forward计算出所有节点的收敛的状态向量:x=Forward(w)x=Forward(w)x=Forward(w)
- 通过Backward计算:∂ew∂w=Backward(x,w)\frac{\partial e_w}{\partial w}=Backward(x, w)∂w∂ew=Backward(x,w),利用梯度下降法更新参数www:w=w−λ⋅∂ew∂ww=w-\lambda \cdot \frac{\partial e_w}{\partial w}w=w−λ⋅∂w∂ew,最后利用更新后的参数www重新对所有节点的状态进行更新:x=Forward(w)x=Forward(w)x=Forward(w)。重复以上过程。
- 最后得到的www就是我们的GNN了。
上述描述只是一个总体的概述,可以略过先不看。
3.1 Forward
早期的GNN都是RecGNN,即循环GNN。这种类型的GNN基于信息传播机制: GNN通过不断交换邻域信息来更新节点状态,直到达到稳定均衡。节点的状态向量xxx由以下fwf_wfw函数来进行周期性更新:
解析上述公式:对于节点nnn,假设为节点1,更新其状态需要以下数据参与:
- lnl_nln,节点nnn的特征向量,即:l1=(2,3)l_1=(2, 3)l1=(2,3)。
- lco[n]l_{co[n]}lco[n],与nnn相连的边的特征向量,即[(1, 3), (5, 6)]
- xnenx_{ne[n]}(t)xne[n](t),节点nnn相邻节点(这里为2和3)ttt时刻的状态向量。
- lne[n]l_{ne[n]}lne[n]:节点nnn相邻节点的特征向量,这里为节点2和3的特征向量。
这里的fwf_wfw只是形式化的定义,不同的GNN有不同的定义,如随机稳态嵌入(SSE)中定义如下:
由更新公式可知,当所有节点的状态都趋于稳定状态时,此时所有节点的状态向量都包含了其邻居节点和相连边的信息。
这与图嵌入有些类似:如果是节点嵌入,我们最终得到的是一个节点的向量表示,而这些向量是根据随机游走序列得到的,随机游走序列中又包括了节点的邻居信息, 因此节点的向量表示中包含了连接信息。
证明上述更新过程能够收敛需要用到不动点理论,这里简单描述下:
如果我们有以下更新公式: x(t+1)=Fw(x(t),l)x(t+1)=F_w(x(t), l)x(t+1)=Fw(x(t),l) 只要FwF_wFw是压缩映射,那么最终xxx必会收敛到一个固定的点,这个点称为不动点。是否收敛可用以下公式判断:
∣∣x(t)−x(t−1)∣∣<εf||x(t)-x(t-1)||<\varepsilon_f∣∣x(t)−x(t−1)∣∣<εf
GNN的Foward描述如下:
解释:
- 初始化所有节点的状态向量,此时t=0t=0t=0。
- 然后利用压缩映射FwF_wFw对节点状态向量进行更新:x(t+1)=Fw(x(t),l)x(t+1)=F_w(x(t), l)x(t+1)=Fw(x(t),l),这里的lll包含三种类型信息:节点的特征向量lnl_nln,与节点相连边的特征向量 lco[n]l_{co[n]}lco[n]以及与节点相连节点的特征向量lne[n]l_{ne[n]}lne[n]。
- 如果更新后达到了收敛条件,则停止更新,返回最终时刻所有节点的状态向量。
3.2 Backward
在节点嵌入中,我们最终得到了每个节点的表征向量,此时我们就能利用这些向量来进行聚类、节点分类、链接预测等等。
GNN中类似,得到这些节点状态向量的最终形式不是我们的目的,我们的目的是利用这些节点状态向量来做一些实际的应用,比如节点标签预测。
因此,如果想要预测的话,我们就需要一个输出函数来对节点状态进行变换,得到我们要想要的东西:
最容易想到的就是将节点状态向量经过一个前馈神经网络得到输出,也就是说gwg_wgw可以是一个FNN,同样的,fwf_wfw也可以是一个FNN:
我们利用gwg_wgw函数对节点nnn收敛后的状态向量xnx_nxn以及其特征向量lnl_nln进行变换,就能得到我们想要的输出,比如某一类别,某一具体的数值等等。
在BP算法中,我们有了输出后,就能算出损失,然后利用损失反向传播算出梯度,最后再利用梯度下降法对神经网络的参数进行更新。
对于某一节点的损失(比如回归)我们可以简单定义如下: lossn=(on−tn)2loss_n=(o_n-t_n)^2lossn=(on−tn)2 这里的tnt_ntn是节点的某一标签(比如年龄)。
因此所有节点的损失可以定义为: ew=∑n∈V(on−tn)2e_w=\sum_{n \in V}(o_n-t_n)^2ew=∑n∈V(on−tn)2
因为我们要更新www,所以我们需要得到损失ewe_wew对参数www的导数,即算出: ∂ew∂w\frac{\partial e_w}{\partial w}∂w∂ew
在GNN中,我们定义z(t)z(t)z(t)如下:
有了z(t)z(t)z(t)后,我们就能求导了:
ew=∑n∈V(on−tn)2e_w=\sum_{n \in V}(o_n-t_n)^2ew=∑n∈V(on−tn)2,所以我们可以直接求∂ew∂o\frac{\partial e_w}{\partial o}∂o∂ew。∂Gw∂w(x,lN)\frac{\partial G_w}{\partial w}(x, l_N)∂w∂Gw(x,lN)是输出对www的导数,∂Fw∂w(x,lN)\frac{\partial F_w}{\partial w}(x, l_N)∂w∂Fw(x,lN)是状态转换函数对www的导数,这两个也能直接算出。
z(t)z(t)z(t)的求解方法在Backward中有描述:
- 先对Forward后得到的最终节点状态向量进行转换,得到输出ooo
- 计算状态转换函数对节点状态向量xxx的导数A=∂Fw∂x(x,l)A=\frac{\partial F_w}{\partial x}(x, l)A=∂x∂Fw(x,l)
- 计算b=∂ew∂o⋅∂Gw∂x(x,lN)b=\frac{\partial e_w}{\partial o} \cdot \frac{\partial G_w}{\partial x}(x, l_N)b=∂o∂ew⋅∂x∂Gw(x,lN)
- 初始化z(0)z(0)z(0),此时为0时刻
- 重复计算:z(t)=z(t+1)⋅A+bz(t)=z(t+1) \cdot A + bz(t)=z(t+1)⋅A+b,直至z(t)z(t)z(t)收敛
- 计算c=∂ew∂o⋅∂Gw∂w(x,lN)c=\frac{\partial e_w}{\partial o} \cdot \frac{\partial G_w}{\partial w}(x, l_N)c=∂o∂ew⋅∂w∂Gw(x,lN)
- 计算d=z(t)⋅∂Fw∂w(x,l)d=z(t) \cdot \frac{\partial F_w}{\partial w}(x, l)d=z(t)⋅∂w∂Fw(x,l)
- 最后算出误差对要更新的www的导数∂ew∂w=c+d\frac{\partial e_w}{\partial w}=c+d∂w∂ew=c+d
因此,在Backward中需要计算以下导数:
- 状态转换函数FwF_wFw对节点状态xxx的导数∂Fw∂x\frac{\partial F_w}{\partial x}∂x∂Fw
- 输出函数GwG_wGw对节点状态的导数∂Gw∂x\frac{\partial G_w}{\partial x}∂x∂Gw
- GwG_wGw和FwF_wFw对www的导数
4.总结与展望
本文所讲的GNN是最原始的GNN,此时的GNN存在着不少的问题,比如对不动点隐藏状态的更新比较低效。
由于CNN在CV领域的成功,许多重新定义图形数据卷积概念的方法被提了出来,图卷积神经网络ConvGNN也被提了出来,ConvGNN被分为两大类:频域方法(spectral-based method )和空间域方法(spatial-based method)。2009年,Micheli在继承了来自RecGNN的消息传递思想的同时,在架构上复合非递归层,首次解决了图的相互依赖问题。在过去的几年里还开发了许多替代GNN,包括GAE和STGNN。这些学习框架可以建立在RecGNN、ConvGNN或其他用于图形建模的神经架构上。
GNN是用于图数据的深度学习架构,它将端到端学习与归纳推理相结合,业界普遍认为其有望解决深度学习无法处理的因果推理、可解释性等一系列瓶颈问题,是未来3到5年的重点方向。
因此,不仅仅是GNN,图领域的相关研究都是比较有前景的,这方面的应用也十分广泛,比如推荐系统、计算机视觉、物理/化学(生命科学)、药物发现等等。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
😝有需要的小伙伴,可以Vx扫描下方二维码免费领取==🆓
更多推荐
所有评论(0)