模型计算量 MAC/FLOPs 的手动统计方法

文章目录

    • 简介
    • 背景
      • 为什么理解神经网络中的MAC和FLOPs很重要?
        • 资源效率
        • 内存效率
        • 能耗
          • 功耗效率
        • 模型优化
        • 性能基准
        • 研究与发展
    • FLOPs 和 MACs 定义
    • 1. 全连接层 FLOPs 计算
      • 步骤 1:识别层参数
      • 步骤 2:计算 FLOPs 和 MACs
      • 步骤 3:总结结果
      • 使用 torchprofile 库验证
    • 2. 卷积神经网络(CNNs)
      • 计算卷积操作时的重要考虑因素
      • 第一步:确定层参数
      • 第二步:计算FLOPs和MACs
      • 第三步:汇总结果
      • 使用torchprofile库验证操作
    • 3. 自注意力模块 (self-attention) FLOPs 计算
      • 第一步:确定层参数
      • 第二步:汇总结果
      • 使用torchprofile库验证操作
    • 总结:按不同批次大小缩放MACs和FLOPs

简介

理解神经网络中的 MAC(乘累加操作)和 FLOPs(浮点运算)对于优化网络性能和效率至关重要。通过手动计算这些指标,可以更深入地了解网络结构的计算复杂性和资源需求。这不仅能帮助设计高效的模型,还能在训练和推理阶段节省时间和资源。本文将通过实例演示如何计算全连接层(fc)卷积层(conv) 以及 自注意力模块(self-attention) 的 FLOPs 和 MACs,并探讨其对资源效率、内存效率、能耗和模型优化的影响。


背景

为什么理解神经网络中的MAC和FLOPs很重要?

在本节中,我们将深入探讨神经网络中 MAC(乘累加操作)和 FLOPs(浮点运算)的概念。通过学习如何使用笔和纸手动计算这些指标将获得对各种网络结构的计算复杂性和效率的基本理解。

理解 MAC 和 FLOPs 不仅仅是学术练习;它是优化神经网络性能和效率的关键组成部分。它有助于设计既计算高效又有效的模型,从而在训练和推理阶段节省时间和资源。

这是一个在 Colab 笔记本中完全运行的示例

资源效率

理解 FLOPs 有助于估算神经网络的计算成本。通过优化 FLOPs 的数量,可以潜在地减少训练或运行神经网络所需的时间。

内存效率

MAC 操作通常决定了网络的内存使用情况,因为它们直接与网络中的参数和激活数量相关。减少 MACs 有助于使网络的内存使用更高效。

能耗
功耗效率

FLOPs 和 MAC 操作都对运行神经网络的硬件的功耗有贡献。通过优化这些指标,可以潜在地减少运行网络所需的能量,这对于移动设备和嵌入式设备尤为重要。

模型优化
  • 剪枝和量化
    理解 FLOPs 和 MACs 可以帮助通过剪枝(去除不必要的连接)和量化(降低权重和激活的精度)等技术优化神经网络,这些技术旨在减少计算和内存成本。
性能基准
  • 模型间比较
    FLOPs 和 MACs 提供了一种比较不同模型计算复杂性的方法,这可以作为为特定应用选择模型的标准。

  • 硬件基准
    这些指标还可以用于对比不同硬件平台运行神经网络的性能。

  • 边缘设备上的部署

    • 实时应用
      对于实时应用,特别是在计算资源有限的边缘设备上,理解和优化这些指标对于确保网络能够在应用的时间限制内运行至关重要。
    • 电池寿命
      在电池供电的设备中,减少神经网络的计算成本(从而减少能耗)可以帮助延长电池寿命。
研究与发展
  • 设计新算法
    在开发新算法或神经网络结构时,研究人员可以使用这些指标作为指导,目的是在不牺牲精度的情况下提高计算效率。

FLOPs 和 MACs 定义

  • FLOP(浮点运算)被认为是加法、减法、乘法或除法运算。

  • MAC(乘加运算)基本上是一次乘法加上一次加法,即 MAC = a * b + c。它算作两个FLOP(一次乘法和一次加法)。


1. 全连接层 FLOPs 计算

现在,我们将创建一个包含三层的简单神经网络,并开始计算所涉及的操作。以下是计算第一层线性层(全连接层)操作数的公式:

  • 对于具有 I 个输入和 O 个输出的全连接层,操作数如下:
    • MACs: I × O
    • FLOPs: 2 × (I × O)(因为每个 MAC 算作两个 FLOP)
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchprofile import profile_macsclass SimpleLinearModel(nn.Module):def __init__(self):super(SimpleLinearModel,self).__init__()self.fc1 = nn.Linear(in_features=10, out_features=20, bias=False)self.fc2 = nn.Linear(in_features=20, out_features=15, bias=False)self.fc3 = nn.Linear(in_features=15, out_features=1, bias=False)def forward(self, x):x = self.fc1(x)x = F.relu(x)x = self.fc2(x)F.relu(x)x = self.fc3(x)return xlinear_model = SimpleLinearModel().cuda()
sample_data = torch.randn(1, 10).cuda()

步骤 1:识别层参数

  • 对于给定的模型,我们定义了三层线性层:
    fc1:10 个输入特征,20 个输出特征
    fc2:20 个输入特征,15 个输出特征
    fc3:15 个输入特征,1 个输出特征

步骤 2:计算 FLOPs 和 MACs

现在,计算每层的 MACs 和 FLOPs:

  • 层 fc1:
    MACs = 10 × 20 = 200
    FLOPs = 2 × MACs = 2 × 200 = 400

  • 层 fc2:
    MACs = 20 × 15 = 300
    FLOPs = 2 × MACs = 2 × 300 = 600

  • 层 fc3:
    MACs = 15 × 1 = 15
    FLOPs = 2 × MACs = 2 × 15 = 30

步骤 3:总结结果

  • 最后,为了找到单个输入通过整个网络的总 MACs 和 FLOPs,我们将所有层的结果相加:
  • 总 MACs = MACs(fc1) + MACs(fc2) + MACs(fc3) = 200 + 300 + 15 = 515
  • 总 FLOPs = FLOPs(fc1) + FLOPs(fc2) + FLOPs(fc3) = 400 + 600 + 30 = 1030

使用 torchprofile 库验证

可以使用 torchprofile 库来验证给定神经网络模型的 FLOPs 和 MACs 计算。以下是具体操作步骤:

macs = profile_macs(linear_model, sample_data)
print(macs)
# -> 515

2. 卷积神经网络(CNNs)

现在,让我们确定一个简单卷积模型的 MACs(乘加运算)和 FLOPs(浮点运算)。由于诸如步幅、填充和核大小等因素,这种计算比我们之前用密集层的例子更复杂一些。然而,我将逐步讲解以便于学习。

class SimpleConv(nn.Module):def __init__(self):super(SimpleConv, self).__init__()self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=1, padding=1)self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1)self.fc =  nn.Linear(in_features=32*28*28, out_features=10)def forward(self, x):x = self.conv1(x)x = F.relu(x)x = self.conv2(x)x = F.relu(x)x = x.view(x.shape[0], -1)x = self.fc(x)return xx = torch.rand(1, 1, 28, 28).cuda()
conv_model = SimpleConv().cuda()

计算卷积操作时的重要考虑因素

在计算卷积核的操作时,必须记住核的通道数量应与输入的通道数量相匹配。例如,如果我们的输入是一个有三个颜色通道的 RGB 图像,则核的维度将是 3x3x3 以匹配输入的三个通道。

为了演示的目的,我们将保持图像大小在整个卷积层中一致。为此,我们将填充和步幅值都设置为1。

第一步:确定层参数

对于给定的模型,我们定义了两个卷积层和一个线性层:

  • conv1: 1 个输入通道,16 个输出通道,核大小为 3
  • conv2: 16 个输入通道,32 个输出通道
  • fc: 32x28x28 个输入特征,10 个输出特征。因为我们的图像在卷积层中没有改变

第二步:计算FLOPs和MACs

现在,计算每层的 MACs 和 FLOPs:

公式是:output_image_size * kernel_shape * output_channels

层conv1:

  • MACs = 28 * 28 * 3 * 3 * 1 * 16 = 1,12,896
  • FLOPs = 2 × MACs = 2 × 1,12,896 = 2,25,792

层conv2:

  • MACs = 28 × 28 * 3 * 3 * 16 * 32 = 3,612,672
  • FLOPs = 2 × MACs = 2 × 3,612,672 = 7,225,344

层fc:

  • MACs = 32 * 28 * 28 * 10 = 250,880
  • FLOPs = 2 × MACs = 2 × 250,880 = 501,760

第三步:汇总结果

最后,为了找到单个输入通过整个网络的总MACs和FLOPs,我们汇总所有层的结果:

  • 总MACs = MACs(conv1) + MACs(conv2) + MACs(fc) = 1,12,896 + 3,612,672 + 250,880 = 3,976,448
  • 总FLOPs = FLOPs(conv1) + FLOPs(conv2) + FLOPs(fc) = 2,25,792 + 7,225,344 + 501,760 = 7,952,896

使用torchprofile库验证操作

macs = profile_macs(conv_model, (x,))
print(macs)
# 输出: 3976448

3. 自注意力模块 (self-attention) FLOPs 计算

在涵盖了线性和卷积层的 MACs 之后,我们的下一步是确定自注意力模块的FLOPs(浮点运算),这是大型语言模型中的一个关键组件。这个计算对于理解这些模型的计算复杂度至关重要。让我们深入探讨。

class SimpleAttentionBlock(nn.Module):def __init__(self, embed_size, heads):super(SimpleAttentionBlock, self).__init__()self.embed_size = embed_sizeself.heads = headsself.head_dim = embed_size // headsassert (self.head_dim * heads == embed_size), "Embedding size needs to be divisible by heads"self.values = nn.Linear(self.embed_size, self.embed_size, bias=False)self.keys = nn.Linear(self.embed_size, self.embed_size, bias=False)self.queries = nn.Linear(self.embed_size, self.embed_size, bias=False)self.fc_out = nn.Linear(heads * self.head_dim, embed_size)def forward(self, values, keys, queries, mask):N = queries.shape[0]value_len, key_len, query_len = values.shape[1], keys.shape[1], queries.shape[1]print(values.shape)values = self.values(values).reshape(N,  self.heads, value_len, self.head_dim)keys = self.keys(keys).reshape(N, self.heads, key_len, self.head_dim)queries = self.queries(queries).reshape(N,  self.heads, query_len, self.head_dim)energy = torch.matmul(queries, keys.transpose(-2, -1))        if mask is not None:energy = energy.masked_fill(mask == 0, float("-1e20"))attention = torch.nn.functional.softmax(energy, dim=3)out = torch.matmul(attention, values).reshape(N, query_len, self.heads * self.head_dim)return self.fc_out(out)

第一步:确定层参数

线性变换

让我们定义一些超参数:

batch_size = 1
seq_len = 10
embed_size = 256

在注意力块中,我们有三个线性变换(用于查询、键和值),以及一个在末尾的线性变换(fc_out)。

输入大小: [batch_size, seq_len, embed_size]

线性变换矩阵: [embed_size, embed_size]

MACs: batch_size × seq_len × embed_size × embed_size

查询、键、值线性变换:

  • 查询变换的MACs = 1 × 10 × 256 × 256 = 655,360
  • 键变换的MACs = 1 × 10 × 256 × 256 = 655,360
  • 值变换的MACs = 1 × 10 × 256 × 256 = 655,360

能量计算: 查询(重塑后)和键(重塑后)点积——一个点积操作。

MACs: batch_size × seq_len × seq_len × heads × head_dim

查询和键的点积

MACs = 1 × 10 × 10 × 8 × 32 [32 因为256/8] = 25,600

从注意力权重和值的计算输出: 注意力权重和值(重塑后)点积——另一个点积操作。

MACs : batch_size × seq_len × seq_len × heads × head_dim

注意力和值的点积

MACs = 1 × 10 × 10 × 8 × 32 = 25,600

全连接输出(fc_out)

MACs: batch_size × seq_len × heads × head_dim × embed_size

MACs = 1 × 10 × 8 × 32 × 256 = 655,360

第二步:汇总结果

总 MACs = MACs(conv1) + MACs(conv2) + MACs(fc)= 655,360 + 655,360 + 655,360 + 25,600 + 25,600 + 655,360 = 2,672,640

总 FLOPs = 2 × 总MACs = 5,345,280

使用torchprofile库验证操作

# 创建模型实例
model = SimpleAttentionBlock(embed_size=256, heads=8).cuda()# 生成一些样本数据(5个序列的批次,每个长度为10,嵌入大小为256)
values = torch.randn(1, 10, 256).cuda()
keys = torch.randn(1, 10, 256).cuda()
queries = torch.randn(1, 10, 256).cuda()# 简化起见,没有掩码
mask = None# 使用样本数据进行前向传递
macs = profile_macs(model, (values, keys, queries, mask))
print(macs)
# -> 2672640

总结:按不同批次大小缩放MACs和FLOPs

在我们的计算中,我们主要考虑了批次大小为 1。然而,按更大的批次大小缩放 MACs 和 FLOPs 是很简单的。

要计算批次大小大于 1 的 MACs 或 FLOPs,您可以简单地将批次大小 1 得到的总 MACs 或 FLOPs 乘以所需的批次大小值。此缩放允许您估计神经网络模型的各种批次大小的计算需求。

请记住,结果将直接线性缩放批次大小。例如,如果您的批次大小为 32,您可以通过将批次大小为 1 的值乘以 32 来获得 MACs 或 FLOPs。


原文链接: https://medium.com/@pashashaik/a-guide-to-hand-calculating-flops-and-macs-fa5221ce5ccc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/869361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行列视(RCV)是否支持批量共享和自定义共享设置,以提高共享效率?

行列视(RCV)确实支持批量共享和自定义共享设置,以提高共享效率。以下是根据参考文章信息,对RCV在共享功能方面的详细说明: 1. 批量共享: - RCV系统支持大规模数据或报表的共享,这意味着用户可以…

Echarts实现github提交记录图

最近改个人博客&#xff0c;看了github的提交记录&#xff0c;是真觉得好看。可以移植到自己的博客上做文章统计 效果如下 代码如下 <!DOCTYPE html> <html lang"en" style"height: 100%"><head><meta charset"utf-8"> …

240709_昇思学习打卡-Day21-文本解码原理--以MindNLP为例

240709_昇思学习打卡-Day21-文本解码原理–以MindNLP为例 今天做根据前文预测下一个单词&#xff0c;仅作简单记录及注释。 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积 &#x1d44a;_0:初始上下文单词序列&#x1d447;: 时间步当生成EOS标签时&a…

企业级网关设计

tips&#xff1a;本文完全来源于卢泽龙&#xff01;&#xff01;&#xff01; 一、Gateway概述 1.1设计目标 1.2gateway基本功能 中文文档参考&#xff1a;https://cloud.tencent.com/developer/article/1403887?from15425 三大核心&#xff1a; 二、引入依赖和yaml配置…

Interpretability 与 Explainability机器学习

在机器学习的范畴中&#xff0c;“Interpretability”&#xff08;可解释性&#xff09;和“Explainability”&#xff08;可解释性&#xff09;尽管在含义上有重叠部分&#xff0c;但仍存在一些微妙的差异和重点的不同。 “Interpretability”主要强调模型自身的结构和运作方式…

如何制定python编码规范,符合PEP 8

嗨&#xff0c;我是兰若&#xff0c;今天在检查代码的时候&#xff0c;发现了一个很严重但是大家平时却不重视的问题&#xff0c;就是编码格式规范&#xff0c;很多人在平时写python脚本的时候&#xff0c; 总是胡乱发挥&#xff0c;想怎么命名就怎么命名&#xff0c;&#xf…

如何在 PostgreSQL 中确保数据的异地备份安全性?

文章目录 一、备份策略1. 全量备份与增量备份相结合2. 定义合理的备份周期3. 选择合适的备份时间 二、加密备份数据1. 使用 PostgreSQL 的内置加密功能2. 使用第三方加密工具 三、安全的传输方式1. SSH 隧道2. SFTP3. VPN 连接 四、异地存储的安全性1. 云存储服务2. 内部存储设…

人话学Python-基础篇-字符串

一&#xff1a;字符串的定义 在Python中使用引号来定义。不论是单引号还是双引号。 str1 Hello World str2 "Hello World" 二&#xff1a;字符串的访问 如果我们要取出字符串中单独的字符&#xff0c;需要使用方括号来表示取得的位置。如果要取出字符串的子串&…

OmniParse:AI+PDF工具与知识库的开源革新

在AI技术的推动下,非结构化数据的解析与结构化已成为提升数据处理效率的关键。OmniParse,一个开源框架,为开发者和企业提供了强大的数据预处理能力,尤其适合用于构建AI+PDF工具和知识库产品。 一、核心功能:全能数据解析 数据解析与结构化:OmniParse能够处理文档、表格…

一元线性回归代码

一元线性回归代码 %% 代码说明 % 该程序为一元线性回归的实现&#xff0c;仅供学习参考&#xff0c;切勿抄袭 % 输入&#xff1a; % X&#xff1a;为第一个变量的已知值&#xff0c;是一个列向量 % Y&#xff1a;为第二个变量的已知值&#xff0c;是一个列向量 % …

原创作品—数据可视化大屏

设计数据可视化大屏时&#xff0c;用户体验方面需注重以下几点&#xff1a;首先&#xff0c;确保大屏信息层次分明&#xff0c;主要数据突出显示&#xff0c;次要信息适当弱化&#xff0c;帮助用户快速捕捉关键信息。其次&#xff0c;设计应直观易懂&#xff0c;避免复杂难懂的…

53-3 内网代理5 - frp搭建二级代理

前提:53-2 内网代理4 - frp搭建socks一级代理-CSDN博客 扩展知识: VPN代表虚拟专用网络(Virtual Private Network)。这是一种通过公共网络(如互联网)在私人网络之间建立安全连接的技术。VPN允许用户通过加密和其他安全性手段,安全地访问远程资源或传输数据,就像直接连…

前端javascript中的排序算法之冒泡排序

冒泡排序&#xff08;Bubble Sort&#xff09;基本思想&#xff1a; 经过多次迭代&#xff0c;通过相邻元素之间的比较与交换&#xff0c;使值较小的元素逐步从后面移到前面&#xff0c;值较大的元素从前面移到后面。 大数据往上冒泡&#xff0c;小数据往下沉&#xff0c;也就是…

Contest3630 - 2024小学期程序设计实训竞-赛-班专题训练四(动态规划专题)

问题A&#xff1a;不能整除 题目描述 给你一个长度为 N N N的整数序列 a i a_i ai​,找出满足下列条件的 i ( 1 ≤ i ≤ N ) i(1\leq i \leq N) i(1≤i≤N)的个数&#xff1a; 对于每个 j j j并且 1 ≤ j ≤ N , i ≠ j 1\leq j \leq N, i \neq j 1≤j≤N,ij&#xff0c; a …

构建工具和自动化:Maven、Gradle及CI/CD实践

引言 在现代软件开发过程中&#xff0c;自动化构建和持续集成/持续部署&#xff08;CI/CD&#xff09;是提高开发效率、保证代码质量的重要实践。构建工具如Maven和Gradle&#xff0c;因其强大的依赖管理和自动化构建功能&#xff0c;已成为Java开发中不可或缺的一部分。本文将…

大语言模型垂直化训练技术与应用

在人工智能领域&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已经成为推动技术进步的关键力量&#xff0c;垂直化训练技术逐渐成为研究的热点&#xff0c;它使得大模型能够更精准地服务于特定行业和应用场景。本文结合达观数据的分享&#xff0c…

tomcat 项目迁移,无法将项目作为服务service启动

背景 测试服务器需要迁移到正式服务器上&#xff0c;为了方便省事&#xff0c;将测试服务器上的一些文件直接复制到正式服务器 问题 使用startup启动项目之后&#xff0c;可以直接使用使用tomcat9w启动&#xff0c;或者作为服务service启动的时候&#xff0c;显示无法访问到资源…

AGE Cypher 查询格式

使用 ag_catalog 中的名为 cypher 的函数构建 Cypher 查询&#xff0c;该函数返回 Postgres 的记录集合。 Cypher() Cypher() 函数执行作为参数传递的 Cypher 查询。 语法&#xff1a;cypher(graph_name, query_string, parameters) 返回&#xff1a; A SETOF records 参…

自动驾驶事故频发,安全痛点在哪里?

大数据产业创新服务媒体 ——聚焦数据 改变商业 近日&#xff0c;武汉城市留言板上出现了多条关于萝卜快跑的投诉&#xff0c;多名市民反映萝卜快跑出现无故停在马路中间、高架上占最左道低速行驶、转弯卡着不动等情况&#xff0c;导致早晚高峰时段出现拥堵。萝卜快跑是百度 A…

北方法学期刊

《北方法学》杂志是经国家新闻出版总署批准&#xff0c;面向国内外公开出版发行的专业法学学术期刊&#xff0c;双月刊&#xff0c;逢单月1&#xff15;日出版。国家新闻出版总署批复《北方法学》的办刊宗旨为&#xff1a;“繁荣法学研究&#xff0c;服务法制建设&#xff0c;加…