二值化神经网络(Binarized Neural Networks, BNN)模型解读

论文连接:https://arxiv.org/pdf/1602.02830.pdfgit

介绍

时至今日,深度神经网络通常都须要多个GPU才能够训练,这使得在低功耗设备运行神经网络模型有极大的挑战,如今也有大量的研究工做是关于在通用或者专用硬件上作加速。
本篇论文作了如下贡献:github

  1. 介绍了一种训练BNN的方法,在训练阶段使用二值化的权重和激活值计算参数梯度;
  2. 基于Torch7和Theano框架完成了两个实验,实验结果代表在MNIST、CIFAR-10和SVHN数据集上训练二值化神经网络是可能的,并且都达到了最早进的结果;
  3. 不论是在训练仍是推理阶段,对于前向传播,BNNs能够大幅度减少内存大小和访问量,使用位运算替代算术运算,均可以极大程度的提高能效;并且,二值化的卷积神经网络会致使卷积核复用;
  4. 最后,自行设计了一种二值矩阵乘法GPU核,在没有任何精度损失的前提下,比未优化前的GPU核在MNIST上的速度快了7倍。

一. 二值化神经网络

在本节主要讨论了二值化函数,展现了如何用它来计算参数梯度,以及经过它如何完成反向传播。web

1. 决定式 VS 随机二值化算法

在训练BNN时,咱们将权重和激活值限制为 +1 和 -1,从硬件角度来看这两个值是大有好处的,为了能将真实值转变为这两个值,咱们使用两种不一样的二值化函数,第一个二值化函数是决定式的:
在这里插入图片描述
其中x是真实变量值,Sign(x)是符号函数,这样的函数是很是简单粗暴的;第二个二值化函数是随机式的:
在这里插入图片描述
在这里插入图片描述
随机式的二值化比符号函数看起来要更有吸引力,可是很难实现,由于量化过程当中须要硬件产生随机位,所以在实际应用过程当中采用第一种函数多一些。网络

2. 梯度计算和累加框架

虽然BNN在训练过程当中使用的是二值化的权重和激活值,可是梯度值是不能够用二值化存储的,缘由在于:svg

  • 随机梯度降低更新参数时,梯度的量级很小;
  • 梯度具备累加效果。梯度中是包含有噪声的,而噪声通常都是正态分布的,屡次累加能够将噪声平均消耗掉;

并且,当计算参数梯度时,二值化至关于给权重和激活添加了噪声,这相似于正则化使得模型的泛化性能更好。咱们训练BNN的方法能够看做是Dropout的一种变体,只是计算参数梯度时Dropout是把通常的激活值设置为0,而二值化网络是对权重和参数进行二值化。函数

3. 离散化梯度传播性能

在反向传播过程当中要用到符号函数的导数,符号函数的导数几乎到处是0,所以是不能够采用的,咱们须要对符号函数进行宽松化,就获得了一种变形:
在这里插入图片描述
在这里插入图片描述
二值化操做函数为:
在这里插入图片描述学习

假设损失函数为C,C对q的导数已知,那么C对r的导数为:
在这里插入图片描述

1|r|<=1 就是Htanh函数;
在具体的算法应用时,对于隐藏层单元:

  • 咱们利用符号函数的非线性得到激活值,即直接使用Sign(a)得到二值化后的激活值。
  • 对于权重,Htanh和Sign两种函数都有用到:
    • 在对参数进行更新时,对权重使用Htanh函数进行裁减,使得权重永远在[-1, 1]之间;
    • 量化权重时,使用Sign(w)直接获得二值化的权重值;

在这里插入图片描述 在这里插入图片描述
算法1分为两个步骤,第一个步骤是计算参数梯度,其中又包括前向传播和反向传播两个过程;第二个步骤是对参数梯度进行累加。
在这里插入图片描述
4. Shift based Batch Normalization
在这里插入图片描述
Batch Normalization,即批量归一化,一般是在送入激活层以前使用,能够加速训练并下降整个权重尺度的影响(由于BN将数据归一化,使之均值为0,标准差为1),可是在训练过程当中,BN须要作不少次乘除运算占用了大量的计算力资源和时间。

针对二值化网络中BN层的前向运算,咱们设计了一种基于移位的批量归一化技术(SBN)如算法2所示,它将批量归一化中的乘除运算全都变为了移位操做。

BN层的前向传播以下图所示:
在这里插入图片描述在这里插入图片描述
经过实验对比发现,用基于移位的BN代替BN没有准确率的损失。

5. Shift based AdaMax

找最优解的一种优化方法,算法以下:
在这里插入图片描述
6. First Layer

在BNN中,某一层的输出就是下一层的输入,除了第一层以外全部层的输入都是二值化的,可是这对于咱们来讲不是一个麻烦,缘由有两点:

  • 第一层的通道数x相比于内部层来讲不多(对于彩色图片来讲,就是3),所以不论是从计算量仍是参数量来讲,第一层都是最小的卷积层;
  • 将输入层的像素点用m位定点数表示,举个例子,通常用8位的定点数表示一个像素点,那么咱们能够用下面的公式进行优化:
    在这里插入图片描述

这样的话第一层的运算就是点乘和移位 ,各层的计算方法以下:
在这里插入图片描述
针对前向传播的优化主要就是要对二值化的权重与激活值乘法(即+1与-1之间的乘法)作优化,做者的GPU矩阵乘法核就是基于此优化实现的,优化方法主要就是xnor和popcount操做,xnor操做就是按位异或操做,popcount就是计算一个二进制串中的"1"的数目。

举个例子说明:假设某一层隐藏层的激活向量二值化后a=[1,-1, 1, 1, -1],同时又有二值化后的权值W=[-1,1,1,-1,-1]。在程序中是以a=[1,0,1,1,0],W=[0,1,1,0,0]表示的。

那么按照正常的乘法应该是:a1*w1+a2*w2+a3*w3+a4*w4+a5*w5=1*-1+-1*1+1*1+1*-1+-1*-1=-1

    按照做者给出的操做应该是:a^W=[1^0,0^1,1^1,1^0,0^0]=11010,popcount(a^w)=3

而后使用-(2 x popcount(a^w) - len(vecor_length)),这里vector_length = 5,所以,最后的结果是-1,与咱们直接对a和w作乘加运算的结果相同。

二. Benchmark Results

  1. 在Torch7实验中,在训练阶段激活值是采用随机二值化的,而在Theano中是肯定式二值化的;
  2. 在Torch7中,咱们使用基于移位的BN和AdaMax。而在Theano中,使用的是vanilla BN和AdaMax。

在这里插入图片描述在这里插入图片描述

三. Very Power Efficient in Forward Pass

不管是通用的仍是专用的计算机硬件,都是由存储器、算术运算器进而控制单元组成,在前向传播过程当中,BNN能够大幅度地减小内存大小和访问量,使用移位操做代替算术运算致使能效的大大提升;并且,二值化的CNN致使了卷积核的复用,使得时间复杂度下降了60%。

1. 内存大小和访问量
在这里插入图片描述
与32位的DNN相比,BNN内存大小和访问量均减小了32倍。

2. XNOR-Count

深度学习中最主要的运算就是乘加运算,在BNN中,权重和激活值都被约束为-1和1。所以,大多数32位浮点数乘加运算能够被1位XNOR-Count操做代替,这将会给硬件带来重大影响,举个例子,32位浮点数乘法运算须要200 Xilinx FPGA slices,而1位XNOR仅须要一个slice。

3. 利用 Filter Repetitions

二值化的卷积网络中卷积核的数量是由卷积核的尺寸决定的。举个例子,若是卷积核的尺寸是 3 x 3,那么不一样的二维卷积核数量上限就是 2^9 = 512个,可是一般卷积核都是三维的,假定Ml表示第l层卷积核的数量,那么咱们须要存储一个4维矩阵 Ml x M(l-1) x k x k,因此,不一样的三维卷积核数量上限就是 2 **(M(l-1) x k x k)。

由于咱们如今有二值化的卷积核,许多 k x k 的二维卷积核都是重复的,经过使用专用的硬件,咱们能够仅仅用不一样的卷积核在feature map上作卷积,而后合理的进行加减就能够获得 3维卷积的结果。同时相似于[-1, 1, -1]和[1, -1, 1]能够看做是重复的。经过这种复用同一层卷积核的数量平都可以下降到原来的42%,XNOR-popcount 操做的数量能够减小3倍。

4. Seven Times Faster on GPU at Run-Time

经过在寄存器内部使用一种叫作SIMD方法角度BNN的GPU核实现,其基本思想是在一个32位寄存器中存储32位二值化变量,从而在位操做上得到32倍的加速。使用SWAR,仅3个指令就能够计算32个connections,从而原来32个时钟周期才能够作完的操做如今只须要 1 + 4 + 1 = 6个时钟,达到了32/6=5.3倍的加速。

为了验证上面的理论结果,设计了两个GPU核,一个是未经优化的乘法核,另外一个是采用了SWAR进行优化的XNOR核,二者的对好比下:
在这里插入图片描述

四. 展望

将来的工做应该是探索进一步加速训练时间(好比经过二值化一些梯度),还有就是将基准测试的结果扩展到其余模型或者数据集上。

源码连接:https://github.com/MatthieuCourbariaux/BinaryNet