ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

深度学习模型FLOPs计算全解析:从原理到工程实践

深度学习模型FLOPs计算全解析:从原理到工程实践 1. 项目概述为什么我们需要关心FLOPs在深度学习的项目里尤其是当你开始从跑通Demo转向模型优化、部署上线时总会遇到一个绕不开的指标FLOPs。我第一次被问到“你这个模型有多少FLOPs”的时候也是一头雾水心想这跟“FLOPS”每秒浮点运算次数衡量硬件算力的单位不是一回事吗后来在模型压缩、移动端部署上踩过几次坑才明白搞清FLOPs并会计算它是模型工程师从“炼丹”走向“工程”的关键一步。简单来说FLOPs注意小写‘s’是floating point operations的缩写指的是模型完成一次前向传播或一次推理所需要的浮点运算次数。它是一个衡量模型计算复杂度或“计算量”的指标。而FLOPS大写‘S’是floating point operations per second的缩写则是衡量硬件如CPU、GPU计算速度的单位比如“这颗GPU的峰值算力是10 TFLOPS”意思是它每秒能进行10万亿次浮点运算。一个关乎模型本身“有多重”一个关乎硬件“跑多快”两者天差地别但名字又如此相似混淆它们是新手上路最常见的“坑”之一。那么我们为什么非得关心FLOPs呢从我实际做移动端AI应用和模型轻量化的经验来看主要有三个核心场景模型选型与对比当你在两个精度相近的模型间犹豫时FLOPs是关键的决策依据。一个FLOPs更低的模型意味着在相同硬件上推理更快、耗电更少。在资源受限的边缘设备如手机、摄像头上这直接决定了应用是否可行。性能瓶颈分析通过计算模型中各层的FLOPs你可以像做性能剖析Profiling一样精准定位到计算“热点”。可能80%的计算量都集中在某几个卷积层那么优化如剪枝、量化就应该优先针对这些层做到有的放矢。学术研究与创新在发表论文或设计新模型结构如轻量化网络MobileNet、ShuffleNet时FLOPs是和准确率Accuracy并列的核心评价指标。它回答了“你的模型创新在计算效率上带来了多少提升”这个问题。因此无论你是算法研究员、工程部署工程师还是刚入门的学习者理解并掌握FLOPs的计算都是深入理解模型内部运作、进行高效开发和优化的必备技能。下面我就结合具体的网络层拆解FLOPs的计算方法并分享一些工具使用和实际分析中的心得。2. FLOPs核心计算原理与逐层拆解计算FLOPs本质上是对模型前向传播中所有涉及浮点数乘加运算的计数。最基础的运算单元是乘加运算Multiply-Add, MA。在深度学习中一次乘法和一次加法常被绑定在一起视为一次操作但值得注意的是有些计算库或论文中将一次乘加计为1个FLOP而另一些则将其计为2个FLOP乘法1次加法1次。目前社区更常见的约定是1次乘加运算 2次浮点运算。我们在后续计算和工具使用时需要留意这个差异。为了统一本文后续均采用1 MAC 2 FLOPs的约定进行阐述。2.1 全连接层的FLOPs计算全连接层是理解FLOPs计算最好的起点。假设一个全连接层输入向量维度为M输出向量维度为N。对于输出的每一个元素都需要进行M次乘法权重乘以输入和M次加法累加求和。所以计算一个输出元素需要2M次浮点运算。该层共有N个输出元素。因此该全连接层的总FLOPs为FLOPs_fc N * (2M) 2 * M * N注意这里通常忽略了偏置项bias的加法。如果考虑偏置每个输出元素会额外增加一次加法总FLOPs约为2 * M * N N。当M很大时偏置项的影响可以忽略不计。许多计算工具默认不计入偏置。实操心得全连接层是FLOPs的“大户”尤其是在分类网络的最后几层。例如ResNet-50最后一个全连接层1000个类别输入维度是2048其FLOPs高达2 * 2048 * 1000 4.1M。这也是为什么在轻量化网络中常用全局平均池化GAP替代全连接层因为GAP几乎不引入额外的FLOPs。2.2 卷积层的FLOPs计算卷积层是CNN中FLOPs的主要来源计算也稍复杂。我们定义以下参数H_in, W_in, C_in: 输入特征图的高、宽、通道数。K_h, K_w: 卷积核的高和宽。C_out: 输出通道数即卷积核的个数。H_out, W_out: 输出特征图的高和宽由输入尺寸、Padding、Stride等决定。计算分两步理解一次卷积操作在一个空间位置用一个C_in通道的卷积核与输入对应位置的局部区域做逐通道相乘并求和。这需要K_h * K_w * C_in次乘法和同样次数的加法减1次严格说是K_h*K_w*C_in - 1次加法但通常近似。所以一次卷积操作的FLOPs约为2 * K_h * K_w * C_in。全部卷积操作输出特征图有H_out * W_out个空间位置并且有C_out个不同的卷积核输出通道。因此总的FLOPs为FLOPs_conv 2 * K_h * K_w * C_in * H_out * W_out * C_out为什么这么算你可以想象为每个输出特征图上的一个像素点都是由C_out个卷积核分别与输入的一个局部区域进行三维立体宽、高、通道的乘加运算得到的。这个公式清晰地揭示了计算量与卷积核大小、输入输出通道数以及特征图尺寸的乘积关系。一个具体例子输入为224x224x3的图片经过一个3x3卷积输出通道为64步幅为1填充为1保证输出尺寸不变。则H_out W_out 224。FLOPs 2 * 3 * 3 * 3 * 224 * 224 * 64 ≈ 173.4M。这是一个非常典型的计算量。2.3 其他常见层的FLOPs计算池化层最大/平均池化池化操作通常不涉及乘加运算主要是比较或取平均。虽然有一些加法或比较操作但其计算量远小于卷积层在粗略估算模型FLOPs时常常被忽略。精确计算时平均池化可视为除法的加法但FLOPs占比极小。激活层ReLU, Sigmoid等像ReLU这样的激活函数max(0, x)只涉及简单的比较和赋值操作不涉及浮点乘加因此通常不计入FLOPs。Sigmoid、Tanh等复杂激活函数涉及指数运算计算成本较高但在现代网络中如使用ReLU其影响通常也不单独计算。批量归一化层BatchNorm在训练时BN层需要计算均值和方差涉及加法和乘法。但在推理阶段BN层通常会被“折叠”进其前面的卷积层或全连接层的权重和偏置中因此不增加额外的FLOPs。这是模型部署时的一个重要优化点。跳跃连接Skip Connection如ResNet中的加法操作需要将两个张量相加。这会产生H*W*C次浮点加法。虽然计算量相对较小但在精确计算时应当计入。例如一个56x56x256的特征图做逐元素相加会产生约56*56*256 0.8M次浮点运算0.4M FLOPs如果按1加法1 FLOP算。3. 实战手动计算与工具使用指南理解了原理我们进入实战环节。在实际工作中我们很少徒手计算整个网络的FLOPs但掌握手动计算局部的能力有助于理解和验证工具结果。3.1 手动计算一个小型CNN模块假设我们有一个简单的CNN模块Conv2d(3, 16, kernel_size3, stride1, padding1) - ReLU - MaxPool2d(2)。输入图片为32x32x3。卷积层K_h3, K_w3, C_in3, C_out16由于stride1, padding1输出尺寸H_out W_out 32。FLOPs_conv 2 * 3 * 3 * 3 * 32 * 32 * 16 2 * 9 * 3 * 1024 * 16 2 * 9 * 3 * 16384 884,736。ReLU层忽略不计。最大池化层忽略不计。 所以这个模块的FLOPs约为0.88M。你可以看到即使是一个很小的卷积在输入尺寸稍大的情况下计算量也能达到百万级别。3.2 使用流行工具自动计算FLOPs手动计算整个网络是不现实的。下面介绍两个最常用的Python工具库并分享我的使用心得。工具一thop(PyTorch)thop库简单直接是PyTorch用户的常用选择。import torch import torch.nn as nn from thop import profile, clever_format # 定义一个简单网络 class SimpleNet(nn.Module): def __init__(self): super(SimpleNet, self).__init__() self.conv1 nn.Conv2d(3, 16, 3, 1, 1) self.pool nn.MaxPool2d(2) self.fc nn.Linear(16*16*16, 10) # 假设池化后是16x16 def forward(self, x): x self.pool(torch.relu(self.conv1(x))) x x.view(-1, 16*16*16) x self.fc(x) return x model SimpleNet() input torch.randn(1, 3, 32, 32) # 批大小1 flops, params profile(model, inputs(input,)) flops, params clever_format([flops, params], %.3f) print(fFLOPs: {flops}, Params: {params})注意事项thop默认使用1 MAC 2 FLOPs的计数方式。它的clever_format函数能自动将数字转换为“G”、“M”等易读格式。需要确保你的输入张量是合法的形状否则会报错。它有时会对某些特殊算子如深度可分离卷积的支持不够细致需要留意。工具二fvcore(Facebook Research)fvcore是Facebook开源的更强大的分析库支持PyTorch和TensorFlow通过单独的tfprof。from fvcore.nn import FlopCountAnalysis, parameter_count model SimpleNet() input torch.randn(1, 3, 32, 32) flops FlopCountAnalysis(model, input) print(Total FLOPs (G):, flops.total() / 1e9) print(Detailed FLOPs by operator:\n, flops.by_operator()) print(Detailed FLOPs by module:\n, flops.by_module())fvcore的强大之处在于它能提供按算子类型by_operator和按模型子模块by_module的详细分解。这对于性能瓶颈分析至关重要。例如你可以一眼看出是Conv2d还是Linear占用了大部分计算资源。工具对比与选择建议特性thopfvcore易用性极高一行代码出结果较高接口稍多但清晰详细度提供总FLOPs和参数量提供总FLOPs、参数量并支持分层/分算子详细统计定制性较弱较强可以注册自定义算子的FLOPs计算规则推荐场景快速获取模型整体计算量进行粗略对比需要深入分析模型内部计算分布定位瓶颈我个人在项目中的习惯是初期模型选型用thop快速筛选当需要对一个候选模型进行深度优化时必定使用fvcore进行详细剖析。3.3 计算结果的解读与常见陷阱拿到FLOPs数字后解读它需要注意以下几点单位与换算工具输出的通常是原始数字如1769472。我们需要将其转换为1.77 MFLOPs百万或1.77 GFLOPs十亿。1 GFLOPs 10^9 FLOPs。仅前向传播FLOPs通常只计算一次前向传播推理。训练时的计算量大约是前向传播的2-3倍因为还包括反向传播梯度计算。反向传播的FLOPs与前向传播大致在同一数量级。动态结构与条件分支如果你的模型有动态计算图如基于输入内容的条件分支那么FLOPs可能不是固定的。工具给出的通常是针对你提供的示例输入的计算量。FLOPs ≠ 实际推理时间这是一个最重要的认知陷阱。FLOPs是理论计算量而实际推理时间还受众多因素影响内存访问成本如果模型计算量不大但需要在内存中频繁搬运大量数据如特征图那么实际瓶颈可能在内存带宽Memory Bandwidth上而非算力。这就是“内存墙”问题。算子优化程度深度学习框架如PyTorch、TensorRT对算子的实现优化水平不同。一个FLOPs更低的模型如果其算子没有被高度优化可能跑得比一个FLOPs高但算子优化好的模型更慢。硬件特性GPU有强大的并行计算能力但对某些特殊操作如分组卷积Group Conv的支持效率可能不同。ARM CPU上的计算特点也与GPU迥异。因此FLOPs是一个重要的参考指标但绝非唯一标准。在最终决策前必须在目标硬件上进行实际的端到端速度测试Latency Benchmark。4. 高级话题FLOPs在模型优化中的应用与局限掌握了基础计算后我们可以更深入地探讨FLOPs如何指导模型设计以及它的局限性。4.1 如何根据FLOPs指导模型轻量化设计轻量化模型设计的核心思想是在保持精度的前提下显著降低FLOPs和参数量。主流技术背后都有其降低FLOPs的数学逻辑深度可分离卷积这是MobileNet的核心。它将标准卷积分解为深度卷积逐通道卷积和逐点卷积1x1卷积。对于一个标准卷积其FLOPs为2 * K*K * C_in * H_out * W_out * C_out。深度可分离卷积的FLOPs为深度卷积2 * K*K * C_in * H_out * W_out * 1逐点卷积2 * 1*1 * C_in * H_out * W_out * C_out总和约为2 * H_out * W_out * C_in * (K*K C_out)与标准卷积相比计算量降低了大约K*K * C_out / (K*K C_out)倍。当C_out较大时如256这个降低倍数接近K*K9倍对于3x3卷积。模型剪枝通过移除网络中不重要的连接权重或整个通道直接减少参与计算的权重数量从而降低FLOPs。例如将一个C_in256, C_out512的卷积层通过通道剪枝将输入通道减为200输出通道减为400那么FLOPs将大致按比例(200/256)*(400/512) ≈ 0.61下降。知识蒸馏用一个庞大的“教师模型”指导一个轻量级“学生模型”的训练。学生模型本身结构小巧FLOPs低但通过模仿教师模型的输出或中间特征获得接近教师模型的精度。FLOPs的降低来自于学生模型本身的结构设计。实操心得在实际轻量化项目中我通常会先用FLOPs和参数量做第一轮筛选挑出几个候选结构如MobileNetV3, EfficientNet-Lite。然后务必在目标硬件例如一款具体的手机芯片上测试它们的真实推理延迟和功耗。经常遇到的情况是A模型FLOPs比B模型低20%但实际推理速度却更慢原因可能就是B模型的算子更适合该硬件的计算单元。4.2 FLOPs的局限性它没有告诉你什么过度依赖FLOPs会带来误导我们必须清楚它的边界忽略内存访问如前所述这是最大的局限。一个典型的例子是激活函数和逐元素相加。它们的FLOPs极低但会产生大量的内存读写。如果网络中有很多跳跃连接如DenseNet虽然FLOPs增加不多但内存访问量会剧增可能成为速度瓶颈。忽略并行度FLOPs是一个标量总和它不反映计算的并行性。两个FLOPs相同的模型一个计算高度并行另一个计算串行依赖严重在GPU上的运行时间会相差巨大。忽略硬件特定优化现代硬件如GPU的Tensor CoreNPU的专用指令集对某些计算模式如低精度INT8计算、特定尺寸的矩阵乘有极度优化。一个FLOPs较高的模型如果其计算模式完美匹配硬件特性可能比一个FLOPs较低但计算模式“别扭”的模型快得多。忽略启动开销对于非常小的模型或层计算本身很快但内核启动kernel launch、数据搬运等固定开销可能占主导地位。此时FLOPs对比就失去了意义。因此一个更全面的模型效率评估体系应该包括理论计算量FLOPs、内存占用峰值显存、内存访问量MACs、实际推理延迟Latency以及能耗Power Consumption。对于部署工程师延迟和功耗是最终的黄金标准。4.3 实际项目中的FLOPs分析案例在我参与的一个手机端图像增强项目中我们需要在15ms内完成一张1080p图片的处理。初始基线模型是一个精简的UNetFLOPs为5.6G。瓶颈分析使用fvcore分析发现超过60%的FLOPs集中在解码器的前两个上采样层它们使用了大量的转置卷积。优化尝试方案A降低FLOPs将转置卷积替换为双线性上采样卷积。经计算FLOPs降至3.8G降低32%。但在手机NPU上实测延迟仅从18ms降至16ms提升不明显。原因是NPU对转置卷积有专用优化而对“上采样卷积”这个组合操作效率一般。方案B改变结构借鉴GhostNet的思想在瓶颈层使用更激进的通道压缩和廉价操作如深度卷积。FLOPs降至4.2G降低25%。实测延迟降至14ms满足了要求分析原因是这种改变不仅降低了FLOPs更重要的是减少了中间特征图的通道数从而显著降低了内存访问量和数据搬运开销而这正是该NPU的瓶颈所在。这个案例深刻说明优化FLOPs是手段而不是目标。最终要服务于降低实际延迟。结合详细的分析工具理解FLOPs来源再针对目标硬件特性进行设计才能取得最佳效果。5. 常见问题与排查技巧实录在实际工作中计算和使用FLOPs时总会遇到一些坑。这里记录几个典型问题和我的解决方法。Q1我用不同工具计算同一个模型的FLOPs结果差异很大该信谁的A这非常常见。首先检查以下几点计数标准确认工具使用的是1 MAC 1 FLOP还是1 MAC 2 FLOPs。thop默认是后者。如果A工具结果是10GB工具是5G很可能差了一倍。输入尺寸确保传递给两个工具的输入张量尤其是批大小和图片尺寸完全一致。FLOPs与输入尺寸直接相关。算子覆盖有些工具可能忽略了某些算子如自定义层、某些激活函数、池化层。检查工具的文档看它支持哪些算子。排查方法用一个极简的模型如只有一层卷积进行交叉验证手动计算和工具结果对比确定基准。Q2模型训练时的FLOPs和推理时一样吗A不一样。训练包含前向传播和反向传播。通常一次训练迭代的FLOPs大约是前向传播的2到3倍。反向传播需要计算梯度其计算量与前向传播大致相当有时还会更多例如某些激活函数的梯度计算更复杂。此外训练时可能开启Dropout、BatchNorm的训练模式等也会引入少量额外计算但这些通常不是主要部分。Q3如何估算模型在GPU上的理论最快推理时间A这是一个“屋顶线模型”的简化应用。理论最快时间T_min Total_FLOPs / Peak_FLOPS。Total_FLOPs你的模型一次前向传播的FLOPs。Peak_FLOPS你所用GPU的峰值单精度浮点算力以FLOPS为单位。例如NVIDIA RTX 3080的峰值算力约为30 TFLOPS每秒30万亿次。例如一个10 GFLOPs的模型在RTX 3080上的理论最快时间T_min 10e9 / 30e12 ≈ 0.33 ms。注意这只是一个理论极限。由于内存带宽限制、内核启动开销、计算并行度不足等原因实际时间实测可能为3ms会远大于这个值。这个值的主要作用是告诉你算力瓶颈的上限在哪里。如果实际时间已经接近这个理论值说明优化重点可能在算法本身降低FLOPs如果相差甚远说明优化重点在内存访问或算子实现上。Q4在论文中报告FLOPs有哪些注意事项A为了公平对比学术界逐渐形成了一些约定俗成的规范明确输入尺寸必须说明计算FLOPs所使用的输入张量形状通常是3 x H x W对于图像。常见的是224x224或320x320。明确计数规则在论文的“实验设置”或附录中最好注明“FLOPs计数遵循1 MAC 2 FLOPs的惯例”并说明使用的计算工具如fvcore。区分训练与推理通常报告的是一次前向传播的FLOPs。如果涉及训练成本分析需单独说明。报告乘加运算数有些领域如硬件设计更习惯报告乘加运算数MACs或MAdds。1 GFLOPs 0.5 GMACs如果按1 MAC2 FLOPs。务必清晰区分。Q5除了FLOPs还有哪些重要的效率指标需要关注A构建一个完整的模型效率评估清单我通常会看以下维度指标描述常用工具/方法为什么重要FLOPs理论计算量thop,fvcore,ptflops衡量模型计算复杂度筛选候选模型参数量模型权重总数thop,fvcore,torchsummary影响模型存储大小、内存占用与过拟合风险相关内存占用前向传播峰值显存torch.cuda.max_memory_allocated()决定模型能否在给定设备上运行内存访问量数据读写总量较难直接测量可通过分析网络结构估算影响实际速度尤其是内存带宽受限的设备推理延迟单次预测耗时实际部署使用time.time()或torch.cuda.Event测量最终用户体验的直接指标黄金标准吞吐量单位时间处理样本数压力测试测量不同批大小下的FPS服务端场景的关键指标最终我的建议是建立一个分层评估策略先用FLOPs和参数量进行大量模型的快速初筛然后对少数候选模型在目标硬件上进行延迟和内存占用的实测对于最关键的一两个模型再进行深入的剖析如使用Nsight Systems, Android Profiler等工具分析内核执行时间和内存瓶颈指导最终的微调。FLOPs是这张效率地图上一个重要但并非唯一的坐标理解它的内涵与边界才能让它真正为你的深度学习项目服务。
返回列表