from __future__ import division
from __future__ import print_function
# 导入包
import argparse
import numpy as np
import scipy.sparse as sp
import torch
import torch.nn.functional as F

# 定义命令行参数
parser = argparse.ArgumentParser()
parser.add_argument('--seed', type=int, default=42, help='Random seed.')
parser.add_argument('--dataset', type=str,
                    default='cora', help='type of dataset.')
#parser.add_argument('--hops', type=int, default=20, help='number of hops')
hops =20
r_list = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
args = parser.parse_args()

# 将稀疏矩阵转换成稀疏张量
def sparse_mx_to_torch_sparse_tensor(sparse_mx):
  
    sparse_mx = sparse_mx.tocoo().astype(np.float32) # 将稀疏矩阵转换为coo格式,并转换为float32类型
    indices = torch.from_numpy(
        np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)) # 将行索引和列索引合并,并转换为int64类型
    values = torch.from_numpy(sparse_mx.data) # 将矩阵中的元素转换为张量类型
    shape = torch.Size(sparse_mx.shape) # 获取矩阵的形状
    return torch.sparse.FloatTensor(indices, values, shape) # 返回稀疏张量

# 对邻接矩阵进行归一化
def normalize_adj(mx, r):
    '''Row-normalize sparse matrix'''
    mx = sp.coo_matrix(mx) + sp.eye(mx.shape[0])# 将邻接矩阵转换为coo格式,然后加上对角线元素
    rowsum = np.array(mx.sum(1))# 按行求和
    r_inv_sqrt_left = np.power(rowsum, r-1).flatten()# 求行向量的r-1次方,并将结果展平
    r_inv_sqrt_left[np.isinf(r_inv_sqrt_left)] = 0.# 如果结果中有inf则赋值为0
    r_mat_inv_sqrt_left = sp.diags(r_inv_sqrt_left)

    r_inv_sqrt_right = np.power(rowsum, -r).flatten()# 求行向量的-r次方,并将结果展平
    r_inv_sqrt_right[np.isinf(r_inv_sqrt_right)] = 0.# 如果结果中有inf则赋值为0
    r_mat_inv_sqrt_right = sp.diags(r_inv_sqrt_right)
    adj_normalized = mx.dot(r_mat_inv_sqrt_left).transpose().dot(r_mat_inv_sqrt_right).tocoo()# 计算D^ r_t-1 A^ ~  D^ -r_t,DAD
    return sparse_mx_to_torch_sparse_tensor(adj_normalized) # 返回归一化后的稀疏张量

# 主函数
def run(args):
   
    adj = torch.tensor([
        [1., 1., 0., 0., 0., 0., 0., 1., 0., 0.],
        [1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 1., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0., 0., 1.],
    ])
    features=torch.tensor([
        [1., 1.2, 0., 0., 0., 0., 0., 1., 0.2, 0.],
        [1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0.5, 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 1., 0., 0., 0., 0., 0.],
        [0., 0., 2., 0., 0., 1., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0., 0., 1., 0., 0., 0.],
        [0., 0., 0., 0.4, 0., 0., 0., 1., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0., 0., 1.],
    ])
    n_nodes, feat_dim = features.shape

    # 迭代hop次
    for hop in range(hops, hops+1): # hop为迭代次数n
        # 设置
        input_features = 0.
        for r in r_list:
            adj_norm = normalize_adj(adj, r) # 对邻接矩阵进行归一化
            features_list = []
            features_list.append(features) # 将特征矩阵加入列表
            features_list.append(torch.spmm(adj_norm, features_list[-1]))  # 计算邻接矩阵与特征矩阵的乘积
            # 计算权重
            weight_list = []
            norm_fea = torch.norm(features, 2, 1).add(1e-10)  # 计算特征矩阵的L2范数
            for fea in features_list:
                norm_cur = torch.norm(fea, 2, 1).add(1e-10) # 计算当前特征矩阵的L2范数
                temp = torch.div((features*fea).sum(1), norm_fea) # 计算特征矩阵与当前特征矩阵的点积,并除以两个矩阵的L2范数
                temp = torch.div(temp, norm_cur) # 再除以当前特征矩阵的L2范数
                weight_list.append(temp.unsqueeze(-1)) # 将权重加入列表
            weight = F.softmax(torch.cat(weight_list, dim=1), dim=1) # 对权重进行softmax归一化

            input_feas = []
           
            for i in range(n_nodes):
                fea = 0.
                for j in range(hop+1):
                    fea += (weight[i][j]*features_list[j][i]).unsqueeze(0) # 计算每个节点的输入特征向量
                input_feas.append(fea)
            input_feas = torch.cat(input_feas, dim=0) # 将所有节点的输入特征向量拼接起来

            if r == r_list[0]:
                input_features = input_feas
            else:
             
                temp = []
                temp.append(input_features.unsqueeze(0))
                temp.append(input_feas.unsqueeze(0))

                input_features = torch.cat(temp, dim=0).max(0)[0] # 将不同r值下的输入特征向量进行max池化

        sim = torch.sigmoid(torch.mm(input_features, input_features.T)) # 计算相似度矩阵

if __name__ == '__main__':
    run(args)

这段代码实现了基于邻接矩阵和特征矩阵的图卷积神经网络(GCN)模型,并计算了输入节点的相似度矩阵。具体实现步骤如下:

  1. 对邻接矩阵进行归一化,得到归一化后的稀疏张量。

  2. 迭代hop次,每次迭代分别计算不同r值下的输入特征向量,并对不同r值下的输入特征向量进行max池化,得到最终的输入特征向量。

  3. 计算输入特征向量之间的相似度矩阵。

图卷积神经网络 (GCN) 实现节点相似度计算

原文地址: https://www.cveoy.top/t/topic/jOwZ 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录