小批量样本训练的GCN

import torch.nn as nn
import torch
import torch.nn.init as init
import scipy.sparse as sp
import numpy as np
import torch.nn.functional as F
import torch.optim as optim
from random import shuffle

class GraphConvolutionLayerWithAttention(nn.Module):
    '''定义一个图卷积层'''
    def __init__(self, nodes_num, input_dim, output_dim, use_bias = True):
        '''
        节点输入特征维度
        :param input_dim: int
        输出特征维度
        :param output_dim: int
        是否使用偏置项
        :param use_bias: bool, optional
        '''
        # 构造函数
        # 按照框架继承了nn.Module类,就必须首先调用父类的构造函数
        super(GraphConvolutionLayerWithAttention, self).__init__()
        # 声明网络结构和参数
        self.input = input_dim
        self.labels = output_dim
        self.use_bias = use_bias
        self.weight = nn.Parameter(torch.Tensor(input_dim, output_dim))
        self.attention = nn.Parameter(torch.Tensor(nodes_num, nodes_num))

        if self.use_bias:
            self.bias = nn.Parameter(torch.Tensor(output_dim))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()

    def reset_parameters(self):
        # 正态分布初始化
        init.kaiming_uniform_(self.weight)
        init.kaiming_uniform_(self.attention)
        if self.use_bias:
            # 零值初始化
            init.zeros_(self.bias)

    def forward(self, adjacency, input_feature):
        '''
        邻接矩阵
        邻接矩阵是稀疏矩阵,因此在计算时使用稀疏矩阵乘法。
        :param adjacency: torch.sparse.FloatTensor
        输入特征
        :param input_feature: torch.Tensor
        :return:
        '''
        # 前向传播
        # 矩阵乘法用torch.mm哈达玛积用torch.mul或*
        support = torch.mm(input_feature, self.weight)
        output = torch.mm(self.attention * adjacency, support)
        #output = torch.sparse.mm(adjacency, support)
        if self.use_bias:
            output += self.bias
        return output



class GCN_ATT(nn.Module):
    def __init__(self, BatchNodesNum, dims, neighbor_k):
        super(GCN_ATT, self).__init__()
        self.BatchNodesNum = BatchNodesNum
        self.gcns = []
        assert len(dims)-1 >= neighbor_k
        for i in range(len(dims)-1):
            gcn = GraphConvolutionLayerWithAttention(BatchNodesNum, dims[i], dims[i+1])
            self.gcns.append(gcn)
        
        self.neighbor_k = neighbor_k

    def forward(self, adjacency, feature):
        h = feature
        for i in range(len(dims)-1):
            h = F.relu(self.gcns[i](adjacency, h))
        return h[0] #以第一行作为本次Batch的中心目标node

def LoadByIndices(url, Indices):
    # 逐个按照idx加载数据文件,存入BatchSamples并返回。
    BatchSamples = []
    for idx in Indices:
        file = url + str(idx) + '.npy'
        BatchSamples.append(np.load(file))
    return BatchSamples

def normalization(adjacency):
    '''计算 L = A+I'''
    # 构造单位阵
    adjacency += sp.eye(adjacency.shape[0])
    # tocoo将矩阵转化为scipy.coo_matrix稀疏矩阵
    return adjacency.tocoo()

# 邻域采样阶数
neighbor_k = 2

# 输入点属性的维度
input_dim = 25

# 模型各层的维度
dims = [input_dim, 16, 2]

# 采样得到的点的总数
BatchNodeNum = 100

# 超参数定义
learning_rate = 0.1
weight_decay = 5e-4
epochs = 200
# 模型定义,包括模型实例化、损失函数与优化器定义
device = "cuda" if torch.cuda.is_available() else "cpu"
model = GCN_ATT(BatchNodeNum, dims, neighbor_k).to(device)
# 损失函数使用交叉熵
criterion = nn.CrossEntropyLoss().to(device)
# 优化器使用Adam
optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=weight_decay)



# 加载数据,并转换为torch.Tensor
#dataset = CoraData().data

# 样本总数
AllSampleNum = 20000
train_per = 0.3
train_sample_num = int(AllSampleNum*train_per)
indices = np.random.permutation(AllSampleNum)
train_indices = indices[:train_sample_num]
test_indeces = indices[train_sample_num:]

# 样本加载地址
samples_url = 'D:\\Samples\\Sample'
adjacencys_url = 'D:\\Adjacencys\\Adjacencys'
y_url = 'D:\\y\\y'

def train():
    loss_history = []
    val_acc_history = []
    train_y = LoadByIndices(y_url, train_indices)
    test_y = LoadByIndices(y_url, test_indeces)
    for epoch in range(epochs):
        # 每个epoch开始时,对样本索引进行重新打散
        shuffle(train_indices)

        for idx in train_indices:
            tensor_x = torch.from_numpy(LoadByIndices(samples_url, idx)[0])
            tensor_adjacency = torch.from_numpy(LoadByIndices(adjacencys_url, idx)[0])
            normal_adjacency = normalization(tensor_adjacency)
            logits = model(normal_adjacency, tensor_x)# 前向传播
            loss = criterion(logits, train_y[idx])
            # 梯度归零
            optimizer.zero_grad()
            # 反向传播计算梯度
            loss.backward()
            # 更新参数
            optimizer.step()

        train_acc = test(train_indices, train_y) # 计算当前模型在训练集上的准确率
        val_acc = test(test_indeces, test_y) # 计算当前模型在验证集上的准确率
        # 记录训练过程中的损失值和准确率变化,用于画图
        loss_history.append(loss.item())
        val_acc_history.append(val_acc.item())
        print('Epoch {:03d}: Loss{:.4f}, TrainAcc{:.4}, ValAcc{:.4f}'.format(epoch, loss.item(), train_acc.item(), val_acc.item()))
    return loss_history, val_acc_history

def test(indices_now, y):
    model.eval()
    acc = []
    with torch.no_grad():
        for idx in indices_now:
            tensor_x = torch.from_numpy(LoadByIndices(samples_url, idx)[0])
            tensor_adjacency = torch.from_numpy(LoadByIndices(adjacencys_url, idx)[0])
            normal_adjacency = normalization(tensor_adjacency)
            logits = model(normal_adjacency, tensor_x)
            predict_y = logits.max(1)[1]
            acc.append(torch.eq(predict_y, y[idx]).float())
    accuracy = np.mean(acc)
    return accuracy
GCN(Graph Convolutional Network,图卷积网络)是一种用于图数据的深度学习模型,可以用于图分类、节点分类和链接预测等任务。Python中有很多开源的GCN框架可以使用,例如DGL、PyTorch Geometric等,下面简要介绍一下如何使用DGL训练GCN。 首先需要安装DGL库,可以使用pip install dgl命令进行安装。接着,我们需要定义一个GCN模型,例如: ```python import dgl import torch import torch.nn as nn import torch.nn.functional as F class GCN(nn.Module): def __init__(self, in_feats, hidden_size, num_classes): super(GCN, self).__init__() self.conv1 = dgl.nn.GraphConv(in_feats, hidden_size) self.conv2 = dgl.nn.GraphConv(hidden_size, num_classes) def forward(self, g, inputs): h = self.conv1(g, inputs) h = F.relu(h) h = self.conv2(g, h) return h ``` 其中in_feats是输入特征的维度,hidden_size是隐藏层特征的维度,num_classes是输出类别的数量。这里使用了两层GraphConvolution层,并使用ReLU作为激活函数。 接着,我们需要定义一个训练函数,例如: ```python def train(model, g, features, labels, train_mask, optimizer): model.train() optimizer.zero_grad() logits = model(g, features) loss = F.cross_entropy(logits[train_mask], labels[train_mask]) loss.backward() optimizer.step() return loss.item() ``` 其中g表示图数据,features表示节点特征,labels表示节点标签,train_mask表示训练集的掩码。我们使用交叉熵作为损失函数,并使用优器进行模型优。 最后,在训练数据上进行训练,例如: ```python import dgl.data # 加载数据集 dataset = dgl.data.CoraGraphDataset() g = dataset features = g.ndata['feat'] labels = g.ndata['label'] train_mask = g.ndata['train_mask'] # 创建模型和优器 model = GCN(in_feats=features.shape, hidden_size=16, num_classes=dataset.num_classes) optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 训练模型 for epoch in range(100): loss = train(model, g, features, labels, train_mask, optimizer) print('Epoch %d | Loss: %.4f' % (epoch + 1, loss)) ``` 这里使用了Cora数据集进行训练,每个节点有1433个特征和7个类别。我们使用Adam优器进行训练,共进行100轮训练
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值