【AM-GCN】代码解读之主程序(二)

[前篇]:
【AM-GCN】代码解读之初了解(一)
【AM-GCN】论文解读


一、导入库

import torch.nn.functional as F #常用函数
import torch.optim as optim     #优化算法
from utils import *
from models import SFGCN        #主模型
from sklearn.metrics import f1_score #计算F1分数,也称为平衡F分数或F测度
import os
import argparse
from config import Config
import torch
import numpy as np

解释说明

  1. torch.optim
  2. f1_score

二、参数读取和设置

if __name__ == "__main__":
    os.environ["CUDA_VISIBLE_DEVICES"] = "2"
    parse = argparse.ArgumentParser()
    parse.add_argument("-d", "--dataset", help="dataset", type=str, required=True)
    parse.add_argument("-l", "--labelrate", help="labeled data for train per class", type = int, required = True)
    args = parse.parse_args()
    config_file = "./config/" + str(args.labelrate) + str(args.dataset) + ".ini"
    config = Config(config_file)

    cuda = not config.no_cuda and torch.cuda.is_available() #cuda可否能用

    use_seed = not config.no_seed # cuda
    if use_seed:
        np.random.seed(config.seed)
        torch.manual_seed(config.seed)
        if cuda:
            torch.cuda.manual_seed(config.seed)

解释说明

  1. os.environ[“CUDA_VISIBLE_DEVICES”] = "2"设置使用的标号为"2"的显卡。os.environ[‘环境变量名称’]=‘环境变量值’ :其中key和value均为string类型
  2. argparse 参数配置的方法,可以打开cmd来设置参数的值,具体使用方法见5中链接。

    1)import argparse 首先导入模块
    ​2)parser = argparse.ArgumentParser() 创建一个解析器
    3)parser.add_argument() 向该解析器中添加你要关注的命令行参数和选项
    4)parser.parse_args() 进行解析

  3. config = Config(config_file) 是调用的config.py中的class类函数并实例化。其可以读取 'config_file '文件路径中的参数文件并配置参数。
  4. 'config_file '文件路径,涉及了 标签率args.labelrate 数据集args.dataset.通过原文可以知道是

    三个标签率(即每类20、40、60个标签节点)
    六个数据集(见《初了解一》)

  5. 区别:import argparse 和 import configparser,↙️具体见链接。
    1. 可以理解为都是参数配置的模块,两者并非不可互相替代。
    2. 显著区别是使用方法不同。通俗来讲,
      configparser更像是把参数进行分类归纳整理在一个.ini的文件中,通过读取文件的方式获得文件中的各项参数。
      argparse 更像是机器的开关,在开机运作的时候设置各项功能。

6.参数来源以及对照值

对象读取命令读取文件参数值
config.no_cudaconf.getboolean("Model_Setup", "no_cuda")20acmFalse
config.no_seedgetboolean("Model_Setup", "no_seed")20acmFalse
config.seedgetint("Model_Setup", "seed")20acm123
  1. 函数解析(具体见超链接):

np.random.seed()函数:用于生成指定随机数。
torch.manual_seed()函数:CPU生成随机数的种子,方便下次复现实验结果
torch.cuda.manual_seed()函数:固定生成随机数的种子,使得每次运行该 .py 文件时生成的随机数相同

  1. cuda–至结束。含义为是否使用cuda以及有可用的cuda,如果使用cuda则设置随机数种子123,否则使用cpu设置随机数种子123.

二、数据读取

    sadj, fadj = load_graph(args.labelrate, config)
    features, labels, idx_train, idx_test = load_data(config)
  • fadj是特征图矩阵 【3025,3025】–> 在acm中有7282个非零值
  • sadj是结构图矩阵 【3025,3025】–>有26256个非零值
  • features是特征向量—>(3025, 1870)
  • labels是标签向量 —>(3025,1)
  • idx_train是训练数据索引 -->(1000,)
  • idx_test是测试数据索引 -->(60,)
    以上数据结构以acm数据为例。且都是torch中的结构。该函数在utils.py中,并在《utils》该篇中详解。

三、模型准备

  1. 模型实例化
  2. 如果cuda可用,将数据放置到cuda上。
   model = SFGCN(nfeat = config.fdim,
              nhid1 = config.nhid1,
              nhid2 = config.nhid2,
              nclass = config.class_num,
              n = config.n,
              dropout = config.dropout)
    if cuda:
        model.cuda()
        features = features.cuda()
        sadj = sadj.cuda()
        fadj = fadj.cuda()
        labels = labels.cuda()
        idx_train = idx_train.cuda()
        idx_test = idx_test.cuda()
    optimizer = optim.Adam(model.parameters(), lr=config.lr, weight_decay=config.weight_decay)

四、模型训练

    acc_max = 0   #当前最大精度
    f1_max = 0    #‘当前’的f1分数
    epoch_max = 0 #‘当前’的epoch
    for epoch in range(config.epochs):
        loss, acc_test, macro_f1, emb = train(model, epoch)
        if acc_test >= acc_max:
            acc_max = acc_test
            f1_max = macro_f1
            epoch_max = epoch
    print('epoch:{}'.format(epoch_max),
          'acc_max: {:.4f}'.format(acc_max),
          'f1_max: {:.4f}'.format(f1_max))

解释说明

  1. 调用函数train(model, epoch)返回loss(损失),acc_test(),macro_f1(F1得分),emb(). train()函数在附录A中详解。
  2. if 语句的含义,如果返回的acc_test比当前记录的acc_max值大,则用本次的结果更新acc_max,f1_max,epoch_max.并将这次记录通过print输出。

附录–main.py:

main.py中定义的函数train()和test()

A train()

    def train(model, epochs):
        model.train()# 调用model中的train()函数
        optimizer.zero_grad()#把梯度置零,也就是把loss关于weight的导数变成0.
        output, att, emb1, com1, com2, emb2, emb= model(features, sadj, fadj)
        loss_class =  F.nll_loss(output[idx_train], labels[idx_train])
        loss_dep = (loss_dependence(emb1, com1, config.n) + loss_dependence(emb2, com2, config.n))/2
        loss_com = common_loss(com1,com2)
        loss = loss_class + config.beta * loss_dep + config.theta * loss_com
        acc = accuracy(output[idx_train], labels[idx_train])
        loss.backward()# 向后传播
        optimizer.step()# 参数优化
        # 参数优化后调用测试模型,将返回的结果print输出
        acc_test, macro_f1, emb_test = main_test(model)
        print('e:{}'.format(epochs),
              'ltr: {:.4f}'.format(loss.item()),
              'atr: {:.4f}'.format(acc.item()),
              'ate: {:.4f}'.format(acc_test.item()),
              'f1te:{:.4f}'.format(macro_f1.item()))
        return loss.item(), acc_test.item(), macro_f1.item(), emb_test

解释说明

  1. optimizer.zero_grad,将loss的导数设置为0.

  2. model(features, sadj, fadj)的输出结果为:

  3. F.nll_loss:最大似然 / log似然代价函数

    在这里插入图片描述
    a k a_k ak表示第k个神经元的输出值, y k y_k yk表示第k个神经元对应的真实值,取值为0或1。

  4. loss_dependence(),common_loss()见本文的附-utils.

  5. loss为:(暂时未知??)

  6. loss.item():item()仅可用于torch.Tensor的一维情况。测试

    print(type(torch.tensor([3]).item()))
    print(type(torch.tensor([3.2]).item())) 
    

    out:

    <class 'int'>
    <class 'float'>
    

B main_test()

    def main_test(model):
        model.eval()
        output, att, emb1, com1, com2, emb2, emb = model(features, sadj, fadj)
        acc_test = accuracy(output[idx_test], labels[idx_test])
        label_max = []
        for idx in idx_test:
            label_max.append(torch.argmax(output[idx]).item())
        labelcpu = labels[idx_test].data.cpu()
        macro_f1 = f1_score(labelcpu, label_max, average='macro')
        return acc_test, macro_f1, emb

解释说明

附:form utils import *

[1]utils–loss_dependence

def loss_dependence(emb1, emb2, dim):
    R = torch.eye(dim).cuda() - (1/dim) * torch.ones(dim, dim).cuda()
    K1 = torch.mm(emb1, emb1.t())
    K2 = torch.mm(emb2, emb2.t())
    RK1 = torch.mm(R, K1)
    RK2 = torch.mm(R, K2)
    HSIC = torch.trace(torch.mm(RK1, RK2))
    return HSIC

解释说明

  1. 相关函数
  • torch.eye:生成单位矩阵。
  • torch.ones:生成全1矩阵。
  • emb1.t中.t表示转职。
  • torch.mm表示二维矩阵乘法(非点乘)。
  • torch.trace()返回输入二维矩阵的对角线元素的总和
  1. 设dim=N,则R=E-1/N[ones].假设N=4.R则为
3/4-1/4-1/4-1/4
-1/43/4-1/4-1/4
-1/4-1/43/4-1/4
-1/4-1/4-1/43/4
  1. 设A = emb1, B= emb2.则
    H S I C = [ R ∗ ( A ∗ A T ) ] ∗ [ R ∗ ( B ∗ B T ) ] HSIC = [R \ast(A \ast A^T)] \ast [R \ast (B \ast B^T)] HSIC=[R(AAT)][R(BBT)]
    其中, K 1 = A ∗ A T = [ a i j 2 ] N × N K1=A\ast A^T = [a_{ij}^2]_{N\times N} K1=AAT=[aij2]N×N.意为K1矩阵每个元素为矩阵A的每个元素的平方。
  2. 功能:暂时未知。

[2]utils–common_loss()

def common_loss(emb1, emb2):
    emb1 = emb1 - torch.mean(emb1, dim=0, keepdim=True)
    emb2 = emb2 - torch.mean(emb2, dim=0, keepdim=True)
    emb1 = torch.nn.functional.normalize(emb1, p=2, dim=1)
    emb2 = torch.nn.functional.normalize(emb2, p=2, dim=1)
    cov1 = torch.matmul(emb1, emb1.t())
    cov2 = torch.matmul(emb2, emb2.t())
    cost = torch.mean((cov1 - cov2)**2)
    return cost
  1. 相关函数:

    • torch.mean:求均值.torch.mean(a,axis=0,keepdim=True).if :a.shape=(N,M),so mean.shape=(1,M).注意都是二维结构。如果keepdim=False,so mean.shape=(M,).
    • torch.nn.functional.normalize : 进行L-p范数的标准化。不明白看链接。
    • torch.matmul:torch.Tensor[张量]的乘法。二维的时候是矩阵乘法,可以支持广播机制。因此支持多维数据的乘法。
  2. 设emb1=A,emb2=B

    step1 : A = A − [ [ a ˉ 1 , . . . , a ˉ N ] ] , w h e r e   a ˉ i = ∑ j = 1 N a i j A=A-[[\bar{a}_1,...,\bar{a}_N]],where \ \bar{a}_i=\sum_{j=1}^N{a_{ij}} A=A[[aˉ1,...,aˉN]],where aˉi=j=1Naij,利用广播机制相减
    step2: A的标准化—A的每行求和,每个元素除以行和。
    step3: c o v 1 = A ∗ A T → cov1 = A\ast A^T \rightarrow cov1=AAT A的每个元素求平方
    step4: 同理对于B的操作
    step5 :
    [ ( A ∗ A T ) − ( B ∗ B T ) ] 2 = ( ( a 11 2 − b 11 2 ) 2 ( a 12 2 − b 12 2 ) 2 ⋯ ( a 1 n 2 − b 1 n 2 ) 2 ⋮ ⋮ ⋱ ⋮ ( a n 1 2 − b n 1 2 ) 2 ( a n 2 2 − b n 2 2 ) 2 ⋯ ( a n n 2 − b n n 2 ) 2 ) [(A\ast A^T)-(B\ast B^T)]^2=\begin{pmatrix} (a_{11}^2-b_{11}^2)^2 & (a_{12}^2-b_{12}^2)^2 & \cdots & (a_{1n}^2-b_{1n}^2)^2 \\ \vdots & \vdots & \ddots & \vdots \\ (a_{n1}^2-b_{n1}^2)^2 & (a_{n2}^2-b_{n2}^2)^2 & \cdots & (a_{nn}^2-b_{nn}^2)^2 \\ \end{pmatrix} [(AAT)(BBT)]2=(a112b112)2(an12bn12)2(a122b122)2(an22bn22)2(a1n2b1n2)2(ann2bnn2)2
    step6:torch.mean { [ ( A ∗ A T ) − ( B ∗ B T ) ] 2 } \{ [(A\ast A^T)-(B\ast B^T)]^2 \} {[(AAT)(BBT)]2},由于默认axis=None,即对矩阵内的所有元素求平均。结果为 ∑ j = 1 N ∑ j = 1 N ( ( a i j 2 − b i j 2 ) 2 ] N 2 \frac{\sum_{j=1}^N\sum_{j=1}^N( (a_{ij}^2-b_{ij}^2)^2 ]}{N^2} N2j=1Nj=1N((aij2bij2)2]


后篇:
【AM-GCN】代码解读之utlis(三)
【AM-GCN】代码解读之model(四)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
T-GCN(Temporal Graph Convolutional Network)是一种用于时间序列分类和预测的深度学习模型。它的核心思想是将时间序列数据表示成一个图结构,然后利用图卷积神经网络(GCN)对图进行卷积操作,从而实现时间序列数据的特征提取和预测。 以下是 T-GCN 模型的代码解读: ```python class TGCN(nn.Module): def __init__(self, num_nodes, in_channels, out_channels, K, p): super(TGCN, self).__init__() self.K = K self.p = p self.num_nodes = num_nodes self.conv1 = nn.ModuleList() self.conv2 = nn.ModuleList() self.conv3 = nn.ModuleList() self.conv4 = nn.ModuleList() self.conv5 = nn.ModuleList() self.conv6 = nn.ModuleList() for i in range(K): self.conv1.append(GCNConv(in_channels, 64)) self.conv2.append(GCNConv(64, 64)) self.conv3.append(GCNConv(64, 64)) self.conv4.append(GCNConv(64, 128)) self.conv5.append(GCNConv(128, 128)) self.conv6.append(GCNConv(128, out_channels)) def forward(self, x, A): x = x.reshape(self.num_nodes, self.p, -1) for i in range(self.K): x1 = self.conv1[i](x.view(self.num_nodes, -1), A) x1 = F.relu(x1) x2 = self.conv2[i](x1, A) x2 = F.relu(x2) x3 = self.conv3[i](x2, A) x3 = F.relu(x3) x4 = self.conv4[i](x3, A) x4 = F.relu(x4) x5 = self.conv5[i](x4, A) x5 = F.relu(x5) x6 = self.conv6[i](x5, A) if i == 0: res = x6 else: res += x6 x = torch.cat([x[:, 1:, :], x6.unsqueeze(1)], dim=1) return res ``` 这个模型的输入是一个形状为 `(num_nodes, p, in_channels)` 的张量 `x`,表示有 `num_nodes` 个节点、每个节点 `p` 个时间步、每个时间步 `in_channels` 个特征。`A` 是形状为 `(num_nodes, num_nodes)` 的邻接矩阵,表示节点之间的联系。 首先,模型将 `x` reshape 成 `(num_nodes, p, -1)` 的形状,其中 `-1` 表示特征维度。接着,模型利用 `nn.ModuleList` 定义了 6 层 GCN,每层 GCN 都包含了若干个 `GCNConv` 层。在每层 GCN 中,模型将输入 `x` 进行卷积,并利用 ReLU 激活函数进行非线性转换。最后一层 GCN 的输出作为该层的输出 `x6`。 在每个时刻 `i`,模型将 `x6` 加到之前的结果 `res` 中,并将 `x` 中除了第一个时间步以外的所有时间步和 `x6` 的第一个时间步拼接在一起,得到新的 `x`。这个过程会重复执行 `K` 次,最终模型的输出就是 `res`。 总体来说,T-GCN 模型是一个基于 GCN 的循环神经网络,可以对时间序列数据进行建模和预测。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值