【深度学习】网络模型的参数量和运算量计算

1.模型说明

首先明确模型的计算量一般是衡量冻结模型(.pd)的,.ckpt在权重和偏置按照高斯分布初始化时一般计算量要大于冻结模型,所以我们要首生成模型的冻结文件(.pd)。

2.计算复杂度衡量标准

FLOPS:注意全大写,是floating point operations per second的缩写,意指每秒浮点运算次数,理解为计算速度。是一个衡量硬件性能的指标。
FLOPs:注意s小写,是floating point operations的缩写(s表复数),意指浮点运算数,理解为计算量。可以用来衡量算法/模型的复杂度。

MACCs:是multiply-accumulate operations),也叫MAdds,意指乘-加操作(点积运算),理解为计算量,也叫MAdds, 大约是 FLOPs 的一半。

1TFLOPs=1e3
GFLOPs=1e6
MFLOPs=1e9
BFLOPs=1e12

  • FLOPs和Madd的差别:
    FLOPs, floating point operations per second. 每秒的浮点运算数。
    MADD、MACC(multiply-accumulate operations):先乘起来再加起来的运算次数。
y = w[0]*x[0] + w[1]*x[1] + w[2]*x[2] + ... + w[n-1]*x[n-1]

上面的运算有n次浮点乘法,n-1次浮点加法,所以总共FLOPS为2*n-1
先乘后加的浮点操作有n次,所以MACC为n

3. 各种计算对于FLOPs的消耗

可以用 FLOPS(floating point operations per second,每秒浮点运算数)来衡量模型的速度。另一种方法是 MACCs(multiply-accumulate operations,乘-加操作),也叫 MAdds。但说穿了,都是点积运算而已。
什么叫乘-加?神经网络里的运算大都是这样的:

y = w[0]*x[0] + w[1]*x[1] + w[2]*x[2] + ... + w[n-1]*x[n-1]

w 和 x 都是向量,y 是标量。上式是全连接层或卷积层的典型运算。一次乘-加运算即一次乘法+一次加法运算,所以上式的 MACCs 是n。
而换到 FLOPS 的情况,点积做了 2n-1 FLOPS,即 n-1 次加法和 n 次乘法。可以看到,MACCs 大约是 FLOPS 的一半。

(1)全连接层:
权重 W 是一个 I×J 矩阵,输入 xI 维实值向量,bJ 维偏置。输出 y 也是 J维实值向量。FC 层的 MACCs 也不难计算。

上文例子是向量与向量的点积,FC 是向量与矩阵的点积,每一组点积发生在输入 x同权重 W 某一列之间,计有 I MACCs,一共要计算 J 组点积,所以 FC 层的 MACCs 总计 I×J,跟权重的尺寸一致。

偏置项 b对 MACCs 的影响可以忽略不计。而上面也提到 MACCs 中加法比乘法少一次, b刚好补上了这个缺。

所以,对 I的输入、权重为 I×J 的权重矩阵和 J 的输出,MACCs 为 I×J ,FLOPS 为 (2I−1)×J

(2)激活函数
FC 完了接下来通常有个激活函数,ReLU 或者 Sigmoid。激活函数的计算没有点积,所以只用 FLOPS 衡量。

对输出为 J的 FC 层,ReLU 有 J FLOPS:

y = max(x, 0)

相比之下 Sigmoid 就复杂很多。

y = 1/(1+exp(-x))

我们把加减乘除、指数、平方根等等运算都算作一次 FLOPS,这里有除法、加法、指数和减法四种运算,所以 FLOPS 就是 J×4

(3)卷积层:卷积层的乘-加操作次数很多,占总体的大头
卷积层要单独算而不是用全连接层的结论,是因为输入至少是三维的:H×W×C。对于这样的卷积层,MACCs 有:
K×K×Cin×Hout×Wout×Cout

解释一下:

  • 输出的 feature map 里每个通道上有 Hout×Wout个元素,
  • 权重以 K×K大小的窗口,在所有的 Cin个通道上做点积,
  • 共有 Cout个卷积核,上述操作重复了 Cout

同样,这里也忽略了偏置和激活函数。不应该忽略的是 stride(步长)、dilation factors(漏孔/膨胀卷积)、padding(填充),这就是为什么直接从输出尺寸 Hout×Wout 开始算的原因——都已经考虑在内了。

(4)batch normalization
计算公式:

z = gamma * (y - mean) / sqrt(variance + epsilon) + beta

首先以输入为卷积层的情况为例。

每个通道上都存在一组 mean 、beta 、gamma 、varianceC
个通道就有 C×4个可学习的参数。而且 BN 是作用在每一个元素上的,这样看来,造成的 FLOPS 应该不少。

但有趣的是,在 BN 直接连接卷积层的情况下,即 Conv-BN-ReLU 时,通过一组推导,可以将 BN 的计算整合到卷积层当中(注意这是 inference 的情况,跟训练阶段差别很大),从而消去的 BN 层造成的 FLOPS。如果是 Conv-ReLU-BN 的结构这一套就行不通了。

( BN 层的计算结合到 Conv 层中去,BN 层的 FLOPS 消失了,Conv 层需要乘一个常系数)

即从结果上来说,在 inference 时模型中的 BN 层实际被消去了。

(5)其它层
像 Pooling 层虽然确实很关键,但没有用到点积运算,所以 MACCs 不能很好地衡量这部分计算消耗。如果用 FLOPS,可以取 feature map 的尺寸然后乘一个常系数。

如 maxpooling 层,stride=2、filter_sz=2(即输出保持相同尺寸),112 x 112 x 128 的feature map,FLOPS 就是 112 x 112 x 128 = 1,605,632 。相对卷积层和全连接层的运算,这个计算量比较小,所以也可以忽略不计

4. 内存占用

内存带宽其实比 MACCs 更重要。目前的计算机结构下,单次内存访问比单次运算慢得多的多。
对每一层网络,设备需要:

  • 从主内存中读取输入向量 / feature map
  • 从主内存中读取权重并计算点积
  • 将输出向量或 feature map 写回主内存

涉及大量的内存访问。内存是很慢的,所以网络层的内存读写对速度有很大的影响,可能比计算耗时还要多。

(1)权重的内存占用
全连接层有 I x J 大小的权重矩阵,加上偏置向量共计 (I + 1) x J

卷积层的 kernel 通常是正方形的,对 kernel_sz = K 和输入通道为 Cin 、输出 Cout 和额外的 Cout 个偏置的情况,共有 (K x K x Cin + 1) x Cout 个参数。对比之下卷积层的参数量远小于全连接。

举例:

全连接层有4096个输入和4096个输出,所以权重数 (4096+1) x 4096 = 16.8M

3 x 3 、48个卷积核,在64x64 、32个通道的输入上计算,共有 3 x 3 x 32 x 48 + 48 = 13, 872 个权重。

注意到此处卷积层的输入实际是全连接层的32倍(通道),输出是48倍,然鹅权重数只有后者的千分之一不到。全连接层的内存占用真的很可怕。

(2)feature maps和中间结果
举例说明:
卷积层的输入是 224x224x3 ,把所有这些值读出来需要访问 150,528 次内存。如果卷积核是 KxKxCout ,还要乘上这个系数(因为每次卷积都要访问一遍)。
输出拿 stride=2, kernel 数为32的情况来说,输出的 feature map 尺寸为 112x112x32,共计 401,408 次内存访问。

所以,每层的内存访问总数如下:
input = Hin x Win x Cin x K x K x Cout
output = Hout x Wout x Cout
weights = K x K x Cin x Cout + Cout ,按上例:

input = 224 x 224 x 3 x 3 x 3 x 32 = 43,352,064
output = 112 x 112 x 32 = 401,408
weights = 3 x 3 x 3 x 32 + 32 = 896
total = 43,754,368

当网络层数加深时,Hin Win 会越来越小,但通道数会变得很大:

input = 28 x 28 x 256 x 3 x 3 x 512 = 924,844,032
output = 28 x 28 x 512 = 401,408
weights = 3 x 3 x 256 x 512 + 512 = 1,180,160
total = 926,425,600

这种情况下 weights 部分也会变得很大,所以是不能忽略的。

参考博客链接:

  1. 我的模型有多快?——深度学习网络模型的运算复杂度、空间占用和内存访问情况计算
  2. how fast is my model?

你可能感兴趣的:(深度学习)