前言
对于神经网络, 我们更多谈的是其精度怎么样, 有百分之零点几的提升. 但是如果谈到速度的话, 深度学习神经网络相比于传统的算法来说, 速度恐怕没有那么快了.
那么我们什么时候需要提升速度呢? 假如有以下的场景:
将模型运行在手机上
需要实时的场景, 比如高速摄像机捕捉动作
在嵌入式设备上运行
对于有桌面级显卡这种利器来说, 速度似乎很容易得到很快, 但是放到以上这些设备时, 在有效的硬件上如果速度提升不上来, 那么所设计的算法也就没什么用处了.
所谓提升速度, 不谈论硬件级别的优化, 对于神经网络来说无非也就两点:
网络的设计
输入数据的大小
输入数据大小我们姑且不谈, 而神经网络的设计这一点就显得比较重要了, 网络的设计可以细分为: 网络模型权重的大小, 网络运行过程中产生的中间变量的大小, 网络设计中各种计算的执行速度等等这些都会对速度产生影响, 一般来说, 模型参数和模型速度是成正比的.
关于速度和精度来说, 这往往是一个衡量, 精度和速度一般无法兼顾, 正如在工业界使用很火的 YOLO 和在学术界名声远扬的 Mask-Rcnn, 一个追求速度一个追求精度(当然速度的前提是精度在可接受范围之内).
运算量
接触过 ACM 的童鞋一定知道时间复杂度和空间复杂度这两个概念, 时间复杂度即衡量一个算法运行的时间量级, 而空间负责度则衡量一个算法所占用的空间大小. 神经网络则类似, 如何判断一个网络的速度快不快, 最直观最直接地就是看其包含多少个浮点运算(当然与内存带宽也有关系).
与这个概念密切相关的就是 FLOPS(Floating-point operations per second, 每秒执行的浮点运算数). 现在的桌面级显卡, 大部分都是 TFLOPs 级别了, 1TFLOP 也就是每秒执行 1,000,000,000,000 次浮点运算.
矩阵乘法
在神经网络中, 最常见的就是矩阵乘法:
正如下方的输入 4*4 的图像, 卷积核为 3*3, 输出为 2*2:
在计算机中将上述运算分解为:
结果中一个标量的计算过程可以用公式表示为:
y = w[0]*x[0] + w[1]*x[1] + w[2]*x[2] + ... + w[n-1]*x[n-1]
w 和 x 都是向量, w 是权重, x 是输入. 最终的结果是 y 是一个标量 (scalar). 这个运算称作 multipy-accumulate operations. 而其中的一个操作 w[0]*x[0] + ..(先乘后加) 称为一个 MACC(multipy-accumulate operation). 而上面的计算一共包含 n 个 MACCs.
简而言之, 两个 n 维向量的点乘所需要 n 个 MACCs 运算(其实可以说是 n-1 个, 因为第一个不算, 但是我们近似地认为是 n 个). 而 n 个 MACCs 运算包括 2n-1 个 FLOPs(n 个乘法和 n-1 个加法), 我们近似为 2n 个 FLOPs.
也就是说, 两个 n 维向量的乘积所需要的 FLOPs 是 2n 个.
当然, 在很多的硬件设施中(比如显卡), 一个 MACC 就可以称作一个运算单位了, 而不是将加法和乘法分开, 因为硬件已经对其进行了大量的优化, 我们之后在测一个卷积运算量就可以按照 MACC 这样的单位来计算了.
全连接层
全连接层是除了卷积层最常见的层, 在全连接层中, 输入数量为 I 和输出数量为 O, 这些节点一一相连, 然后权重 W 保存在 I x J 的矩阵中, 于是对于一个全连接层来说, 其计算量为:
y = matmul(x,W) + b
- 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
- Cexp = (Cin * expansion_factor)
- expansion_layer = Cin * Hin * Win * Cexp
- depthwise_layer = K * K * Cexp * Hout * Wout
- projection_layer = Cexp * Hout * Wout * Cout
来源: https://juejin.im/post/5c17a5595188250fa835f116