【深度网络】GCN

目录

一.背景

二.原理

三.应用实例

1.Cora数据集

2.GCN分类代码

一.背景

CNN通过卷积conv来对某个空间区域的像素点进行加权求和,得到新的特征表示。 加权系数就是卷积核的参数,如下图所示。

CNN适用于规则2维矩阵数据 (每个像素点有上下左右相连)或1维序列数据(如语音,每个点左右相连) 来提取特征。CNN无法处理非欧几里得结构的数据, 因为传统的卷积没法处理节点关系多变的信息(没法固定尺寸进行设置卷积核)。

对于并不具备规则的空间结构,如社交网络、脑信号、分子结构等,可以利用图图卷积神经网络(GCN)提取图的特征信息与结构信息。

二.原理

图数据具有节点特征(每个节点都具有自己的向量表示)和结构特征(节点与节点间具有一定的联系, 即携带信息的边)。

GCN的核心思想是聚合来自节点局部邻域的特征和节点特征更新。GCN主要分为2类,1)基于顶点域或空间域 vertex domain(spatial domain);2)基于频域或谱域(spectral domain) 。顶点域可以类比到直接在图片的像素点上进行卷积,而频域可以类比到对图片进行傅里叶变换后,再进行卷积。在此,只讨论空间域GCN。

GCN的步骤主要为:

1. 初始化:为每个节点分配初始特征表示。

2. 邻居聚合:对于每个节点,将其自身特征与邻居节点的特征进行加权平均或拼接,得到聚合后的特征。
3. 特征转换:对聚合后的特征进行线性变换,以充分利用特征之间的关系。
4. 非线性激活:应用非线性激活函数,如ReLU,将线性变换后的特征映射到非线性空间。
5.循环迭代:重复进行邻居聚合、特征转换和非线性激活的步骤,直到达到所需的网络层数或收敛条件。

具体地,GCN第l+1层的特征矩阵具体计算方式如下:

其中,H是隐藏层的特征,σ是非线性激活函数,\tilde{A}=A+I是邻接矩阵与单位矩阵的和。

D是度矩阵,其中对角线元素代表节点的度。

W是权重矩阵。

三.应用实例

使用Pytorch提供的GCN网络对Cora数据集进行分类。

1.Cora数据集

数据集共2708个样本,每个样本都是1篇科学论文,论文分为以下7类之一。

  • 基于案例
  • 遗传算法
  • 神经网络
  • 概率方法
  • 强化学习
  • 规则学习
  • 理论

每篇论文都由1个1433维的词向量表示,词向量的每个元素都对应1个词,只有0(不在论文中),1(在论文中)2个取值。

每篇论文都至少引用1篇其他论文,或者被其他论文引用,没有任何1个样本与其他样板完全没联系。如果将样本看作图中的点,则是1个连通图,不存在孤立点。

(1)文件格式

cora.content是所有论文的独自的信息;cora.cites是论文之间的引用记录。

cora.content共有2708行,每行即1篇论文,由3部分组成,分别是论文编号、论文词向量、论文的类别。

cora.cites共5429行,每1行有2个论文编号,表示第1个编号的论文先写,第2个编号的论文引用第1个编号的论文。

如果将论文看作图中的节点,那么5429行便是节点之间的5429条边。

2.GCN分类代码

import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
from torch_geometric.datasets import Planetoid
from torch_geometric.transforms import NormalizeFeatures

# 加载并预处理Cora数据集
# dataset = Planetoid(root='data/planetoid', name='Cora', transform=NormalizeFeatures())
dataset = Planetoid(root='', name='Cora', transform=NormalizeFeatures())

class GCN(torch.nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(GCN, self).__init__()
        self.conv1 = GCNConv(input_dim, hidden_dim)
        self.conv2 = GCNConv(hidden_dim, output_dim)

    def forward(self, x, edge_index):
        print(f"first {x.shape}")
        x = self.conv1(x, edge_index)
        print(f"conv1 {x.shape}")
        x = F.relu(x)
        x = self.conv2(x, edge_index)
        print(f"conv2 {x.shape}")
        print(f"x[0] {x[0]}")
        print(f"max x[0] {max(x[0])}")
        return F.log_softmax(x, dim=1)

# 数据集信息
data = dataset[0]
# print(f"data shape {len(data)}")
input_dim = dataset.num_node_features
hidden_dim = 16
output_dim = dataset.num_classes
print(input_dim, output_dim)

# 初始化模型
model = GCN(input_dim, hidden_dim, output_dim)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

# 训练模型
model.train()
for epoch in range(100):
    optimizer.zero_grad()
    out = model(data.x, data.edge_index)
    loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
    loss.backward()
    optimizer.step()
    if epoch % 10 == 0:
        print(f'Epoch {epoch}, Loss: {loss.item()}')

# 测试模型
model.eval()
_, pred = model(data.x, data.edge_index).max(dim=1)
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum()
accuracy = int(correct) / int(data.test_mask.sum())
print(f'Accuracy: {accuracy:.4f}')

(1) 数据集加载

Planetoid数据会因为网络问题无法直接下载,一直报错。可以通过Cora,将下载好的数据

放到根目录下Cora/raw文件夹下,然后再运行代码。

(2) Planetoid中Cora数据集边数量不一致问题

cora.cites中显示有5429条边有 但Planetoid中的Cora边数量5278原因在于cora.cites中存在重复边,详细信息如下

'''data check'''
def data_check(cites_file):

    # 读取引用关系数据
    with open(cites_file, 'r') as f:
        cites_lines = f.readlines()

    edge_count = {}
    self_loops = 0

    # 解析边数据并统计出现次数
    for line in cites_lines:
        parts = line.strip().split()
        cited = parts[0]
        citing = parts[1]

        # 检查自环
        if cited == citing:
            self_loops += 1

        # 创建无向边的标准形式 (sorted tuple)
        edge = tuple(sorted((cited, citing)))

        if edge in edge_count:
            edge_count[edge] += 1
        else:
            edge_count[edge] = 1

    # 查找并打印重复边
    repeated_edges = {edge: count for edge, count in edge_count.items() if count > 1}

    print(f'Total edges (directed): {len(cites_lines)}')
    print(f'Unique edges (undirected): {len(edge_count)}')
    print(f'Self-loops: {self_loops}')
    print(f'Number of repeated edges: {len(repeated_edges)}')

    # 打印重复边及其出现次数
    print('Repeated edges:')
    top_info=list(repeated_edges.items())[:10]
    for edge, count in top_info:
        print(f'Edge {edge} appears {count} times')
cites_file='Cora/cora_origin/cora.cites'
data_check(cites_file)

'''data check'''

cora.cites中5429-5278=151条存在重复边。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值