手算神经网络MAC和FLOP

news2024/9/21 14:50:20

在本文中,我们将深入探讨神经网络背景下的 MAC(乘法累加运算)和 FLOP(浮点运算)概念。通过学习如何使用笔和纸手动计算这些内容,你将对各种网络结构的计算复杂性和效率有基本的了解。

这是 colab 笔记本中一个功能齐全的示例。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - AI模型在线查看 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、为什么要计算MAC和FLOP

首先让我们看下MAC和FLOP的定义。

  • FLOP:FLOP(浮点运算)可视为加法、减法、乘法或除法运算。
  • MAC:MAC(乘法累加)运算本质上是乘法后跟加法,即 MAC = a * b + c。它算作两个 FLOP(一个用于乘法,一个用于加法)。

解 MAC 和 FLOP 不仅仅是一项学术活动;它是优化神经网络性能和效率的关键组成部分。它有助于设计计算效率高且有效的模型,最终在训练和推理阶段节省时间和资源。

  • 资源效率。了解 FLOP 有助于估计神经网络的计算成本。通过优化 FLOP 的数量,可以减少训练或运行神经网络所需的时间。
  • 内存效率。MAC 操作通常决定网络的内存使用量,因为它们与网络中的参数和激活数量直接相关。减少 MAC 有助于提高网络内存效率。
  • 功率效率。FLOP 和 MAC 操作都会影响运行神经网络的硬件的功耗。通过优化这些指标,可以潜在地降低运行网络的能耗,这在移动和嵌入式设备中尤为重要。
  • 修剪和量化。了解 FLOP 和 MAC 有助于通过修剪(删除不必要的连接)和量化(降低权重和激活的精度)等技术优化神经网络,旨在降低计算和内存成本。
  • 模型之间的比较。FLOP 和 MAC 提供了一种比较不同模型的计算复杂度的方法,这可以作为选择特定应用模型的标准。
  • 硬件基准测试。这些指标还可用于对不同硬件平台在运行神经网络时的性能进行基准测试。
  • 实时应用。对于实时应用,尤其是在计算资源有限的边缘设备上,理解和优化这些指标对于确保网络能够在应用的时间限制内运行至关重要。
  • 电池寿命。在电池供电的设备中,降低神经网络的计算成本(从而降低能耗)有助于延长电池寿命。
  • 设计新算法。研究人员可以在开发新算法或神经网络架构时使用这些指标作为指导方针,旨在提高计算效率而不牺牲准确性。

2、神经网络层的MAC和FLOP计算

接下来让我们计算浮点运算或乘法累加运算的数量,以了解每层的计算复杂度。

2.1 全连接层(密集层)

现在,我们将创建一个具有 3 层的简单神经网络,并开始计算所涉及的运算。以下是计算第一线性层(即全连接(或密集)层)中的运算的公式:

对于具有 I 个输入和 O 个输出的全连接层,运算数量如下:

  • MAC:I × O
  • FLOP:2 × (I × O)(因为每个 MAC 算作两个 FLOP)
class 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 x

linear_model = SimpleLinearModel().cuda()
sample_data = torch.randn(1, 10).cuda()
步骤 1:确定层参数对于给定的模型,我们有三个线性层,定义为:
  • fc1:10 个输入特征,20 个输出特征
  • fc2:20 个输入特征,15 个输出特征
  • fc3:15 个输入特征,1 个输出特征
步骤 2:计算 FLOP 和 MAC 现在,计算每个层的 MAC 和 FLOP:

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

我们可以使用 torchprofile 库来验证给定神经网络模型的 FLOP 和 MAC 计算。操作方法如下:

macs = profile_macs(linear_model, sample_data)
print(macs)

#515

2.2 卷积神经网络 (CNN)

现在,让我们确定一个简单的卷积模型的 MAC(乘法累加)和 FLOP(浮点运算)。这个计算可能比我们之前使用密集层的示例更复杂一些,主要是由于步幅、填充和内核大小等因素。不过,我会将其分解,以便于我们学习。

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 x

x = torch.rand(1, 1, 28, 28).cuda()
conv_model = SimpleConv().cuda()

计算卷积运算的重要注意事项:

  • 计算卷积核的运算时,务必记住核中的通道数应与输入中的通道数相匹配。例如,如果我们的输入是具有三个颜色通道的 RGB 图像,则核的尺寸将为 3x3x3,以说明输入的三个通道。
  • 为了演示的目的,我们将在整个卷积层中保持一致的图像大小。为此,我们将填充值和步幅值都设置为 1。
步骤 1:识别层参数

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

  • conv1:1 个输入通道,16 个输出通道,核大小为 3
  • conv2:16 个输入通道,32 个输出通道
  • fc:322828 个输入特征,1 个输出特征。因为我们的图像在卷积层中没有改变
步骤 2:计算 FLOP 和 MAC 现在,计算每个层的 MAC 和 FLOP:

公式为 output_image_size * kernel shape * output_channels

Layer conv1:

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

Layer conv2:

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

Layer fc:

  • MACs = 32 * 28 * 28 * 10 = 250,880
  • FLOPs = 2 × MACs = 2 × 15 = 501,760
步骤 3:总结结果最后,为了找到单个输入通过整个网络的 MAC 和 FLOP 总数,我们将所有层的结果相加:
  • 总 MAC = MACs(conv1) + MACs(conv2) + MACs(fc) = 1,12,896 + 3,612,672 + 250,880 = 39,76,448
  • 总 FLOPs = FLOPs(fc1) + FLOPs(fc2) + FLOPs(fc3) = 2,25,792 + 7,225,344 + 501,760 = 7,952,896

使用 torchprofile 库验证操作:

macs = profile_macs(conv_model,(x,))
print(macs)

#3976448

2.3 自注意力模块

在介绍了线性层和卷积层的 MAC 之后,我们的下一步是确定自注意力模块的 FLOP(浮点运算),这是大型语言模型中的关键组件。此计算对于理解此类模型的计算复杂性至关重要。让我们深入研究一下。

class SimpleAttentionBlock(nn.Module):
    def __init__(self, embed_size, heads):
        super(SimpleAttentionBlock, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads

        assert (
            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)
步骤 1:识别层参数

线性变换

让我们定义 hyper_params

  • batch_size = 1
  • seq_len = 10
  • embed_size = 256

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

  • 输入大小:[batch_size, seq_len, embed_size]
  • 线性变换矩阵:[embed_size, embed_size]
  • MAC:batch_size×seq_len×embed_size×embed_size

查询、键、值线性变换:

  • 查询变换的MAC = 1 * 10 * 256 * 256 = 6,55,360
  • 键变换的MAC = 1 * 10 * 256 * 256 = 6,55,360
  • 值变换的MAC = 1 * 10 * 256 * 256 = 6,55,360

能量计算:查询(重塑)点键(重塑)——点积运算。

  • Macs:batch_size×seq_len×seq_len×heads×head_dim

查询和键点积

  • MACS = 1 * 10 * 10 * 32 [32 因为 256/8 除以 heads] = 25,600

注意权重和值计算的输出:注意权重点值(重塑)——另一个点积运算。

  • Macs:batch_size×seq_len×seq_len×heads×head_dim

注意力和价值点积

  • Macs = 1 * 10 * 10 * 32 = 25,600

全连接输出 (fc_out)

  • Macs:batch_size×seq_len×heads×head_dim×embed_size
  • Macs = 1 * 10 * 8 * 32 * 256 = 6,55,360
步骤 2:总结结果
  • 总 MACs = MACs(conv1) + MACs(conv2) + MACs(fc) = 6,55,360 + 6,55,360 + 6,55,360 + 25,600 + 25,600 + 6,55,360 = 26,72,640
  • 总计FLOPs = 2 * 总 MAC = 53,45,280

使用 torchprofile 库验证操作:

# Create an instance of the model
model = SimpleAttentionBlock(embed_size=256, heads=8).cuda()

# Generate some sample data (batch of 5 sequences, each of length 10, embedding size 256)
values = torch.randn(1, 10, 256).cuda()
keys = torch.randn(1, 10, 256).cuda()
queries = torch.randn(1, 10, 256).cuda()

# No mask for simplicity
mask = None
# Forward pass with the sample data
macs = profile_macs(model, (values, keys, queries, mask))
print(macs)

#2672640

3、结束语

在整个计算过程中,我们主要考虑批次大小为 1。但是,需要注意的是,针对较大批次大小缩放 MAC 和 FLOP 非常简单。

要计算批次大小大于 1 的 MAC 或 FLOP,只需将批次大小为 1 时获得的总 MAC 或 FLOP 乘以所需的批次大小值即可。这种缩放允许你估算神经网络模型中各种批次大小的计算要求。

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


原文链接:手算神经网络MAC和FLOP - BimAnt

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

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

相关文章

使用 Python 和 SQL 自动将 ETL 传输到 SFTP 服务器

了解如何在 Windows 上自动执行从 PostgreSQL 数据库到远程服务器的日常数据传输过程 欢迎来到雲闪世界。将文件从一个位置传输到另一个位置的过程显然是自动化的完美选择。重复执行这项工作可能令人望而生畏,尤其是当您必须对几组数据执行整个 ETL(提取…

神经网络模型剪枝快速指南

模型剪枝(Model Pruning)是指从深度学习神经网络模型中删除不重要的参数,以减小模型大小并实现更高效的模型推理。通常,只剪枝参数的权重,而不影响偏差。偏差的剪枝往往有更明显的缺点。 非结构化剪枝期间权重如何归零…

书生.浦江大模型实战训练营——(十)Lagent 自定义你的 Agent 智能体

最近在学习书生.浦江大模型实战训练营,所有课程都免费,以关卡的形式学习,也比较有意思,提供免费的算力实战,真的很不错(无广)!欢迎大家一起学习,打开LLM探索大门&#xf…

【9月持续更新】国内ChatGPT-4中文镜像网站整理~

以前我也是通过官网使用,但是经常被封号,就非常不方便,后来有朋友推荐国内工具,用了一阵之后,发现:稳定方便,用着也挺好的。 最新的 GPT-4o、4o mini,可搭配使用~ 1、 最新模型科普&…

遗传算法整合talib技术分析算子做因子挖掘,比如ADX, 阿隆指标等

“ 原创内容第631篇,专注量化投资、个人成长与财富自由” 七年实现财富自由 七年,经过十万小时刻意练习,足矣在任何领域成为专家。 七年,成为自己的财富管理专家。 七年,实现财富自由。 1512篇原创内容 公众号 星球…

怎样恢复微信聊天记录?4个巧妙方法,速来学习!

微信不仅是我们的通讯工具,更是情感的载体,每一句“早安”与“晚安”都藏着不为人知的温柔。但有时候这些珍贵的聊天记录却会离家出走。怎么恢复微信聊天记录?就成为我们需要解答的难题。 别担心,今天,小编我将化身为…

PostgresSQL--基于Kubernetes部署PostgresSQL

基于docker 拉取镜像,这个镜像是我自己的阿里云镜像,拉取的国外的镜像。 docker pull registry.cn-hangzhou.aliyuncs.com/qiluo-images/postgres:latest创建 dolphinscheduler 命名空间,本文命名空间是使用的dolphinscheduler 使用 kubectl…

基于元神操作系统编写(FPU)数学计算程序

1. 背景 数学计算已经成为计算机的主要工作之一,尤其是实数运算,在人工智能时代更是普遍存在,神经网络中的绝大部分参数都用的实数。 2. 方法 (1)FPU运算 计算机中的实数运算是通过数学协处理器FPU完成的&#xff…

黑神话悟空配置要求:CPU/内存/显卡/存储和系统最低限制

玩《黑神话:悟空》对电脑配置有什么要求?至少需要i5处理器、16G内存、GTX 1060显卡、130G空闲磁盘空间,没有高配电脑怎么办?码笔记整理详细配置如下: CPU处理器:64位处理器,CPU选择Intel Core …

数据防泄密知识集锦丨八个实用数据防泄露软件,你知道吗

数据已成为企业的核心资产。 然而,随着网络威胁的日益严峻,数据泄露事件频发,给企业带来了巨大的经济损失和声誉风险。 为了有效保护企业数据的安全性和保密性,各种数据防泄露软件应运而生。 本文将为您介绍八个实用的数据防泄露…

ROS机器人专用云台相机防抖摄像头

【告别模糊】机器人专用摄像头,为您的视觉算法保驾护航 产品概述 Autolabor C1专为机器人设计的高性能摄像头,即使在没有减震装置或不平坦的路面上,也能提供清晰稳定的图像。它拥有先进的主动式机械防抖和数字ISP防抖技术,图像效…

基于太阳能供电的水情监测站设计(论文+源码+图纸)

1.总体方案设计 根据水情监测站系统的实际应用需求,从硬件电路以及软件程序两个方面展开系统设计。按照系统设计功能以及功能选型的结果,制定了如图2.11所示的系统总体框图。系统采用STM32单片机作为控制器,在传感器检测模块中包括的DS18B20…

netty编程之使用ChannelOutboundHandler对write出去的消息做不同处理

写在前面 源码 。 在进行网络编程的时候,不可避免的需要对write出去的消息做一些处理,比如脱敏,增加统一数据等。而netty提供了ChannelOutboundHandler来允许我们拦截消息从而可以对消息进行处理。对应的接口是io.netty.channel.ChannelHand…

Python:win10下一种不用编译,直接下载二进制依赖的方法

python依赖的安装,在win环境下, 有些包还是比较麻烦, 经常编译失败, 我曾发帖讨论过多次,有帖为证!点此进入! https://blog.csdn.net/weixin_62598385/article/details/135945383 win下的Pyth…

基于vue.js和node.js的酒坊销售网站的设计与实现---附源码98047

目 录 摘要 1 绪论 1.1研究背景与意义 1.3研究内容 1.4论文结构与章节安排 2 酒坊销售网站分析 2.1 可行性分析 2.2系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例…

实战分享:利用两大在线平台实现自动化数据采集的技巧

本文将深入探讨如何运用两大主流在线平台,通过实战案例分享,揭示自动化数据采集的高效技巧。无需编程基础,也能快速掌握跨平台数据抓取秘籍,助力企业和个人提升市场竞争力与决策效率。 正文 在大数据时代背景下,信息…

ESP8266通过WiFiManager实现Web配网

背景 一个项目中使用到了一款压力传感器,需要通过单片机实现数据的采集并发送到远程的服务器上,单片机采用的时ESP8266,通过WiFiManager实现局域网配置,以及远端服务器IP地址和服务端口的配置。发布此文章记录一下使用WiFiManager实现配网的方法。 程序流程图 示例代码 …

如何下载GB2312字体,免费

因为写文章需要用到,然后wps里面这个是收费的,所以我就去找了免费的,现在分享给大家。 因为我看网上很多都是给一个网址,有些网址已经坏了,所以我这里给一下我的链接 链接:https://pan.baidu.com/s/1wiyF…

如何用Java SpringBoot+Vue构建高效的产品订单管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…

python 爬虫,东方网 上海新闻, 简单数据分析

起因: 本来想去市区玩玩,结果搜到一些相关的新闻,所以就想爬取新闻网站… 1. 爬虫部分 import os import csv import time import requests""" # home: https://sh.eastday.com/ # 1. 标题, url, 来源,时间 &qu…