Xz's blog Xz's blog
首页
时间序列
多模态
合成生物学
其他方向
生活
工具相关
PyTorch
导航站

Xu Zhen

首页
时间序列
多模态
合成生物学
其他方向
生活
工具相关
PyTorch
导航站
  • 深度学习基础

  • Agent

  • 时序预测

  • 图学习

    • 图学习基础(GCN)
      • 1 图的基础与图表示
        • 1.1 图的基本概念
        • 1.2 实践:创建一个简单图并可视化
      • 2 图数据的编码与特征表示
      • 3 图神经网络核心思想 —— 消息传递(Message Passing)
        • 3.1 直觉理解:
        • 3.2 基本图卷积网络 GCN 层(Kipf & Welling, 2017)
        • 3.3 为什么要这么做?
        • 3.3.1 添加自环
        • 3.3.2 邻接矩阵归一化(防止特征爆炸)
        • 3.4 最后计算:
        • 3.5 举个具体例子
        • 3.6 总结一句话
      • 4 手动实现一个图卷积网络 (GCN) 层(不使用框架)
        • 4.1 多层 GCN:搭建一个两层的 GCN 网络
        • 4.2 测试这个网络
    • 图注意力网络(GAT)
    • GraphSAGE(Graph Sample and Aggregate)
  • 其他

  • 其他方向
  • 图学习
xuzhen
2025-07-14
目录

图学习基础(GCN)

# 1 图的基础与图表示

# 1.1 图的基本概念

我们先理解图的一些基本术语:

  • 图(Graph):由顶点(节点)和边组成,记为 G=(V,E)G = (V, E)G=(V,E)
    • VVV:节点集合(如人、物体)
    • EEE:边集合(如朋友关系、连接)
  • 邻接矩阵(Adjacency Matrix):图中连接关系的矩阵表示
  • 有向图 vs 无向图:边是否有方向
  • 带权图:边是否有权重

# 1.2 实践:创建一个简单图并可视化

我们使用 NetworkX 和 matplotlib 创建一个简单图:

import networkx as nx
import matplotlib.pyplot as plt

# 创建一个无向图
G = nx.Graph()

# 添加节点
G.add_nodes_from([0, 1, 2, 3])

# 添加边(无向)
G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0)])

# 可视化图
nx.draw(G, with_labels=True, node_color='lightblue', edge_color='gray')
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2 图数据的编码与特征表示

图神经网络的输入通常包括:

  • 节点特征矩阵 X∈RN×FX \in \mathbb{R}^{N \times F}X∈RN×F,每个节点一个 F 维向量
  • 邻接矩阵 A∈{0,1}N×NA \in \{0, 1\}^{N \times N}A∈{0,1}N×N,表示边的连接情况

我们可以构造一个小图并定义这些结构:

import torch

# 节点特征:4个节点,每个2维特征
X = torch.tensor([
    [1.0, 0.0],  # 节点 0
    [0.0, 1.0],  # 节点 1
    [1.0, 1.0],  # 节点 2
    [0.0, 0.0],  # 节点 3
])

# 邻接矩阵(无向图)
A = torch.tensor([
    [0, 1, 0, 1],  # 节点 0
    [1, 0, 1, 0],  # 节点 1
    [0, 1, 0, 1],  # 节点 2
    [1, 0, 1, 0],  # 节点 3
], dtype=torch.float32)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3 图神经网络核心思想 —— 消息传递(Message Passing)

在图神经网络中,每个节点会从邻居节点收集信息,并更新自身的特征表示。

# 3.1 直觉理解:

  • 类似社交网络:你认识的人会影响你的“状态”。
  • 每一轮传播后,节点会融合自己和邻居的信息,变得更“智能”。

# 3.2 基本图卷积网络 GCN 层(Kipf & Welling, 2017)

数学公式如下:

H(l+1)=σ(D^−1/2A^D^−1/2H(l)W(l))H^{(l+1)} = \sigma(\hat{D}^{-1/2} \hat{A} \hat{D}^{-1/2} H^{(l)} W^{(l)}) H(l+1)=σ(D^−1/2A^D^−1/2H(l)W(l))

符号 含义
AAA 原始邻接矩阵(表示图的连接结构)
III 单位矩阵(用于添加自环)
A^=A+I\hat{A} = A + IA^=A+I 添加自环后的邻接矩阵
D^\hat{D}D^ A^\hat{A}A^ 的度矩阵(对角矩阵)
H(l)H^{(l)}H(l) 第 lll 层的节点特征矩阵,初始为输入特征 XXX
W(l)W^{(l)}W(l) 第 lll 层的可学习参数(权重矩阵)
σ\sigmaσ 非线性激活函数(如 ReLU)

# 3.3 为什么要这么做?

图神经网络的目标是:让每个节点聚合邻居的信息,更新自己的表示。

但原始邻接矩阵 AAA 有两个问题:

  1. 没有自环(self-loop):节点无法“看到”自己
  2. 不同节点度数不同:信息量不均衡,容易失衡(例如有些节点有100个邻居,有些只有1个)

所以我们做了两件事:

# 3.3.1 添加自环

A^=A+I\hat{A} = A + I A^=A+I

这表示“每个节点也连接自己”——它就能保留自己的特征了。

# 3.3.2 邻接矩阵归一化(防止特征爆炸)

D^−1/2A^D^−1/2\hat{D}^{-1/2} \hat{A} \hat{D}^{-1/2} D^−1/2A^D^−1/2

  • D^\hat{D}D^ 是 A^\hat{A}A^ 的度矩阵。每个对角线是一个节点的度数。
  • 归一化是为了避免度高的节点把信息“冲淡”或“放大”太多。

这一步就像在图中做了一个“特征平滑”,让高连接节点和低连接节点影响差不多。

# 3.4 最后计算:

H(l+1)=σ(归一化邻接矩阵×H(l)×W(l))H^{(l+1)} = \sigma(\text{归一化邻接矩阵} \times H^{(l)} \times W^{(l)}) H(l+1)=σ(归一化邻接矩阵×H(l)×W(l))

翻译成人话:

👉 “对每个节点,我们把它邻居的特征聚合(平均),再乘一个可学习权重,再过激活函数,得到更新后的特征。”

# 3.5 举个具体例子

假设我们有一个 4 个节点的小图,初始特征是:

H0 = X = [
    [1.0, 0.0],  # 节点 0
    [0.0, 1.0],  # 节点 1
    [1.0, 1.0],  # 节点 2
    [0.0, 0.0],  # 节点 3
]
1
2
3
4
5
6

邻接矩阵(+ 自环):

A_hat = [
    [1, 1, 0, 1],  # 节点 0 连接自己、1、3
    [1, 1, 1, 0],  # 节点 1 连接自己、0、2
    [0, 1, 1, 1],  # 节点 2 连接自己、1、3
    [1, 0, 1, 1],  # 节点 3 连接自己、0、2
]
1
2
3
4
5
6

归一化后:

A^norm=D^−1/2A^D^−1/2\hat{A}_{norm} = \hat{D}^{-1/2} \hat{A} \hat{D}^{-1/2} A^norm​=D^−1/2A^D^−1/2

这个矩阵就是你可以用来聚合邻居特征的“图卷积核”。

# 3.6 总结一句话

GCN 就是:

对每个节点,把邻居的特征平均后,加权映射(W),再过激活函数。

这种“卷积”不是图像上滑动的 kernel,而是结构上的“邻居平均 + 特征变换”。

如果你想,我可以用具体数字例子走一遍这个公式的完整计算过程(比如 2 个节点、每个特征是 2 维)。你想让我这样做吗?

# 4 手动实现一个图卷积网络 (GCN) 层(不使用框架)

我们用 PyTorch 实现这一层:

import torch
import torch.nn as nn
import torch.nn.functional as F

class GCNLayer(nn.Module):
    def __init__(self, in_features, out_features):
        super(GCNLayer, self).__init__()
        self.linear = nn.Linear(in_features, out_features)

    def forward(self, X, A):
        # A: 邻接矩阵,X: 节点特征

        # 加自环:A + I
        I = torch.eye(A.size(0)).to(A.device)
        A_hat = A + I

        # 计算度矩阵 D
        D_hat = torch.diag(torch.sum(A_hat, dim=1))

        # 计算归一化邻接矩阵 D^{-1/2} A_hat D^{-1/2}
        D_inv_sqrt = torch.inverse(torch.sqrt(D_hat))
        A_norm = D_inv_sqrt @ A_hat @ D_inv_sqrt

        # 图卷积
        out = A_norm @ X
        out = self.linear(out)
        return F.relu(out)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 4.1 多层 GCN:搭建一个两层的 GCN 网络

class GCN(nn.Module):
    def __init__(self, in_features, hidden_dim, out_features):
        super(GCN, self).__init__()
        self.gcn1 = GCNLayer(in_features, hidden_dim)
        self.gcn2 = GCNLayer(hidden_dim, out_features)

    def forward(self, X, A):
        x = self.gcn1(X, A)
        x = self.gcn2(x, A)
        return x
1
2
3
4
5
6
7
8
9
10

# 4.2 测试这个网络

我们继续使用前面的小图:

# 节点特征(4个节点,2维)
X = torch.tensor([
    [1.0, 0.0],
    [0.0, 1.0],
    [1.0, 1.0],
    [0.0, 0.0],
])

# 邻接矩阵
A = torch.tensor([
    [0, 1, 0, 1],
    [1, 0, 1, 0],
    [0, 1, 0, 1],
    [1, 0, 1, 0],
], dtype=torch.float32)

# 初始化模型
model = GCN(in_features=2, hidden_dim=4, out_features=2)
output = model(X, A)

print("输出节点表示:")
print(output)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

输出是每个节点新的 2 维向量表示(可以用于分类、聚类等任务)。

#Graph
上次更新: 2025/07/14, 21:11:30

← iTransformer 图注意力网络(GAT)→

最近更新
01
Linux 通过Windows代理上网
09-18
02
vscode远程使用copilot和codex(内网环境)
09-18
03
跨机器克隆环境
09-18
更多文章>
Theme by Vdoing | Copyright © 2025-2025 Xu Zhen | 鲁ICP备2025169719号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式