背景

近几年来,深度学习技术在计算机视觉、语音识别和自然语言处理等诸多领域取得的了一系列重大突破。 然而,深度学习的发展依然面临诸多问题。
尤为突出的是,时下主流的深度神经网络,一般包含数千万甚至是过亿的学习参数,
而如此海量的参数给神经网络模型在存储、计算和功耗开销等方面带来了严峻的考验。

性能提升方法

  1. 小模型 mobilenet , 更精细模型的设计,紧致网络设计 Light Network Structure
  2. 模型压缩:参数稀疏、剪裁、量化、分解
  3. 软件优化-高性能计算
  4. 硬件优化-AI芯片

AI芯片

由于目前基于 PC 平台的神经网络加速一定程度上不能满足需要,
开发基于硬件例如 FPGA 的硬件加速平台显得很有必要。
其实硬件加速神经网络前向运算的最主要的任务就是完成卷积优化,
减少卷积运算的资源和能源消耗非常核心。

卷积优化的主要思路
1. 内存换取时间:

如果深度学习中每一层的卷积都是针对同一张图片, 那么所有的卷积核可以一起对这张图片进行卷积运算,
然后再分别存储到不同的位置,这就可以增加内存的使用率, 一次加载图片,产生多次的数据,而不需要多次访问图片, 这就是用内存来换时间。

2. 乘法优化:

以下图为例,上面是两张图片,右边是卷积核。 我们可以把卷积核心展开成一条行,然后多个卷积核就可以排列成多行,
再把图像也用类似的方法展开,就可以把一个卷积问题转换成乘法问题。 这样就是一行乘以一列,就是一个结果了。 这样虽然多做了一些展开的操作,
但是对于计算来讲,速度会提升很多。

3. GPU优化:

  1. 了解 IO 访问的情况以及 IO 的性能;

  2. 多线程的并行计算特性;

  3. IO 和并行计算间的计算时间重叠。

    对于 NVIDIA 的 GPU 来讲,内存访问是有一些特性的, 连续合并访问可以很好地利用硬件的带宽。 你可以看到,NVIDIA 最新架构的
    GPU,其核心数目可能并没有明显增加, 架构似乎也没有太大变化,但在几个计算流处理器中间增加缓存, 就提高了很大的性能,为 IO
    访问这块儿带来了很大优化。

4. 卷积计算优化

目前,卷积的计算大多采用间接计算的方式,主要有以下三种实现方式:

1、im2col + GEMM。 caffe等很多框架中都使用了这种计算方式,
原因是将问题转化为矩阵乘法后可以方便的使用很多矩阵运算库(如MKL、openblas、Eigen等)。
2、FFT变换。
时域卷积等于频域相乘,因此可将问题转化为简单的乘法问题。
3、Winograd。 这种不太熟悉,据说在GPU上效率更高。
NNPACK就是FFT和Winograd方法的结合。
上面三种方法执行效率都还不错,但对内存占用比较高,因为需要存储中间结果或者临时辅助变量。

1、Strassen 算法: 分析 CNN 的线性代数特性,增加加法减少乘法, 这样降低了卷积运算的计算的复杂度(o(n^3) ->
o(n^2.81)), 但是这种方法不适合在硬件里面使用,这里就不做详细的介绍了。

2、 MEC: 一种内存利用率高且速度较快的卷积计算方法 MEC: Memory-efficient Convolution for
Deep Neural Network 论文
这里是引用
博客解析

5. 卷积中的数据重用

在软件中的卷积运算,其实我们是在不断的读取数据,进行数据计算。 也就是说卷积操作中数据的存取其实是一个很大的浪费,
卷积操作中数据的重用如下图所示.

那么想办法减少数据的重用,减少数据的存取成为解决卷积计算问题的一个很重要的方面。 目前这样的方法有很多种,最主要的方法包括以下几种:

权重固定:最小化权重读取的消耗,最大化卷积和卷积核权重的重复使用;
输出固定:最小化部分和 R/W 能量消耗,最大化本地积累;
NLR (No Local Reuse):使用大型全局缓冲区共享存储,减少 DRAM 访问能耗;
RS:在内部的寄存器中最大化重用和累加,针对整体能源效率进行优化,而不是只针对某种数据类型。
下表是在 45NM CMOS 的基础上对于不同的操作的能耗进行的统计。
对 32 位的各种操作的能耗进行统计,可以看到从 DRAM 里面存取数据的能量消耗是最大的。
是 32 位整型数据进行加法的能量消耗的 6400 倍。
那么,从数据存取角度考虑卷积的优化就显得尤为必要了。

可行性分析
在 GPU 中加速时,主要通过将数据最大程度的并行运算,
增加了 GPU 的使用率从而加快了速度。
但是这种方法在硬件实现的时候是不可行的,因为这种方法本质上没有降低能耗,
而 DNN 模型的高能耗和大量的数据是其在可穿戴设备上面进行部署所需要面对的困难。
下面对一个卷积部分和运算进行分析,如下图 :
对第一组的 PE 整列,输入的是从 Image 的第 0 行到第 R-1 行的 S 列的数据,
同样的对于第二列的 PE 阵列输入的是第 2 行到第 R 的 S 列的数据。
每一列的 PE 计算得到一个最终的 Psum 的结果,那么如果设置 PE 阵列的列数为 N 的话,
每次我们就可以计算得到连续的 N 个部分和的结果。

不断更新 PE(process element,即处理单元)中 Image 缓冲区的数据, 就可以模拟卷积在水平方向上面的滑动,不断更新整个
PE 阵列的数据输入, 就可以模拟卷积窗在垂直方向上面的滑动,最终完成整个卷积运算的实现。

对应的卷积运算公式的细节在图中已经给出了,每一组 PE 产生一个部分和的结果的话, 那么增加 PE
阵列的组数,就可以一次性产生多个部分和计算结果,这里的组数就是并行度。

上面的内容简单论证用数据重用的方式实现卷积运算的可行性, 至于实现的具体数据流,还有相对用的系统的架构。

压缩算法在实际硬件芯片的应用

其实压缩算法应用硬件芯片非常简单,就是简单的将硬件芯片原来使用的乘法器进行替换, 如果是 BNN,参数只有两种情形, 那么如果参数为 1
的时候,直接通过, 不计算,如果参数为 -1 的时候,翻转最高位即可。

同理三值化中增加了一个 0 参数,这个可以直接跳过不进行计算。 至于参数为(-2,-1,0,1,2)的情形,参数为 2
时就增加了一个移位运算, 参数为 -2 的时候增加了一个最高位的翻转。

如果是 DoReFaNet,权值和输出都固定在一定的种类内部,那么他们的乘积情形也只有一定的种类,
这个时候相当于把乘法器变成了一个寻址操作, 每次乘法只需要在 LUT(look-up table,查找表)里面寻找到正确的结果读出即可。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐