torch_geometric实现论文《The Emerging Field of Signal Processing on Graphs》中的算法,有问题请求指导(已解决)

最近,尝试使用Pytorch和Pytorch Geometric(PyG),构建图神经网络架构,根据论文《The Emerging Field of Signal Processing on Graphs》中的算法,用PyG重现实验,出现错误及程序源代码如下,请求指导,谢谢!(已解决)

RuntimeError                              Traceback (most recent call last)
<ipython-input-14-14adeb5271eb> in <module>
      2 best_val_acc = test_acc = 0
      3 for epoch in range(1, 201):
----> 4     train()
      5     train_acc, val_acc, tmp_test_acc = test()
      6     if val_acc > best_val_acc:

<ipython-input-12-f9f6ce4bd81a> in train()
      5     optimizer.zero_grad()
      6     # 将误差反向传播
----> 7     F.nll_loss(model()[data.train_mask], data.y[data.train_mask]).backward()
      8     # 更新参数
      9     optimizer.step()

D:\Anaconda3\lib\site-packages\torch\nn\modules\module.py in __call__(self, *input, **kwargs)
    539             result = self._slow_forward(*input, **kwargs)
    540         else:
--> 541             result = self.forward(*input, **kwargs)
    542         for hook in self._forward_hooks.values():
    543             hook_result = hook(self, input, result)

<ipython-input-10-a5f12f83ff5c> in forward(self)
     10         x, edge_index = data.x, data.edge_index
     11 
---> 12         x = self.conv1(x, edge_index)
     13         x = F.relu(x)
     14         x = F.dropout(x, training=self.training)

D:\Anaconda3\lib\site-packages\torch\nn\modules\module.py in __call__(self, *input, **kwargs)
    539             result = self._slow_forward(*input, **kwargs)
    540         else:
--> 541             result = self.forward(*input, **kwargs)
    542         for hook in self._forward_hooks.values():
    543             hook_result = hook(self, input, result)

<ipython-input-9-e745cda6afb6> in forward(self, x, edge_index)
     33 
     34         # Step 3-5: Start propagating messages.
---> 35         return self.propagate(edge_index, size=(x.size(0), x.size(0)), x=x)
     36 
     37     def message(self, x_j, edge_index, size):

D:\Anaconda3\lib\site-packages\torch_geometric\nn\conv\message_passing.py in propagate(self, edge_index, size, dim, **kwargs)
    124         update_args = [kwargs[arg] for arg in self.__update_args__]
    125 
--> 126         out = self.message(*message_args)
    127         out = scatter_(self.aggr, out, edge_index[i], dim, dim_size=size[i])
    128         out = self.update(out, *update_args)

<ipython-input-9-e745cda6afb6> in message(self, x_j, edge_index, size)
     82         #print("norm.shape=",norm.shape)
     83 
---> 84         return norm.view(-1, 1) * x_j
     85 
     86     def update(self, aggr_out):

RuntimeError: expected device cpu but got device cuda:0

 

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

import torch.nn.functional as F
import scipy.sparse as sp

import numpy as np
import scipy.sparse
import networkx as nx
import math

##############################处理数据集#############################
import os
import os.path as osp
from torch_geometric.datasets import Planetoid
import torch_geometric.transforms as T

dataset = 'Cora'
path = osp.join(osp.dirname(osp.realpath('__file__')), 'data', dataset)

##加载数据集
dataset = Planetoid(path, dataset, T.NormalizeFeatures())
data = dataset[0]

##############################定义超参数#############################
#threshold小波基的阈值,小于阈值置为:0
threshold = 1e-4
#小波尺度:s
s=1.0

##############################由邻接W计算正则化的拉普拉斯矩阵#############################
def laplacian(W):
    """Return the Laplacian of the weight matrix."""
    # Degree matrix.
    d = W.sum(axis=0)
    # Laplacian matrix.
    # d += np.spacing(np.array(0, W.dtype))
    d = d.pow(-0.5)
    ##squeeze()去掉一个维度
    D = torch.diag(d, 0)
    I = torch.eye(2708)
    L = I -torch.mm(torch.mm(D,W),D)
    return L

##############################处特征分解#############################
def fourier(L):
    """Return the Fourier basis, i.e. the EVD of the Laplacian."""
    # print "eigen decomposition:"
    #torch.symeig函数:计算特征值和特征向量(eigenvectors = True)
    lamb, U= torch.symeig(L,eigenvectors = True,upper = True)
    return lamb, U
##############################堆叠小波变换基和逆小波变换基#############################
def wavelet_basis(adj,s=1.0,threshold=1e-4):

    ###laplacian来自文件weighting_func.py
    L = laplacian(adj)
    
    #得到特征值和特征向量矩阵
    lamb, U = fourier(L)
    
    #小波变换UG-sUT
    Weight = weight_wavelet(s,lamb,U)
    #小波逆变换UGsUT
    inverse_Weight = weight_wavelet_inverse(s,lamb,U)
    del U,lamb

    #将小变换换和你小波变换基中的值小于阈值的置为:0
    Weight[Weight < threshold] = 0.0
    inverse_Weight[inverse_Weight < threshold] = 0.0
    # print len(np.nonzero(Weight)[0])

    t_k = [inverse_Weight,Weight]
    return t_k####sparse_to_tuple(t_k)

##############################小波变换基#############################
def weight_wavelet(s,lamb,U):
    s = s
    lamb = torch.exp(-lamb*s)
    #UG-sUT
    Weight = torch.mm(torch.mm(U,torch.diag(lamb)),torch.t(U))
    return Weight

##############################小波变换基#############################
def weight_wavelet_inverse(s,lamb,U):
    s = s
    lamb = torch.exp(lamb*s)
    #UGsUT
    Weight = torch.mm(torch.mm(U,torch.diag(lamb)),torch.t(U))
    return Weight

################################定义谱图小波卷积层############################
class WaveletConv(MessagePassing):
    def __init__(self, in_channels, out_channels):
        super(WaveletConv, self).__init__(aggr='add')  # "Add" aggregation.
        self.lin = torch.nn.Linear(in_channels, out_channels)
        #设置可学习参数
        self.kernel = torch.nn.Parameter(torch.Tensor(2708), requires_grad=True)

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

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

        
        ##print("x = self.lin(x)***:",x,x.shape)
        ##2708*1433
        
        # Step 2: Linearly transform node feature matrix.2708*1433
        x = self.lin(x)

        ##2708*16
        ##print("x = self.lin(x):",x,x.shape)
        
        # Step 3-5: Start propagating messages.
        return self.propagate(edge_index, size=(x.size(0), x.size(0)), x=x)

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

        # Step 3: (归一化节点特征)Normalize node features.
        row, col = edge_index
        
        #计算每个结点的度
        #deg = degree(row, size[0], dtype=x_j.dtype)
        #deg_inv_sqrt = deg.pow(-0.5)
        
        #norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]
        
        ###############################################
        
        #修改此部分完成谱图小波网络
        adj =torch.zeros((2708,2708),dtype=torch.float)
        #print(data.edge_index[0].shape)
        #torch.Size([10556])
        adj[edge_index[0],edge_index[1]]=1


        #计算的带小波变换基support[0]和小波逆变换基support[1]
        support = wavelet_basis(adj)
        
        
       
        self.kernel.data = torch.ones(2708,dtype=torch.float)##(np.ones(2708))

        supports = torch.mm(support[0],torch.diag(self.kernel))

        supports = torch.mm(supports,support[1])

        norm = supports[row, col]
        ###############################################

        #norm:中存放了每条边的归一化权重
        ##norm:1*10556 * 10556*out_channels = 1*out_channels
        #其中参数-1表示剩下的值的个数一起构成一个维度。
        #第一个参数1将第一个维度的大小设定成1,
        #后一个-1就是说第二个维度的大小=元素总数目/第一个维度的大小
        #norm将normal变为10556*1列
        
        #print("message:row=",row.shape)
        #print("message:col=",col.shape)
        #print("type(norm)=",type(norm))
        #print("norm.shape=",norm.shape)
        
        return norm.view(-1, 1) * x_j

    def update(self, aggr_out):
        # aggr_out has shape [N=2708, out_channels]

        # Step 5: Return new node embeddings.
        return aggr_out

##############################定义网络模型#############################
class Net(torch.nn.Module):
    #torch.nn.Module 是所有神经网络单元的基类
    def __init__(self):
        super(Net, self).__init__()###复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        self.conv1 = WaveletConv(dataset.num_node_features, 16)
        self.conv2 = WaveletConv(16, dataset.num_classes)

    def forward(self):
        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)

        return F.log_softmax(x, dim=1)

##############################设置GPU 定义优化器#############################
#device = torch.device('cpu')
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model, data = Net().to(device), data.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

##############################定义训练函数#############################
def train():
    model.train()
     # 在反向传播之前,先将梯度归0
    optimizer.zero_grad()
    # 将误差反向传播
    F.nll_loss(model()[data.train_mask], data.y[data.train_mask]).backward()
    # 更新参数
    optimizer.step()

##############################定义测试函数#############################
def test():
    model.eval()
    logits, accs = model(), []
    for _, mask in data('train_mask', 'val_mask', 'test_mask'):
        pred = logits[mask].max(1)[1]
        acc = pred.eq(data.y[mask]).sum().item() / mask.sum().item()
        accs.append(acc)
    return accs

##############################训练并测试函数#############################
best_val_acc = test_acc = 0
for epoch in range(1, 201):
    train()
    train_acc, val_acc, tmp_test_acc = test()
    if val_acc > best_val_acc:
        best_val_acc = val_acc
        test_acc = tmp_test_acc
        
    #打印有哪些参与训练的参数
    #for name, param in model.named_parameters():
        #if param.requires_grad:
            #print(name)
            
    log = 'Epoch: {:03d}, Train: {:.4f}, Val: {:.4f}, Test: {:.4f}'
    print(log.format(epoch, train_acc, best_val_acc, test_acc))

 

补充:程序已正常运行,修改了如下三处,主要原因在于自定义的tensor没有移到GPU上,修改的代码为:

 42行: I = torch.eye(2708).cuda()

163行:adj =torch.zeros((2708,2708),dtype=torch.float).cuda()

147行:self.kernel.data = torch.ones(2708,dtype=torch.float).cuda()

还需要继续修改,训练结果不够理想,和论文中给出的结果还有不一致

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值