需要数据集和源码请点赞关注收藏后评论区留言~~~
一、数据集简介
我们将使用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次左右收敛。
四、部分源码
主测试类代码如下
-
from __future__
import division
-
from __future__
import print_function
-
import os
-
os.environ[
"KMP_DUPLICATE_LIB_OK"]=
"TRUE"
-
import time
-
import argparse
-
import numpy
as np
-
from torch.utils.data
import DataLoader
-
import torch
-
import torch.nn.functional
as F
-
import torch.optim
as optim
-
-
from utils
import load_data, accuracy
-
from models
import GCN
-
import matplotlib.pyplot
as plt
-
-
# Training settings
-
parser = argparse.ArgumentParser()
-
parser.add_argument(
'--no-cuda', action=
'store_true',
default=False,
-
help=
'Disables CUDA training.')
-
parser.add_argument(
'--fastmode', action=
'store_true',
default=False,
-
help=
'Validate during training pass.')
-
parser.add_argument(
'--seed', type=int,
default=
42, help=
'Random seed.')
-
parser.add_argument(
'--epochs', type=int,
default=
300,
-
help=
'Number of epochs to train.')
-
parser.add_argument(
'--lr', type=float,
default=
0.01,
-
help=
'Initial learning rate.')
-
parser.add_argument(
'--weight_decay', type=float,
default=
5e-4,
-
help=
'Weight decay (L2 loss on parameters).')
-
parser.add_argument(
'--hidden', type=int,
default=
16,
-
help=
'Number of hidden units.')
-
parser.add_argument(
'--dropout', type=float,
default=
0.5,
-
help=
'Dropout rate (1 - keep probability).')
-
-
args = parser.parse_args()
-
args.cuda =
not args.no_cuda
and torch.cuda.is_available()
-
-
.manual_seed(args.seed)
-
-
# Load data
-
adj, features, labels, idx_train, idx_val, idx_test = load_data()
-
-
# Model and optimizer
-
model = GCN(nfeat=features.shape[
1],
-
nhid=args.hidden,
-
nclass=labels.max().item() +
1,
-
dropout=args.dropout)
-
optimizer = optim.Adam(model.parameters(),
-
lr=args.lr, weight_decay=args.weight_decay)
-
-
if args.cuda:
-
model.cuda()
-
features = features.cuda()
-
adj = adj.cuda()
-
labels = labels.cuda()
-
idx_train = idx_train.cuda()
-
idx_val = idx_val.cuda()
-
idx_test = idx_test.cuda()
-
Loss_list = []
-
-
-
accval=[]
-
-
def train(epoch):
-
t=time.time()
-
model.train()
-
optimizer.zero_grad()
-
output=model(features,adj)
-
loss_train=F.nll_loss(output[idx_train],labels[idx_train])
-
acc_train=accuracy(output[idx_train],labels[idx_train])
-
loss_train.backward()
-
optimizer.step()
-
-
if
not args.fastmode:
-
model.
eval()
-
output=model(features,adj)
-
loss_val=F.nll_loss(output[idx_val],labels[idx_val])
-
acc_val=accuracy(output[idx_val],labels[idx_val])
-
print(
'Epoch:{:04d}'.format(epoch+
1),
-
'loss_train:{:.4f}'.format(loss_train.item()),
-
'acc_train:{:.4f}'.format(acc_train.item()),
-
'loss_val:{:.4f}'.format(loss_val.item()),
-
'acc_val:{:.4f}'.format(acc_val.item()),
-
'time:{:.4f}s'.format(time.time()-t))
-
Loss_list.append(loss_train.item())
-
Accuracy_list.append(acc_train.item())
-
lossval.append(loss_val.item())
-
accval.append(acc_val.item())
-
-
-
-
-
-
-
-
-
-
-
-
def test():
-
model.
eval()
-
output = model(features, adj)
-
loss_test = F.nll_loss(output[idx_test], labels[idx_test])
-
acc_test = accuracy(output[idx_test], labels[idx_test])
-
print(
"Test set results:",
-
"loss= {:.4f}".format(loss_test.item()),
-
"accuracy= {:.4f}".format(acc_test.item()))
-
acc=acc_test.detach().numpy()
-
loss=loss_test.detach().numpy()
-
-
print(type(loss_test))
-
print(type(acc_test))
-
-
-
# 定义两个数组
-
-
-
# Train model
-
t_total = time.time()
-
-
for epoch
in range(args.epochs):
-
train(epoch)
-
-
-
-
-
-
print(
"Optimization Finished!")
-
printal time elapsed: {:
.4f}s
".format(time.time() - t_total))
-
'''
-
plt.plot([i for i in range(len(Loss_list))],Loss_list)
-
pplot([i for i in range(len(Accuracy_list))],Accuracy_list)
-
'''
-
plt.plot([i for i in range(len(lossval))],lossval)
-
plot([i for i in range(len(accval))],accval)
-
print(type(Loss_list))
-
print(type(Accuracy_list))
-
#plt.plot([i for i in range(len(Accuracy_list),Accuracy_list)])
-
plt.show()
-
# Testing
-
-
test()
-
-
模型类如下
-
import torch.nn
as nn
-
import torch.nn.functional
as F
-
from layers
import GraphConvolution
-
-
-
class GCN(nn.Module):
-
def __init__(self, nfeat, nhid, nclass, dropout):
-
super(GCN, self).__init__()
-
-
self.gc1 = GraphConvolution(nfeat, nhid)
-
on(nhid, nclass)
-
self.dropout = dropout
-
-
def forward(self, x, adj):
-
x=F.relu(self.gc1(x,adj))
-
x=F.dropout(x,self.dropout,training=self.training)
-
x=self.gc2(x,adj)
-
return F.log_softmax(x,dim=1)
-
layer类如下
-
import math
-
-
import torch
-
-
from torch.nn.parameter
import Parameter
-
from torch.nn.modules.module
import Module
-
-
-
class
GraphConvolution(
Module):
-
"""
-
Simple GCN layer, similar to https://arxiv.org/abs/1609.02907
-
"""
-
-
def
__init__(
self, in_features, out_features, bias=True):
-
super(GraphConvolution, self).__init__()
-
self.in_features=in_features
-
self.out_features=out_features
-
self.weight=Parameter(torch.FloatTensor(in_features,out_features))
-
if bias:
-
self.bias=Parameter(torch.FloatTensor(out_features))
-
else:
-
self.register_parameter(
'bias',
None)
-
self.reset_parameters()
-
-
-
def
reset_parameters(
self):
-
stdv =
1. / math.sqrt(self.weight.size(
1))
-
self.weight.data.uniform_(-stdv, stdv)
-
if self.bias
is
not
None:
-
self.bias.data.uniform_(-stdv, stdv)
-
-
def
forward(
self, input, adj):
-
support=torch.mm(
input,self.weight)
-
output=torch.spmm(adj,support)
-
if self.bias
is
not
None:
-
return output+self.bias
-
else:
-
return output
-
-
def
__repr__(
self):
-
return self.__class__.__name__ +
' (' \
-
+
str(self.in_features) +
' -> ' \
-
+
str(self.out_features) +
')'
util类如下
-
import numpy
as np
-
import scipy.sparse
as sp
-
import torch
-
-
-
def
encode_onehot(
labels):
-
classes =
set(labels)
-
classes_dict = {c: np.identity(
len(classes))[i, :]
for i, c
in
-
enumerate(classes)}
-
labels_onehot = np.array(
list(
map(classes_dict.get, labels)),
-
dtype=np.int32)
-
return labels_onehot
-
-
-
def
load_data(
path="data/cora/", dataset="cora"):
-
"""Load citation network dataset (cora only for now)"""
-
print(
'Loading {} dataset...'.
format(dataset))
-
-
idx_features_labels = np.genfromtxt(
"{}{}.content".
format(path, dataset),
-
dtype=np.dtype(
str))
-
features = sp.csr_matrix(idx_features_labels[:,
1:-
1], dtype=np.float32)
-
labels = encode_onehot(idx_features_labels[:, -
1])
-
-
# build graph
-
idx = np.array(idx_features_labels[:,
0], dtype=np.int32)
-
idx_map = {j: i
for i, j
in
enumerate(idx)}
-
edges_unordered = np.genfromtxt(
"{}{}.cites".
format(path, dataset),
-
dtype=np.int32)
-
edges = np.array(
list(
map(idx_map.get, edges_unordered.flatten())),
-
dtype=np.int32).reshape(edges_unordered.shape)
-
adj = sp.coo_matrix((np.ones(edges.shape[
0]), (edges[:,
0], edges[:,
1])),
-
shape=(labels.shape[
0], labels.shape[
0]),
-
dtype=np.float32)
-
-
# build symmetric adjacency matrix
-
adj = adj + adj.T.multiply(adj.T > adj) - adj.multiply(adj.T > adj)
-
-
features = normalize(features)
-
adj = normalize(adj + sp.eye(adj.shape[
0]))
-
-
idx_train =
range(
140)
-
idx_val =
range(
200,
500)
-
idx_test =
range(
500,
1500)
-
-
features = torch.FloatTensor(np.array(features.todense()))
-
labels = torch.LongTensor(np.where(labels)[
1])
-
adj = sparse_mx_to_torch_sparse_tensor(adj)
-
-
idx_train = torch.LongTensor(idx_train)
-
idx_val = torch.LongTensor(idx_val)
-
idx_test = torch.LongTensor(idx_test)
-
-
return adj, features, labels, idx_train, idx_val, idx_test
-
-
-
def
normalize(
mx):
-
"""Row-normalize sparse matrix"""
-
rowsum = np.array(mx.
sum(
1))
-
r_inv = np.power(rowsum, -
1).flatten()
-
r_inv[np.isinf(r_inv)] =
0.
-
r_mat_inv = sp.diags(r_inv)
-
mx = r_mat_inv.dot(mx)
-
return mx
-
-
-
-
-
de_to_torch_sparse_tensor(sparse_mx):
-
"""Convert a scipy sparse matrix to a torch sparse tensor."""
-
sparse_mx = sparse_mx.tocoo().astype(np.float32)
-
indices = torch.from_numpy(
-
np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64))
-
values = torch.from_numpy(sparse_mx.data)
-
shape = torch.Size(sparse_mx.shape)
-
return torch.sparse.FloatTensor(indices, values, shape)
创作不易 觉得有帮助请点赞关注收藏~~~
转载:https://blog.csdn.net/jiebaoshayebuhui/article/details/127820577