计算GCN的Flops

计算GCN的Flops

计算CNN的Flops

计算ResNet的Flops

计算MobileNet的Flops

计算Transformer的Flops

核心程序:

# 手动估算 GCN FLOPs
E = gcn_data.edge_index.shape[1]  # 边数
N = gcn_data.x.shape[1]           # 节点数
F_in = Input_L                    # 输入特征维度
F_mid = middle_len               # 第一层输出维度
F_out = out_len                  # 第二层输出维度


flops_layer1 = 2 * E * F_in + N * F_in * F_mid
flops_layer2 = 2 * E * F_mid + N * F_mid * F_out
total_flops = flops_layer1 + flops_layer2

第一项计算的是卷积操作的Flops,第二项计算的是映射的Flops

很好理解,卷积时只用边上的节点,所以是边E*特征长度,2代表乘法和加法;而映射的话是每个节点都要映射,于是是节点数N*特征长度*输出特征长度

模型结构:

class Net(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = GCNConv(Input_L, middle_len)
        self.conv2 = GCNConv(middle_len, out_len)

    def encode(self, x, edge_index):
        c1_in = x.T
        c1_out = self.conv1(c1_in, edge_index)
        c1_relu = c1_out.relu()
        c2_out = self.conv2(c1_relu, edge_index)
        c2_relu = c2_out.relu()
        return c2_relu

    def decode(self, z, edge_label_index):
        # 节点和边都是矩阵,不同的计算方法致使:节点->节点,节点->边
        distance_squared = torch.sum((z[edge_label_index[0]] - z[edge_label_index[1]]) ** 2, dim=-1)
        return distance_squared

完成程序,仅供参考:

#作者:zhouzhichao
#创建时间:25年5月30日
#内容:进行残缺数据实验

import warnings

from torch.nn import Threshold

warnings.simplefilter(action='ignore', category=FutureWarning)
import sys
import torch
import time
torch.set_printoptions(linewidth=200)
import pandas as pd
import numpy as np
from torch_geometric.data import Data
from torchinfo import summary
import matplotlib.pyplot as plt
from torch_geometric.nn import GCNConv
sys.path.append('D:\无线通信网络认知\论文1\大修意见\Reviewer1-1 阈值相似性图对比实验')
from gcn_dataset import graph_data
print(torch.__version__)
print(torch.cuda.is_available())
from sklearn.metrics import roc_auc_score, precision_score, recall_score, accuracy_score
from ptflops import get_model_complexity_info


data_i = 1
root = "test data 30 (pyg)\graph data "+str(data_i)

accuracy = []
precision = []
recall_rate = []
cost_time = []
# middle_len = 200
# out_len = 100
# middle_len = 5

middle_len = 50
out_len = 20
# for middle_len in range(0, 50, 1):

Threshold = 0

class Net(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = GCNConv(Input_L, middle_len)
        self.conv2 = GCNConv(middle_len, out_len)

    def encode(self, x, edge_index):
        c1_in = x.T
        c1_out = self.conv1(c1_in, edge_index)
        c1_relu = c1_out.relu()
        c2_out = self.conv2(c1_relu, edge_index)
        c2_relu = c2_out.relu()
        return c2_relu

    def decode(self, z, edge_label_index):
        # 节点和边都是矩阵,不同的计算方法致使:节点->节点,节点->边
        distance_squared = torch.sum((z[edge_label_index[0]] - z[edge_label_index[1]]) ** 2, dim=-1)
        return distance_squared

    def decode_all(self, z):
        prob_adj = z @ z.t()  # 得到所有边概率矩阵
        return (prob_adj > 0).nonzero(as_tuple=False).t()  # 返回概率大于0的边,以edge_index的形式

    @torch.no_grad()
    def get_val(self, gcn_data):
        #获取未参与训练的节点索引
        edge_index = gcn_data.edge_index  # [2, 30]
        edge_label_index = gcn_data.edge_label_index  # [2, 60]
        edge_label = gcn_data.edge_label

        # 转置方便处理,变成 (num_edges, 2)
        edge_index_t = edge_index.t()  # [30, 2]
        edge_label_index_t = edge_label_index.t()  # [60, 2]

        # 把边转成集合形式的字符串,方便查找(也可用tuple)
        edge_index_set = set([tuple(e.tolist()) for e in edge_index_t])

        # 判断edge_label_index中的每个边是否在edge_index_set里
        is_in_edge_index = [tuple(e.tolist()) in edge_index_set for e in edge_label_index_t]

        is_in_edge_index = torch.tensor(is_in_edge_index)


        # 不相同的列(边)
        val_col = edge_label_index[:, ~is_in_edge_index]

        val_label = edge_label[~is_in_edge_index]

        # val_col = val_col[:,:20]
        # val_label = val_label[:20]

        divide_index = int(sum(val_label).item())
        val_col_1 = val_col[:,:divide_index]
        val_label_1 = val_label[:divide_index]
        val_col_0 = val_col[:, divide_index:2*divide_index]
        val_label_0 = val_label[divide_index:2*divide_index]

        return  val_col_1, val_label_1, val_col_0, val_label_0

    @torch.no_grad()
    def predict(self, gcn_data, threshhold):
        model.eval()
        z = model.encode(gcn_data.x, gcn_data.edge_index)
        out = model.decode(z, gcn_data.complex_test).view(-1)
        out = 1 - out
        out_np = out.cpu().numpy()
        pred = (out_np > threshhold).astype(int)
        return pred

    # @torch.no_grad()
    # def forward(self, gcn_data):
    #     model.eval()
    #
    #     z = model.encode(gcn_data.x, gcn_data.edge_index)
    #     # out = model.decode(z, gcn_data.edge_label_index).view(-1)
    #     out = model.decode(z, gcn_data.complex_test).view(-1)
    #     out = 1 - out
    #
    #     out_np = out.cpu().numpy()
    #     labels_np = gcn_data.edge_label.cpu().numpy()
    #
    #     threshhold = 0
    #     accuracy_max = 0
    #     for th in np.arange(-2, 1.1, 0.1):
    #         pred_labels = (out_np > th).astype(int)
    #         accuracy = accuracy_score(labels_np, pred_labels)
    #         if accuracy > accuracy_max:
    #             accuracy_max = accuracy
    #             threshhold = th
    #
    #     pred = (out_np > threshhold).astype(int)
    #     return pred

    @torch.no_grad()
    def forward(self, gcn_data):
        model.eval()

        z = model.encode(gcn_data.x, gcn_data.edge_index)

        out = model.decode(z, gcn_data.complex_test).view(-1)
        out = 1 - out

        out_np = out.cpu().numpy()
        pred = (out_np > Threshold).astype(int)
        return pred

    @torch.no_grad()
    def test_val(self, gcn_data, threshhold):
        model.eval()
        # same_col, diff_col, same_label, diff_label = col_devide(gcn_data)
        val_col_1, val_label_1, val_col_0, val_label_0 = self.get_val(gcn_data)

        # 1
        z = model.encode(gcn_data.x, gcn_data.edge_index)
        out = model.decode(z, val_col_1).view(-1)
        out = 1 - out
        out_np = out.cpu().numpy()
        labels_1 = val_label_1.cpu().numpy()
        # roc_auc_s = roc_auc_score(labels_np, out_np)
        pred_1 = (out_np > threshhold).astype(int)
        accuracy_1 = accuracy_score(labels_1, pred_1)
        precision_1 = precision_score(labels_1, pred_1, zero_division=1)
        recall_1 = recall_score(labels_1, pred_1, zero_division=1)

        # 0
        z = model.encode(gcn_data.x, gcn_data.edge_index)
        out = model.decode(z, val_col_0).view(-1)
        out = 1 - out
        out_np = out.cpu().numpy()
        labels_0 = val_label_0.cpu().numpy()
        # roc_auc_d = roc_auc_score(labels_np, out_np)
        pred_0 = (out_np > threshhold).astype(int)
        accuracy_0 = accuracy_score(labels_0, pred_0)
        precision_0 = precision_score(labels_0, pred_0, zero_division=1)
        recall_0 = recall_score(labels_0, pred_0, zero_division=1)

        accuracy = (accuracy_1 + accuracy_0)/2
        precision = (precision_1 + precision_0)/2
        recall = (recall_1 + recall_0)/2

        return accuracy, precision, recall

    @torch.no_grad()
    def calculate_threshhold(self, gcn_data):
        model.eval()

        z = model.encode(gcn_data.x, gcn_data.edge_index)
        out = model.decode(z, gcn_data.edge_label_index).view(-1)
        out = 1 - out

        out_np = out.cpu().numpy()
        labels_np = gcn_data.edge_label.cpu().numpy()

        threshhold = 0
        accuracy_max = 0
        for th in np.arange(-2, 1.1, 0.1):
            pred_labels = (out_np > th).astype(int)
            accuracy = accuracy_score(labels_np, pred_labels)
            if accuracy>accuracy_max:
                accuracy_max = accuracy
                threshhold = th

        return threshhold

def graph_normalize(gcn_data):
    for i in range(gcn_data.x.shape[1]):
        gcn_data.x[:, i] = gcn_data.x[:,i]/torch.max(torch.abs(gcn_data.x[:,i]))




gcn_data = graph_data(root)
graph_normalize(gcn_data)

Input_L = gcn_data.x.shape[0]


model = Net()
optimizer = torch.optim.Adam(params=model.parameters(), lr=0.01)
criterion = torch.nn.BCEWithLogitsLoss()

model.train()

def train():
    optimizer.zero_grad()
    z = model.encode(gcn_data.x, gcn_data.edge_index)
    out = model.decode(z, gcn_data.edge_label_index).view(-1)
    out = 1 - out
    loss = criterion(out, gcn_data.edge_label)
    loss.backward()
    optimizer.step()
    return loss

min_loss = 99999
count = 0#早停
for epoch in range(100000):
    loss = train()
    if loss<min_loss:
        min_loss = loss
        count = 0
        # print("out_len:  ", out_len, "  epoch:  ", epoch, "   loss: ",
        #       round(loss.item(), 4), "   min_loss: ", round(min_loss.item(), 4))
        print("middle_len:  ", middle_len, "  epoch:  ", epoch, "   loss: ",
              round(loss.item(), 4), "   min_loss: ", round(min_loss.item(), 4))
    count = count + 1
    if count>100:
       break




t1 = time.time()
for p in range(100):
    threshhold = model.calculate_threshhold(gcn_data)
    pred = model.predict(gcn_data,threshhold)
t2 = time.time()
delta_t = (t2 - t1)/100

calculate_flops = 1
# if calculate_flops:
#     # model.summary()
#     # print("Total parameters:", model.count_params())
#     total_params = sum(p.numel() for p in model.parameters())
#     print("Total parameters:", total_params)
#     trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
#     print("Trainable parameters:", trainable_params)
#     # 确保模型构建完成
#     input_shape = (1, gcn_data.x.shape[1])  # batch size = 1
#     # input_shape = x.shape[1]
#     # input_shape = (1, x_val.shape[1])  # 例如 (batch_size=1, sequence_length=3600)
#
#     macs, params = get_model_complexity_info(model, input_shape, as_strings=True,
#                                              print_per_layer_stat=True, verbose=True)
#
#     print(f"FLOPs: {macs}")
#     print(f"Parameters: {params}")

if calculate_flops:
    total_params = sum(p.numel() for p in model.parameters())
    print("Total parameters:", total_params)
    trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
    print("Trainable parameters:", trainable_params)

    threshhold = model.calculate_threshhold(gcn_data)
    Threshold = threshhold

    # dummy_data = Data(x=gcn_data.x, edge_index=gcn_data.edge_index)
    # dummy_data.edge_label_index = gcn_data.edge_label_index  # 如果 forward 需要
    # dummy_data.complex_test = gcn_data.complex_test  # 如果 forward 用到
    #
    # # 2. 展示结构
    # summary(model, input_data=(dummy_data,))

    # 手动估算 GCN FLOPs
    E = gcn_data.edge_index.shape[1]  # 边数
    N = gcn_data.x.shape[1]           # 节点数
    F_in = Input_L                    # 输入特征维度
    F_mid = middle_len               # 第一层输出维度
    F_out = out_len                  # 第二层输出维度

    # GCNConv FLOPs: 2*E*F + N*F*F_out(见论文或相关资料)
    flops_layer1 = 2 * E * F_in + N * F_in * F_mid
    flops_layer2 = 2 * E * F_mid + N * F_mid * F_out
    total_flops = flops_layer1 + flops_layer2

    print(f"Estimated GCN FLOPs: {total_flops / 1e6:.2f} MFLOPs")



accuracy_value, precision_value, recall_value = model.test_val(gcn_data, threshhold)

accuracy.append(accuracy_value)
cost_time.append(delta_t)

data = {
    'cost_time': cost_time,
    'accuracy': accuracy
}

# 创建一个 DataFrame
df = pd.DataFrame(data)
#
# # 保存到 Excel 文件
file_path = 'D:\无线通信网络认知\论文1\大修意见\Reviewer2-7 多种深度学习方法对比实验\\gcn acc-time data '+str(data_i)+'.xlsx'
df.to_excel(file_path, index=False)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值