【YOLOv5】FLOPS计算解析及profile函数的使用对比

YOLOv5中FLOPS计算解析

这里选择的版本是YOLOv5-v5.0,Ultralytics官方代码中计算FLOPS部分的路径在yolov5/utils/torch_utils.py,代码如下:

from thop import profile
stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32
img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device)  # input
flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2  # stride GFLOPS
img_size = img_size if isinstance(img_size, list) else [img_size, img_size]  # expand if int/float
fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride)  # 640x640 GFLOPS

这里贴一个ultralytics YOLOv5-v5.0的github🔗

解释官方FLOPS的计算过程:

第一步-确定输入尺寸:

stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32

这行代码确定了用于计算FLOPS的基准输入尺寸。YOLOv5模型有不同的下采样步长(stride),包括stride=8、stride=16、stride=32,不同的stride分别代表不同大小的特征图,代码取最大步长值和32的较大值作为基准量。

第二步-创建测试输入:

img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device)

创建一个全零张量作为测试输入:

  • 批次大小为1
  • 通道数从模型配置文件获取(默认为3,对应RGB图像)
  • 宽高都是前面计算的stride值

例如通道数=3,stride=32时,张量大小为[1,3,32,32]

第三步-计算基准FLOPS:

flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2
  • 使用profile函数自动计算处理输入时的所有计算操作
  • 乘2是因为大多数深度学习操作涉及乘加运算(multiply-add),每个乘加被计为2次浮点运算

该步计算后得到的是基准FLOPS(inputs为stride的大小)

第四步-计算实际输入尺寸下的FLOPS:

img_size = img_size if isinstance(img_size, list) else [img_size, img_size]
fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride)

对于实际inputs,根据其与stride的比例进行缩放:

  • 将基准FLOPSflops乘比例因子(实际宽度/基准宽度)*(实际高度/基准高度),得到实际FLOPS

总的来说,官方计算可以理解为使用profile函数自定义了一个全新的FLOPS计算规则,具更好的鲁棒性

直接使用profile函数计算FLOPS

thop库中的profile函数是一个成熟的计算FLOPS函数,可以直接使用进行FLOPS的计算:

# 创建随机输入张量
input_image = torch.randn(1, 3, img_size, img_size).to(device)
# 1: 批次大小为1
# 3: RGB三通道
# img_size: 输入图像的高度和宽度

# 使用thop计算FLOPS和参数量
flops, params = thop.profile(model, inputs=(input_image,), verbose=False)
# 统一单位
    fs = '%.2f' % (flops / 1E9)  # Convert to GFLOPS

与之前的方法相比,这种方式有以下特点:

  • 新方法使用torch.randn创建随机数据,而不是之前使用的torch.zeros,但对FLOPS的计算结果实际上没有影响
  • 新方法直接使用指定的img_size,没有考虑stride的影响。这可能带来潜在问题:如果img_size不是stride的整数倍,可能导致特征图尺寸出现小数
    (例如,如果img_size=650而最大stride=32,那么650/32=20.3125会导致问题)
  • 没有乘以2计算实际运算次数

总的来说,直接使用thop计算FLOPS的方式更简洁,但需要注意处理输入尺寸的兼容性问题。


关于实际GFLOPS是否应该考虑*2的问题

在深度学习中,计算FLOPS(浮点运算次数)时,对是否将乘加运算(multiply-add operations,或称MAC)计为1次还是2次运算存在不同的观点。

两种计算方式:

  1. 将乘加看作一个原子操作(MAC方式):
flops, params = thop.profile(model, inputs=(input_image,), verbose=False)
flops_gflops = flops / 1E9  # 不乘以2,直接转换为GFLOPS
  1. 将乘法和加法分别计数(FLOPS方式):
flops, params = thop.profile(model, inputs=(input_image,), verbose=False)
flops_gflops = flops / 1E9 * 2  # 乘以2,考虑乘法和加法分别计数

实际上,现代处理器通常将乘加作为一个融合操作(Fused Multiply-Add,FMA)来执行,一个时钟周期内就能完成。因此,从硬件执行的角度来看,不乘以2可能更符合实际情况。

因此,在实际使用时,若要比较不同模型的计算量时,重要的是保持计算方式的一致性:

  • 如果你正在与其他使用MAC计数的工作进行比较,就不要乘以2
  • 如果你在与分别计数乘法和加法的工作比较,就需要乘以2

这就是为什么在进行模型计算量的比较时,总是需要明确说明FLOPS的具体计算方式,以确保比较的公平性和准确性。

通常情况下,使用MAC的计数方式(不乘以2)更符合硬件的实际执行情况,也更容易与大多数深度学习框架的默认统计方式保持一致。

Reference
【YOLOv5-6.x】模型参数量param及计算量FLOPs解析

### YOLO 模型 FLOPs 计算公式 对于卷积神经网络而言,FLOPs计算主要集中在卷积层上。YOLO 模型中的每一层都会贡献一定的浮点运算次数 (FLOPs),这可以通过下面的公式来估算: 给定输入特征图尺寸 \(H \times W\) 和通道数 \(C_{in}\),以及输出特征图尺寸 \(H' \times W'\) 和通道数 \(C_{out}\),当使用大小为 \(K \times K\) 的卷积核时,单次前向传播过程中该层产生的 FLOPs 可以通过下述方式估计[^1]: \[ \text{FLOPs} = H' \times W' \times C_{\text{in}} \times C_{\text{out}} \times K^2 / G \] 其中: - \(G\) 表示分组数量(group number),默认情况下等于 1; - 如果存在深度可分离卷积,则需分别考虑逐点卷积(pointwise convolution)和深度卷积(depthwise convolution)部分。 特别地,在 PyTorch 中可以利用 `thop` 库提供的接口方便快捷地获取整个模型的具体 FLOPs 数值。具体实现如下所示: ```python from thop import profile import torch from models.yolo import Model device = 'cuda' if torch.cuda.is_available() else 'cpu' model = Model(cfg='path/to/yolov5.yaml').to(device) input_tensor = torch.randn(1, 3, 640, 640).to(device) macs, params = profile(model, inputs=(input_tensor,)) print(f"FLOPs: {macs * 2}") ``` 上述代码片段展示了如何基于预定义配置文件初始化 YOLOv5 模型实例,并传入随机张量作为输入数据来进行性能分析;最终打印出来的结果即代表了所构建模型的大致理论峰值 FLOPs 值(注意实际运行环境下的有效利用率可能会有所不同)。这里乘以 2 是因为在某些文献中会把一次加法操作也计入到 FLOP 当中去[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值