pytorch简单实现GCN

目录

1.引入

 2 环境配置

3 代码分析

4 模型搭建


论文:SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS

前言:学习图卷积刚入门,看了一篇GNN开山之作,而后看了最开始的四代GCN,每一代都在上代上有所更新,大致明白了GCN的发展以及原理,这篇论文是这个系列最后一篇,也是这篇论文中出现了现在GCN的逐层传播公式,后续最新的图网络都是在这个基础上进行更新,个人觉得这四篇论文对图网络感兴趣的朋友入门还是很有帮助的。

这篇文章主要是针对最终得出来的公式进行翻译,简单测试。

1.引入

先通过简单的叙述进入一个公式,

通过之前一些大佬的研究,得出了现在图卷积的思路:

思路一

        将当前节点的特征向量与其一阶节点的特征向量【加和平均】的方式进行聚合来表征当前节点的上下文表征向量

        但时候,这种方法只考虑了当前节点,没有考虑其一阶节点的连接情况,容易造成节点的度越大,参与的节点特征聚合次数越多,而这种度越大的节点本身特殊性应该越弱,影响应该进行削弱

于是,进行改进

思路二

        每个节点的聚合权重除了和自身的连接数相关,也和一阶节点的连接数【度】相关,度越大的节点,说明普遍性越强,重要度反而越低

于是得出了一个公式:

在这里插入图片描述

公式具体意思看下面

 2 环境配置

主要是安装Pytorch Geometric,注意后面看根据自己torch版本下载

pip install --no-index torch-scatter -f https://pytorch-geometric.com/whl/torch-${TORCH}+${CUDA}.html
pip install --no-index torch-sparse -f https://pytorch-geometric.com/whl/torch-${TORCH}+${CUDA}.html
pip install --no-index torch-cluster -f https://pytorch-geometric.com/whl/torch-${TORCH}+${CUDA}.html
pip install --no-index torch-spline-conv -f https://pytorch-geometric.com/whl/torch-${TORCH}+${CUDA}.html
pip install torch-geometric

3 代码分析

先看官方代码:

import torch
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degree

class GCNConv(MessagePassing):
    def __init__(self, in_channels, out_channels):
        super(GCNConv, self).__init__(aggr='add')  # "Add" aggregation (Step 5).
        self.lin = torch.nn.Linear(in_channels, out_channels)

    def forward(self, x, edge_index):
        # x has shape [N, in_channels]
        # edge_index has shape [2, E]

        # Step 1: Add self-loops to the adjacency matrix.
        edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))

        # Step 2: Linearly transform node feature matrix.
        x = self.lin(x)

        # Step 3: Compute normalization.
        row, col = edge_index
        deg = degree(col, x.size(0), dtype=x.dtype)
        deg_inv_sqrt = deg.pow(-0.5)
        norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]

        # Step 4-5: Start propagating messages.
        return self.propagate(edge_index, x=x, norm=norm)

    def message(self, x_j, norm):
        # x_j has shape [E, out_channels]

        # Step 4: Normalize node features.
        return norm.view(-1, 1) * x_j

以及之前的公式:

在这里插入图片描述

 Z:卷积层的输出,X:输入(每个顶点的feature),Θ就是我们要训练的参数,D~是一个对角矩阵,其值为每个节点的度,W~ = A + I(A是邻接矩阵,I是单位矩阵)。

第一步

 # Step 1: Add self-loops to the adjacency matrix.
 edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))

为邻接矩阵添加自环,即W = A + I。

但是edge_index不是邻接矩阵,是表征图中边的向量,先来解释一下这个向量

 如图可以将这个图表示为:

[
[1, 2, 2, 2],
[2, 3, 3, 1]
]

 也就是1-2,2-3。。这样连接,如果加了自环

 [
[1, 2, 2, 2,1,2,3],
[2, 3, 3, 1,1,2,3]
]

 第二步

 # Step 2: Linearly transform node feature matrix.
 x = self.lin(x)

第三步

# Step 3: Compute normalization.
row, col = edge_index
deg = degree(col, x.size(0), dtype=x.dtype)
deg_inv_sqrt = deg.pow(-0.5)
norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]

# Step 4: Normalize node features.
return norm.view(-1, 1) * x_j

 分别为:

  • 获得了row,col,即源节点和目的节点的tensor
  • 根据col来计算度向量
  • 求度向量的-1/2次方
  • 用上一步的结果经过处理后计算norm
  • 求norm*x_j(x_j就是x[col])

 这里很显然不是按照公式一次算W,D,然后算Z,这里用的是一种等价的方式,避免了矩阵相乘,降低了时间复杂度。

可以不用看上面步骤,看下面手算过程,用特例来证明这种方式的正确性:

 

 

 可以看出这两种计算方式是结果一样,并且代码中采用向量的计算方法避免了稀疏矩阵带来的空间浪费和无效计算,从而大大缩短了训练的时间。

 证明的话就是将刚才的例子一般化。

4 模型搭建

模型可以根据自己需求搭建,图卷积层一般来说1-2层就够了,测试了一下

1层ACC:0.66

2层ACC:0.80(√)

3层ACC:0.76

class Net(torch.nn.Module):
    # torch.nn.Module 是所有神经网络单元的基类
    def __init__(self,use_bias=True):
        super(Net, self).__init__()  ###复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        self.use_bias = use_bias
        self.weight = nn.Parameter(torch.Tensor(dataset.num_node_features, dataset.num_classes))
        if self.use_bias:
            self.bias = nn.Parameter(torch.Tensor(dataset.num_classes))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()

        self.conv1 = GCNConv(dataset.num_node_features, 16)
        self.conv2 = GCNConv(16, dataset.num_classes)

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

    def forward(self, data):
        x, edge_index = data.x, data.edge_index

        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index)

        # if self.use_bias:
        #     x += self.bias

        return F.log_softmax(x, dim=1)

没啥可说的,一些参数自己调整可能效果会更好,下面是loss和acc曲线

 

  • 9
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
GCN-DDPG交通是一种基于深度强化学习和图卷积网络的交通流量预测算法,以下是其PyTorch代码实现: 首先,导入所需的库: ```python import torch import torch.nn as nn import torch.nn.functional as F import numpy as np import random from collections import deque import math ``` 然后,定义图卷积网络的类: ```python class GCN(nn.Module): def __init__(self, in_features, hidden_features, out_features): super(GCN, self).__init__() self.fc1 = nn.Linear(in_features, hidden_features) self.fc2 = nn.Linear(hidden_features, out_features) def forward(self, x, adj): x = F.relu(self.fc1(torch.matmul(adj, x))) x = self.fc2(torch.matmul(adj, x)) return x ``` 其中,GCN类包含一个线性层和一个ReLU激活函数,用来实现图卷积运算。 接着,定义深度确定性策略梯度算法(DDPG)的类: ```python class DDPG(object): def __init__(self, state_dim, action_dim, max_action): self.actor = Actor(state_dim, action_dim, max_action).to(device) self.actor_target = Actor(state_dim, action_dim, max_action).to(device) self.actor_target.load_state_dict(self.actor.state_dict()) self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=1e-3) self.critic = Critic(state_dim, action_dim).to(device) self.critic_target = Critic(state_dim, action_dim).to(device) self.critic_target.load_state_dict(self.critic.state_dict()) self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=1e-3) self.max_action = max_action def select_action(self, state): state = torch.FloatTensor(state.reshape(1, -1)).to(device) return self.actor(state).cpu().data.numpy().flatten() def train(self, replay_buffer, iterations, batch_size=100, discount=0.99, tau=0.005): for it in range(iterations): # Sample replay buffer x, y, u, r, d = replay_buffer.sample(batch_size) state = torch.FloatTensor(x).to(device) action = torch.FloatTensor(u).to(device) next_state = torch.FloatTensor(y).to(device) done = torch.FloatTensor(1 - d).to(device) reward = torch.FloatTensor(r).to(device) # Compute the target Q value target_Q = self.critic_target(next_state, self.actor_target(next_state)) target_Q = reward + (done * discount * target_Q).detach() # Compute the current Q value current_Q = self.critic(state, action) # Compute the critic loss critic_loss = F.mse_loss(current_Q, target_Q) # Optimize the critic self.critic_optimizer.zero_grad() critic_loss.backward() self.critic_optimizer.step() # Compute actor loss actor_loss = -self.critic(state, self.actor(state)).mean() # Optimize the actor self.actor_optimizer.zero_grad() actor_loss.backward() self.actor_optimizer.step() # Update the target networks for param, target_param in zip(self.critic.parameters(), self.critic_target.parameters()): target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data) for param, target_param in zip(self.actor.parameters(), self.actor_target.parameters()): target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data) ``` 其中,DDPG类包含一个演员(Actor)和一个评论家(Critic),用来实现深度确定性策略梯度算法。演员网络(Actor)用来预测下一步的交通流量,评论家网络(Critic)用来评估演员网络输出的动作。 最后,定义经验回放缓存器(Experience Replay Buffer)的类: ```python class ReplayBuffer(object): def __init__(self, max_size=1000000): self.buffer = deque(maxlen=max_size) def add(self, state, next_state, action, reward, done): self.buffer.append((state, next_state, action, reward, done)) def sample(self, batch_size): state, next_state, action, reward, done = zip(*random.sample(self.buffer, batch_size)) return np.concatenate(state), np.concatenate(next_state), np.concatenate(action), np.array(reward).reshape(-1, 1), np.array( done).reshape(-1, 1) ``` 其中,ReplayBuffer类用来存储交互数据,以便后续训练使用。 以上就是PyTorch代码实现GCN-DDPG交通流量预测的全部内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值