关于 FLOPS、FLOPs、参数量的相关计算
写在前面
最近找到一些计算FLOPs的文章,奈何全是水文,讲都讲不清楚,完完全全的究极缝合怪。因此,这里准备彻底搞懂。
参考:CNN 模型所需的计算力(flops)和参数(parameters)数量是怎么计算的?
一、FLOPS
FLOPS:全称:FLoating point Operations Per Second的缩写,即每秒浮点运算次数,或表示为计算速度。是一个衡量硬件性能的指标。通俗点讲 显卡算力,对应英伟达官网的那些:GPU算力排行榜。
二、FLOPs
这才是本文的重点,FLOPs:FLoating point OPerationS 即 浮点计算次数,包含乘法和加法,只和模型有关,可以用来衡量其复杂度。多提一嘴,论文里面的FLOPs有的计算也并不明确,包括很多 Github 开源代码里面采用的 MACs,也就是考虑一次乘+加法运算为一次 MAC,粗略换算的话:。建议发表的论文还是按照 FLOPs 来给出,因为我看的大部分文章都是用的这个,而不是 MACs。
2.1 2D 卷积运算
FLOPs
就单纯的 2D 卷积而言,举例:
输入 Feature map:,输出 Feature map:,计算如下:
注意 (.) 里面的 -1 ,如果 bias = True,则不需要 -1。将 (.) 拆分为 乘法和加法:
第一个 (.) 里面是乘法,第二个是加法,如果 n 个数相加,做 n – 1 次加法运算,因此当 bias = True 时,刚好和 -1 抵消掉。
Parameters
参数量的计算要简单些:
同样注意:如果 bias = True,,如果 bias = False,去掉 。
2.2 全连接层
FLOPs
线性全连接层,举例:
,输入 sequence :,输出 sequence:,计算如下:
$
其中 代表乘法和加法。同上,当 bias = False 时,-1,bias = True时,无 -1。
Parameters
全连接层参数:
同样注意:当 bias = True,,当 bias = False,去掉 。
2.3 BatchNorm2D 层
FLOPs
由于 BatchNorm2D 层经常和卷积层连用,参考:论文阅读笔记:看完也许能进一步了解Batch Normalization,而在程序里面,这两个可以合并运算,因此不会增加 FLOPs。当然如果是 BatchNorm2D 在前,卷积在后,通用需要考虑 BatchNorm2D 层。
Parameters
对于每一个通道来说,可学习的参数有 2 个,动量 、动量偏移 。
2.4 激活层
对于 ReLU 来说,由于其本身性质,不涉及 MAC 运算,因此只考虑 FLOPs。而FLOPs 相对来说较小,所以一般不计算或者想其他办法计算。提一嘴,在推理时哪会用得到sigmoid呢。
激活层没有参数。
三、Github 自动计算 Parameters、MACs 的工具
3.1 thop
官网:Github
安装:
pip install thop
使用举例:
from torchvision.models import resnet50
from thop import profile
model = resnet50()
flops, params = profile(model, input_size=(2, 3, 200,280))
print("FLOPs=", str(flops / 1e9) + '{}'.format("G"))
print("FLOPs=", str(flops / 1e6) + '{}'.format("M"))
自定义计算规则举例:
from thop import profile
class YourModule(nn.Module): # 自定义模型
def count_your_model(model, x, y): # 自定义计算规则
flops, params = profile(model, input_size=(2, 3, 200,280),
custom_ops={YourModule: count_your_model})
print("FLOPs=", str(flops / 1e9) + '{}'.format("G"))
print("FLOPs=", str(flops / 1e6) + '{}'.format("M"))
优点:对于某个层的调试来说,很方便,比如 nn.Conv2D。
缺点:自定义的层,如 nn.Sequential()、nn.ModuleList() 这些容器层计算不了,需要自定义规则。
3.2 ptflops
官网:Github
安装:
pip install ptflops
使用举例:
import torch
from torchvision.models import resnet50
from ptflops import get_model_complexity_info
model = resnet50()
macs, params = get_model_complexity_info(model, (3, 200, 280), as_strings=True,
print_per_layer_stat=True, verbose=True)
print("FLOPs=", str(flops / 1e9) + '{}'.format("G"))
print("FLOPs=", str(flops / 1e6) + '{}'.format("M"))
优点:对于某个层的调试来说,很方便,比如 nn.Conv2D这些。另外 print_per_layer_stat = True 可以打印每一层的结构
缺点:自定义的层,如 nn.Sequential()、nn.ModuleList() 这些容器层计算不了。另外输入没有 batch维度,给出 shape 即可。
3.3 其他
还有一些其他的库,基本上和上面两种差不多,但缺点也很明显,自己写的卷积层可能压根计算不了。
举例:Github
四、尚未完结,需要时再补充~
写在后面
CSDN 灌水的人太多了,关键很多是错的,无语~~
文章出处登录后可见!