小言_互联网的博客

PyTorch搭建图卷积神经网络(GCN)完成对论文分类及预测实战(附源码和数据集)

376人阅读  评论(0)

需要数据集和源码请点赞关注收藏后评论区留言~~~

一、数据集简介

我们将使用Cora数据集。

该数据集共2708个样本点,每个样本点都是一篇科学论文,所有样本点被分为7个类别,类别分别是1)基于案例;2)遗传算法;3)神经网络;4)概率方法;5)强化学习;6)规则学习;7)理论

每篇论文都由一个1433维的词向量表示,所以,每个样本点具有1433个特征。词向量的每个元素都对应一个词,且该元素只有0或1两种取值。取0表示该元素对应的词不在论文中,取1表示在论文中。所有的词来源于一个具有1433个词的字典。

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

数据集主要文件有两个:cora.cites, cora.content。其中,cora.content包含了2708个样本的具体信息,每行代表一个论文样本,格式为

<论文id>  <由01组成的1433维特征>  <论文类别(label)>

总的来说,如果将论文当作“图”的节点,则引用关系则为“图”的边,论文节点信息和引用关系共同构成了图数据。本次实验,我们将利用这些信息,对论文所属的类别进行预测,完成关于论文类别的分类任务。

二、图神经网络与图卷积神经网络简介

 图神经网络(Graph Neural Networks, GNN)作为新的人工智能学习模型,可以将实际问题看作图数据中节点之间的连接和消息传播问题,对节点之间的依赖关系进行建模,挖掘传统神经网络无法分析的非欧几里得空间数据的潜在信息。在自然语言处理、计算机视觉、生物化学等领域中,图神经网络得到广泛的应用,并发挥着重要作用。

图卷积神经网络(Graph Convolutional Networks, GCN)是目前主流的图神经网络分支,分类任务则是机器学习中的常见任务。我们将利用GCN算法完成分类任务,进一步体会理解图神经网络工作的原理、GCN的构建实现过程,以及如何将GCN应用于分类任务。

三、运行效果

如下图 可见随着训练次数的增加,损失率在下降,精确度在上升,大概在200次左右收敛。

 

 

 

 四、部分源码

主测试类代码如下


  
  1. from __future__ import division
  2. from __future__ import print_function
  3. import os
  4. os.environ[ "KMP_DUPLICATE_LIB_OK"]= "TRUE"
  5. import time
  6. import argparse
  7. import numpy as np
  8. from torch.utils.data import DataLoader
  9. import torch
  10. import torch.nn.functional as F
  11. import torch.optim as optim
  12. from utils import load_data, accuracy
  13. from models import GCN
  14. import matplotlib.pyplot as plt
  15. # Training settings
  16. parser = argparse.ArgumentParser()
  17. parser.add_argument( '--no-cuda', action= 'store_true', default=False,
  18. help= 'Disables CUDA training.')
  19. parser.add_argument( '--fastmode', action= 'store_true', default=False,
  20. help= 'Validate during training pass.')
  21. parser.add_argument( '--seed', type=int, default= 42, help= 'Random seed.')
  22. parser.add_argument( '--epochs', type=int, default= 300,
  23. help= 'Number of epochs to train.')
  24. parser.add_argument( '--lr', type=float, default= 0.01,
  25. help= 'Initial learning rate.')
  26. parser.add_argument( '--weight_decay', type=float, default= 5e-4,
  27. help= 'Weight decay (L2 loss on parameters).')
  28. parser.add_argument( '--hidden', type=int, default= 16,
  29. help= 'Number of hidden units.')
  30. parser.add_argument( '--dropout', type=float, default= 0.5,
  31. help= 'Dropout rate (1 - keep probability).')
  32. args = parser.parse_args()
  33. args.cuda = not args.no_cuda and torch.cuda.is_available()
  34. .manual_seed(args.seed)
  35. # Load data
  36. adj, features, labels, idx_train, idx_val, idx_test = load_data()
  37. # Model and optimizer
  38. model = GCN(nfeat=features.shape[ 1],
  39. nhid=args.hidden,
  40. nclass=labels.max().item() + 1,
  41. dropout=args.dropout)
  42. optimizer = optim.Adam(model.parameters(),
  43. lr=args.lr, weight_decay=args.weight_decay)
  44. if args.cuda:
  45. model.cuda()
  46. features = features.cuda()
  47. adj = adj.cuda()
  48. labels = labels.cuda()
  49. idx_train = idx_train.cuda()
  50. idx_val = idx_val.cuda()
  51. idx_test = idx_test.cuda()
  52. Loss_list = []
  53. accval=[]
  54. def train(epoch):
  55. t=time.time()
  56. model.train()
  57. optimizer.zero_grad()
  58. output=model(features,adj)
  59. loss_train=F.nll_loss(output[idx_train],labels[idx_train])
  60. acc_train=accuracy(output[idx_train],labels[idx_train])
  61. loss_train.backward()
  62. optimizer.step()
  63. if not args.fastmode:
  64. model. eval()
  65. output=model(features,adj)
  66. loss_val=F.nll_loss(output[idx_val],labels[idx_val])
  67. acc_val=accuracy(output[idx_val],labels[idx_val])
  68. print( 'Epoch:{:04d}'.format(epoch+ 1),
  69. 'loss_train:{:.4f}'.format(loss_train.item()),
  70. 'acc_train:{:.4f}'.format(acc_train.item()),
  71. 'loss_val:{:.4f}'.format(loss_val.item()),
  72. 'acc_val:{:.4f}'.format(acc_val.item()),
  73. 'time:{:.4f}s'.format(time.time()-t))
  74. Loss_list.append(loss_train.item())
  75. Accuracy_list.append(acc_train.item())
  76. lossval.append(loss_val.item())
  77. accval.append(acc_val.item())
  78. def test():
  79. model. eval()
  80. output = model(features, adj)
  81. loss_test = F.nll_loss(output[idx_test], labels[idx_test])
  82. acc_test = accuracy(output[idx_test], labels[idx_test])
  83. print( "Test set results:",
  84. "loss= {:.4f}".format(loss_test.item()),
  85. "accuracy= {:.4f}".format(acc_test.item()))
  86. acc=acc_test.detach().numpy()
  87. loss=loss_test.detach().numpy()
  88. print(type(loss_test))
  89. print(type(acc_test))
  90. # 定义两个数组
  91. # Train model
  92. t_total = time.time()
  93. for epoch in range(args.epochs):
  94. train(epoch)
  95. print( "Optimization Finished!")
  96. printal time elapsed: {: .4f}s ".format(time.time() - t_total))
  97. '''
  98. plt.plot([i for i in range(len(Loss_list))],Loss_list)
  99. pplot([i for i in range(len(Accuracy_list))],Accuracy_list)
  100. '''
  101. plt.plot([i for i in range(len(lossval))],lossval)
  102. plot([i for i in range(len(accval))],accval)
  103. print(type(Loss_list))
  104. print(type(Accuracy_list))
  105. #plt.plot([i for i in range(len(Accuracy_list),Accuracy_list)])
  106. plt.show()
  107. # Testing
  108. test()

模型类如下


  
  1. import torch.nn as nn
  2. import torch.nn.functional as F
  3. from layers import GraphConvolution
  4. class GCN(nn.Module):
  5. def __init__(self, nfeat, nhid, nclass, dropout):
  6. super(GCN, self).__init__()
  7. self.gc1 = GraphConvolution(nfeat, nhid)
  8. on(nhid, nclass)
  9. self.dropout = dropout
  10. def forward(self, x, adj):
  11. x=F.relu(self.gc1(x,adj))
  12. x=F.dropout(x,self.dropout,training=self.training)
  13. x=self.gc2(x,adj)
  14. return F.log_softmax(x,dim=1)

layer类如下


  
  1. import math
  2. import torch
  3. from torch.nn.parameter import Parameter
  4. from torch.nn.modules.module import Module
  5. class GraphConvolution( Module):
  6. """
  7. Simple GCN layer, similar to https://arxiv.org/abs/1609.02907
  8. """
  9. def __init__( self, in_features, out_features, bias=True):
  10. super(GraphConvolution, self).__init__()
  11. self.in_features=in_features
  12. self.out_features=out_features
  13. self.weight=Parameter(torch.FloatTensor(in_features,out_features))
  14. if bias:
  15. self.bias=Parameter(torch.FloatTensor(out_features))
  16. else:
  17. self.register_parameter( 'bias', None)
  18. self.reset_parameters()
  19. def reset_parameters( self):
  20. stdv = 1. / math.sqrt(self.weight.size( 1))
  21. self.weight.data.uniform_(-stdv, stdv)
  22. if self.bias is not None:
  23. self.bias.data.uniform_(-stdv, stdv)
  24. def forward( self, input, adj):
  25. support=torch.mm( input,self.weight)
  26. output=torch.spmm(adj,support)
  27. if self.bias is not None:
  28. return output+self.bias
  29. else:
  30. return output
  31. def __repr__( self):
  32. return self.__class__.__name__ + ' (' \
  33. + str(self.in_features) + ' -> ' \
  34. + str(self.out_features) + ')'

util类如下


  
  1. import numpy as np
  2. import scipy.sparse as sp
  3. import torch
  4. def encode_onehot( labels):
  5. classes = set(labels)
  6. classes_dict = {c: np.identity( len(classes))[i, :] for i, c in
  7. enumerate(classes)}
  8. labels_onehot = np.array( list( map(classes_dict.get, labels)),
  9. dtype=np.int32)
  10. return labels_onehot
  11. def load_data( path="data/cora/", dataset="cora"):
  12. """Load citation network dataset (cora only for now)"""
  13. print( 'Loading {} dataset...'. format(dataset))
  14. idx_features_labels = np.genfromtxt( "{}{}.content". format(path, dataset),
  15. dtype=np.dtype( str))
  16. features = sp.csr_matrix(idx_features_labels[:, 1:- 1], dtype=np.float32)
  17. labels = encode_onehot(idx_features_labels[:, - 1])
  18. # build graph
  19. idx = np.array(idx_features_labels[:, 0], dtype=np.int32)
  20. idx_map = {j: i for i, j in enumerate(idx)}
  21. edges_unordered = np.genfromtxt( "{}{}.cites". format(path, dataset),
  22. dtype=np.int32)
  23. edges = np.array( list( map(idx_map.get, edges_unordered.flatten())),
  24. dtype=np.int32).reshape(edges_unordered.shape)
  25. adj = sp.coo_matrix((np.ones(edges.shape[ 0]), (edges[:, 0], edges[:, 1])),
  26. shape=(labels.shape[ 0], labels.shape[ 0]),
  27. dtype=np.float32)
  28. # build symmetric adjacency matrix
  29. adj = adj + adj.T.multiply(adj.T > adj) - adj.multiply(adj.T > adj)
  30. features = normalize(features)
  31. adj = normalize(adj + sp.eye(adj.shape[ 0]))
  32. idx_train = range( 140)
  33. idx_val = range( 200, 500)
  34. idx_test = range( 500, 1500)
  35. features = torch.FloatTensor(np.array(features.todense()))
  36. labels = torch.LongTensor(np.where(labels)[ 1])
  37. adj = sparse_mx_to_torch_sparse_tensor(adj)
  38. idx_train = torch.LongTensor(idx_train)
  39. idx_val = torch.LongTensor(idx_val)
  40. idx_test = torch.LongTensor(idx_test)
  41. return adj, features, labels, idx_train, idx_val, idx_test
  42. def normalize( mx):
  43. """Row-normalize sparse matrix"""
  44. rowsum = np.array(mx. sum( 1))
  45. r_inv = np.power(rowsum, - 1).flatten()
  46. r_inv[np.isinf(r_inv)] = 0.
  47. r_mat_inv = sp.diags(r_inv)
  48. mx = r_mat_inv.dot(mx)
  49. return mx
  50. de_to_torch_sparse_tensor(sparse_mx):
  51. """Convert a scipy sparse matrix to a torch sparse tensor."""
  52. sparse_mx = sparse_mx.tocoo().astype(np.float32)
  53. indices = torch.from_numpy(
  54. np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64))
  55. values = torch.from_numpy(sparse_mx.data)
  56. shape = torch.Size(sparse_mx.shape)
  57. return torch.sparse.FloatTensor(indices, values, shape)

创作不易 觉得有帮助请点赞关注收藏~~~


转载:https://blog.csdn.net/jiebaoshayebuhui/article/details/127820577
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场