• 理性分析不同模型的性能指标


    性能指标

    FLOPS:浮点运算次数。
    MADD:表示一次乘法和一次加法,这可以粗略认为:MADD=2 * Flops,即((输出一个元素所经历的乘法次数)+(输出一个元素所经历的加法的个数)) * (输出总共的元素的个数)
    MEMREAD:网络运行时,从内存中读取的大小,即输入的特征图大小 + 网络参数的大小
    MEMWRITE:网络运行时,写入到内存中的大小,即输出的特征图大小

    模型类型

    卷积神经网络

    在经典卷积神经网络中,输入特征图通常为\(H\times W\)(这里假设\(H,W\)一致),输入通道数目为\(C_i\),卷积核输入深度通常和输入特征图的输入通道保持一致,其核大小通常为\(K\),输出通道(可以理解为输出深度)通常为\(C_{out}\),除此以外需要考虑填充大小\(P\)和步长\(S\)。基于上述条件,特征图输出大小\(M\)满足:

    \[M=(H-K+2\times P)/ S + 1 \]

    在每一次卷积过程中,每个卷积核与输入特征图上当前步对应的窗口内元素进行逐通道、逐元素相乘并累加;重复多次操作,直至卷积核完整遍历输入特征图,每个卷积层运算次数flops满足下述关系:

    \[Flops = C_i \times K^2 \times M^2 \times C_{out} \]

    依据层内相乘,层间相加的准则,经典卷积神经网络模型所有卷积层的时间复杂度满足关系如下(\(N\)为卷积层的数目):

    \[\sum_j^N C_{ij} \times K_j^2 \times M_j^2 \times C_{out,j} \]

    下面通过一个案例,来具体分析:

    class Net(nn.Module):
    def __init__(self):
    super(Net, self).__init__()
    self.conv1 = nn.Conv2d(3, 2, kernel_size=7, stride=2, padding=3, bias=False)
    self.bn1 = nn.BatchNorm2d(2)
    self.relu1 = nn.ReLU()
    def forward(self, x):
    x = self.conv1(x)
    x = self.bn1(x)
    x = self.relu1(x)
    return x
    net = Net()
    stat(net, (3, 500, 500))
    # 输入通道为3 输入特征图大小为500
    # 输出特征图大小为(500-7+6)/2+1=250
    # Flops=250*250*3*2*7*7=18375000
    # MADD=(250*250*2)*((7*7*3)+(7*7*3-1))=36625000
    # MemREAD= ((500 * 500 * 3) + (7 * 7 * 3 * 2)) * 4 = 3001176.0 【认为每个参数为FP32,满足四个字节,因此乘4】
    # MEMW:250 * 250 * 2 * 4 = 500000

    FLOPS/PARAMS参数计算工具

    下面给出thop的使用方法,thop只能计算输入为一个矩阵的模型的参数量和FLOPs,实际中的模型可能存在多个输入,如以下案例:

    out = model(detections,boxs,grids,masks,captions)
    # 其中作为模型传入参数的是五个矩阵,其尺寸为:
    detections.shape = (bs,50,2048)
    boxs.shape = (bs,50,4)
    grids.shape = (bs,49,2048)
    masks.shape = (bs,50,49)
    captions.shape = (bs,19)

    想要计算这样一个模型的参数量和计算量,需要考虑一种新的方式。我在这里给出的方案是:构建一个新的,接收单矩阵输入的类。代码如下:

    import torch.nn as nn
    class func(nn.Module):
    def __init__(self,object):
    super(func,self).__init__()
    self.model = object
    def forward(self,a):
    detections = torch.randn(1,50,2048).float()
    boxs = torch.randn(1,50,4).float()
    grids = torch.randn(1,49,2048).float()
    masks = torch.randn(1,50,49).float()
    captions = torch.tensor([0,100,105,2,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1]).unsqueeze(0)
    print(captions.shape)
    out = self.model(detections,boxs,grids,masks,captions)
    return out

    可以看到,该类继承自nn.Module,以确保该类可以被声明为一个模型。接着在类的初始化函数中,将待计算模型的对象作为参数传入,并赋值给self.model;在forward函数中,规定其必须接收一个参数(实际上我们并不会使用这个接收到的参数),并通过torch内置的随机函数产生需要形状的张量(之所以特殊对待captions是因为model要求该参数的元素为整型)。

    最后,就可以进行参数量和FLOPs的计算,代码如下:

    model = Transformer(text_field.vocab.stoi[''],
    encoder, decoder, args=args)
    use_model = func(model)
    input = torch.randn(1, 3, 224, 224)
    flops, params = profile(use_model, inputs=(input))
    print("FLOPs=", str(flops/1e9) + '{}'.format("G"))
    print("params=", str(params/1e6) + '{}'.format("M"))

    其中,第一行声明Transformer类,并将其对象命名为model;第二行声明上面定义的func类,将model作为声明类时的传入参数;第三行随机生成一个矩阵;第四行调用thop中的profile方法对func类的参数量和运算量进行计算,实际上等价于对Transformer类的参数量和运算量计算。

    吞吐和时延

    吞吐量:完成一个特定任务的速率(单位时间内完成的任务数目,衡量指标为bits/second,Bytes/second)。对神经网络而言,吞吐量可以设置为每秒处理的图片数量或语音数量。
    延时:完成一个任务需要花费的时间。

    吞吐量和延时并不是严格的反比关系。吞吐量可以认为是一个系统并行处理的任务量,延时是一个系统串行处理一个任务所花费的时间

    optimal_batch = 160000 # 基于本案例中的模型所测试出的最佳batch为160000
    # while True: # 这里是确定最佳batch的大小 出现cuda显存不足前认为是最佳batch
    # x = torch.randn(optimal_batch, 3, 28, 28).to(device='cuda')
    # _ = net(x)
    # print("当前测试批量为:", optimal_batch) if optimal_batch % 1000 == 0 else None
    # optimal_batch += 100
    input = torch.randn(optimal_batch, 3, 28, 28).to(device='cuda')
    repetitions = 100
    total_time = 0
    with torch.no_grad():
    for rep in range(repetitions):
    starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
    starter.record()
    _ = net(input)
    ender.record()
    torch.cuda.synchronize()
    curr_time = starter.elapsed_time(ender) / 1000
    total_time += curr_time
    Throughput = (repetitions * optimal_batch) / total_time
    print('Final Throughput:', Throughput)

    参考文献

    [1] 面试宝典笔记:卷积计算过程中的FLOPs
    [2] 通过thop计算模型的参数量与运算量(FLOPs)
    [3] THOP+torchstat 计算PyTorch模型的FLOPs,问题记录与解决
    [4]吞吐和时延
    [5]深度学习模型推理速度/吞吐量计算

  • 相关阅读:
    005 OpenCV直方图
    全国职业技能大赛云计算--高职组赛题卷②(容器云)
    Fecify 跨境电商系统,有哪些优势?
    爬虫兽问题解答1-抖音评论区爬虫采集拓客系统
    五年了,我在 CSDN 的两个一百万。
    北大肖臻老师《区块链技术与应用》系列课程学习笔记[12]以太坊-账户
    一遍关于vue基础语法下篇
    SpringCloud 2022有哪些变化
    通用的改进遗传算法求解带约束的优化问题(MATLAB代码)
    优雅的接口防刷处理方案
  • 原文地址:https://www.cnblogs.com/XL2COWARD/p/PIM4AI_2.html