1. ReLU和Pool层计算FLOPs,而conv层、FC层、Depthwise-conv层计算MACC数;
2. 区分FLOPS和FLOPs的区别,
FLOPS:注意全大写,是floating point operations per second的缩写,意指每秒浮点运算次数,理解为计算速度。是一个衡量硬件性能的指标。
FLOPs:注意s小写,是floating point operations的缩写(s表复数),意指浮点运算数,理解为计算量。可以用来衡量算法/模型的复杂度。
首先,解释FLOPs和MACC,两者都是CNN计算量的表示方法,一个网络的总的计算量macc等于每一层的MACC或FLOPs累加。了解模型速度的一种方法是简单计算它执行的计算量。我们通常将其视为FLOPs,每秒浮点运算。稍有不同的其他度量是MACC或乘法累加运算,也称为MADD。
以下为常用各层计算量计算方法(未编入则可忽略不计):
二维卷积层计算量公式为
MACC = K × K × Cin × Hout × Wout × Cout
Hout × Wout 对应输出特征图中的像素数目
K x K 卷积核的宽度和长度
Cin 输入通道数
Cout 是卷积核的数目,即输出的维度
针对输入所有值进行一次池化操作,不论是max、sum还是avg,都只需要对每个值算一次。
FLOPs = Hin × Win x Cin
对于输出的每一个值,都是一次池化操作,每次池化操作的计算量就是池化过滤器参数的数量。
FLOPs = Hout × Wout x Cout x K x K
MACC = Cin × Hout × Wout × (K × K + Cout)
具体参数意义与conv一致,请参考conv层。计算方式的原理如下:
一进深度可分离卷积是一个普通的卷积的分解成两个较小的操作。它们总共占用更少的内存(更少的权重)并且速度更快。当然,这只是近似于“完整”卷积层可以做的事情,因此您可能实际上需要更多这样的运算来获得相当于模型中原常规卷积层相同的表现力,但即便需要更多层,您这样做仍然更快。
这些层在移动设备上运行良好,是MobileNet的基础,也是Xception等大型模型的基础。
第一个运算是深度卷积depthwise convolution(深度卷积)。这在很多方面类似于常规卷积,除了我们没有组合输入通道。总是有相同数量的输入通道和输出通道。
深度卷积的MACC总数为:
K × K × C × Hout × Wout
这可以减少C倍工作量,使其比常规卷积层有效率。
示例:在112×112特征图上使用输入通道为64的3×3核进行深度卷积,MACC:
3 × 3 × 64 × 112 × 112 = 7,225,344
请注意,此卷积始终具有与输入通道一样多的滤波器,并且每个滤波器仅应用于单个通道。这就是上述计算中没有× 128的原因。
注意:有一个称为“深度通道乘数(depthwise channel multiplier)”的东西。如果此乘数大于1,则每个输入通道有D个输出通道。因此,不是每个通道只有一个过滤器,现在每个通道都有D个过滤器。但深度乘数(depthwise multiplier)在实践中应用很少。
仅仅深度卷积是不够的,我们还需要添加“可分离(separable)”。第二个运算是常规卷积,但始终使用内核大小1×1,也称为“逐点(pointwise)”卷积。
对于这个逐点卷积层,MACC的数量是:
Cin × Hout × Wout × Cout
因为K = 1。
示例:让我们从深度卷积中获取具有112×112×64特征图的输出,并将其投影到128维中以创建新的112×112×128特征图。那么MACC:
64 × 112 × 112 × 128 = 102,760,448
如您所见,逐点卷积比深度卷积贵很多倍。但是,如果我们将它们组合在一起,则MACC的总数远少于常规的3×3卷积:
3×3 depthwise : 7,225,344
1×1 pointwise : 102,760,448
depthwise separable : 109,985,792 MACCs
regular 3×3 convolution: 924,844,032 MACCs
常规卷积的计算量大概是深度可分离卷积8.4倍!
现在,比较这两种层有点不公平,因为常规的3×3卷积更具表现力:它可以计算更多感兴趣的东西。但是以相同的成本,你可以使用8倍以上这样的深度可分离层,或者给它们有更多的过滤器。
深度可分层的总MACC是:
(K × K × Cin × Hout × Wout) + (Cin × Hout × Wout × Cout)
这简化为:
Cin × Hout × Wout × (K × K + Cout)
如果将其与常规卷积层的公式进行比较,您会发现唯一的区别是我们最初× Cout在此处所做的事情+ Cout。做加法而不是乘法会产生很大的影响......
FLOPs = H x W x C
FLOPs = H x W x C x 4
参数具体意义与ReLU相同。
MACC = (2 x Cin + 1) x Cout
推理过程(测试阶段)可与Conv层合并,故可忽略MACC计算。具体原理为:
批量标准化获取层的输出,并将以下公式应用于每个输出值:
z = gamma * (y - mean) / sqrt(variance + epsilon) + beta
这y是前一层输出特征图中的元素。我们首先通过减去输出通道的mean并除以标准偏差来标准化该值(epsilon用于确保我们不除以0,它通常是这样的0.001)。然后我们按比例缩放gamma并添加偏差或偏移量beta。
每个通道有它自己的gamma,beta,mean,和variance的值,因此,如果在卷积层有C个输出通道,则该批量标准化层学习到C×4个参数。看起来有相当多的FLOPS,因为上面的公式应用于输出特征图中的每个元素。
然而......通常批量标准化应用于卷积层的输出但在非线性(ReLU)之前。在这种情况下,我们可以做一些数学运算来使批量标准化层消失!
由于在全连接层中进行的卷积或矩阵乘法只是一组点积,这是一个线性变换,并且上面给出的批量标准化公式也是线性变换,我们可以将这两个公式组合成一个单一运算。换句话说,我们可以将批量标准化层的学习参数“折叠”到前一个卷积/全连接层的权重中。
将批量标准参数折叠成前面层的权重的数学计算是相当简单的。在上面的公式中,y表示来自前一层的单个输出值。让我们扩展y:
z = gamma * ((x[0]*w[0] + x[1]*w[1] + ... + x[n-1]*w[n-1] + b) - mean) / sqrt(variance + epsilon) + beta
像往常一样,这是一个点积,来自卷积核或来自矩阵乘法。像往常一样,x意味着输入数据,w是该层的权重,并且b是该层的偏置值。
为了折叠批量标准化参数到上一层,我们要改写这个公式,这样gamma,beta,mean,并且variance只应用于w和b,没有x。
w_new[i] = w[i] * gamma / sqrt(variance + epsilon)
b_new = (b - mean) * gamma / sqrt(variance + epsilon) + beta
这里w_new[i]是新的第i个权重,b_new是偏置的新值。
从现在开始,我们可以将这些值用于卷积或全连接层的权重。我们现在可以写了:
z = x[0]*w_new[0] + x[1]*w_new[1] + ... + x[n-1]*w_new[n-1] + b_new
这给出了与以前完全相同的结果,但无需使用批量标准化层。替换上述公式中w_new和b_new,并简化。您应该再次获得原始批量标准化公式。
请注意,紧跟batchnorm的层通常本身没有偏置b,因为batchnorm层已经提供了一个(beta)。在这种情况下,公式b_new变得更简单(我们设置b为0):
b_new = beta - mean * gamma / sqrt(variance + epsilon)
因此,即使原始层没有偏置,无论如何都会得到一个折叠的批量标准化层。
简而言之:我们可以完全忽略批量标准化层的影响,因为我们在进行推理时实际上将其从模型中删除。
注意:此技巧仅在层的顺序为:卷积,批量标准化,ReLU时才有效 - 但不适用于:卷积,ReLU,批量标准化。ReLU是一个非线性操作,它会把数据弄乱。(虽然我认为如果批量标准化后面紧跟一个新的卷积层,你可以反过来折叠参数。无论如何,你的深度学习库已经为你做了这些优化。)