论文地址:https://arxiv.org/abs/1603.05279
代码地址:http://allenai.org/plato/xnornet
Abstract
我们提出了两种对标准卷积神经网络的高效近似:Binary-Weight-Networks 和 XNOR-Networks。在Binary-Weight-Networks中,卷积核中的权重被近似为二值,这使得内存节省了
32x;在XNOR-Networks中,卷积核的权重和卷积层的输入都是二值化的,这导致内存节省了32x,卷积操作的速度提高了58x,这使得在CPUs(而不是GPUs)上运行最先进的CNN成为可能,我们的二值化网络简单、高效、精度高,可以在比较有挑战性的视觉任务上工作。我们在ImageNet分类任务中评估了我们的方法,Binary-Weight-Networks的分类精度和全精度的AlexNet相同,同时我们将我们的方法和最近的二值化网络方法对比(BinaryConnect和BinaryNets),在ImageNet上我们的方法领先于其他方法一大截,top-1的精度高了16%。
1. Introduction
本文的主要两点贡献:
- 介绍了一种对卷积神经网络中权重二值化的方法,展示了我们的方法与之前最先进的方法相比的优势所在;
- 引入了XNOR-Nets(对权重和输入对进行二值化),在保证了与标准的卷积神经网络相似的精度的同时,效率大大提高;
2. Related Work
深度神经网络模型有大量的参数冗余,这导致在计算和内存使用时的不高效,针对这个问题目前有一下几种方法:
Shallow networks:浅层模型可以减小网络大小,Cybenko早期的工作表明拥有一个足够大的单隐藏层的Sigmoid单元的网络可以近似出任意的决策边界。在几个领域(如视觉和语言),却发现浅层网络不能和深度模型相比,我们发现训练一个参数量很大的浅层模型很难,有证据表明在小数据上(如CIFAR-10)上,浅层网络可以学习的和深度网络一样好,为了达到近似的精度,在浅层网络中的参数量要和深度模型中的参数量接近。通常要做到这一点,首先要训练一个最先进的模型,然后训练一个浅层模型来模仿深度模型。
Compressing pre-trained deep networks:将一个之前训练好的网络中的信息量少的权重剪枝掉可以减少网络在推理阶段的运行时间,权重衰减是早期剪枝网络的一种方法。
Designing compact layers:在深度神经网络的每一层都设计一个紧凑的模块可以帮助节省内存和计算成本,用全局池化层来提到全连接层可以实现最先进的结果,还有一些其他的设计技巧,有兴趣的同学可以参考我之前的一些文章,其中一个主要单元就是“组卷积”,可以有效减少参数量和计算量。
Quantizing parameters:在深度网络中使用高精度参数并不是必要的,可以将单精度浮点数量化到16位、8位、4位甚至1位。
Network binarization:这个工作和我们的工作最为接近,已经有几种方法尝试对权重和激活值二值化,然而高度量化的网络的性能一般不好,因为二值化极具破坏性。Expectation BackPropagation(EBP)展示了权重和激活值都二值化的网络仍然可以有很高的准确率,这个是通过一种变分贝叶斯完成的,网络的推理阶段权重和激活值都是二值化的。"Backpropagation for energy-efficient neuromorphic computing."这篇文章采用了和EBP相似的方法,在节省能耗方面取得了巨大的提高,不同的是EBP仅在推理阶段对参数二值化。"Binaryconnect: Training deep neural networks with binary weights during propagations."扩展了EBP背后的概率思想,类似于我们的方法,BinaryConnect使用真实的权重值作为一个二值化过程中的一个关键参考,在反向传播阶段更新的是真实的权重值,而不是二值化之后的权重(先简单忽略更新过程中的二值化),这个方法在小数据集上很成功,但在大数据集上效果并不是很好。"Binarynet: Training deep neural networks with weights and activations constrained to +1 or -1."提出的BinaryNet作为BinaryConnect的一种扩展,权重和激活值都量化了。我们的方法和前面提到的在二值化的方法和网络结构上是不同的,我们将我们的方法和BinaryNet在ImageNet上做了比较,发现准确率提高了一大步。"R.: Regularization of neural networks using dropconnect"讨论了可以将二值化的引入看作一种正则化,从而提高了网络的测试精度,这篇文章中只对权重进行二值化,没有二值化激活值。
3. Binary Convolutional Neural Network
我们用一个三元组<I,W,*>来表示一个L层的CNN结构。I是一组张量,其中每一个元素 I = I l ( l = 1 , . . . . . . , L ) I=I_{l(l=1,......,L)} I=Il(l=1,......,L)表示CNN网络第l层的输入张量(如Figure 1中的绿色方块);W是一组张量,其中每一个元素 W = W l k ( k = 1 , . . . . . . , K L ) W=W_{lk(k=1,......,K^{L})} W=Wlk(k=1,......,KL)表示第l层的第k个卷积核, K L K^{L} KL表示第l层的卷积核个数;*代表一种卷积操作,I和W是操作数, I ∈ R c × w i n × h i n I\in R^{c \times w_{in} \times h_{in}} I∈Rc×win×hin,这里 ( c , w i n , h i n ) (c,w_{in},h_{in}) (c,win,hin)分别代表通道数、宽和高; W ∈ R c × w × h W \in R^{c \times w \times h} W∈Rc×w×h,其中 w ⩽ w i n , h ⩽ h i n w\leqslant w_{in},h\leqslant h_{in} w⩽win,h⩽hin,我们提出了二值化CNN的两种变体:Binary-weights(只有权重进行了二值化)和XNOR-Networks(I和W都是二值化的张量)。
3.1 Binary-Weight-Networks
为了使得CNN的权重二值化,我们使用二值的卷积核 B ∈ ( − 1 , + 1 ) c × w × h B \in (-1,+1)^{c \times w \times h} B∈(−1,+1)c×w×h和缩放因子 α ∈ R + \alpha \in R^{+} α∈R+对真实的卷积核权重进行估算,使得 W ≈ α B W\approx \alpha B W≈αB,这样的话卷积操作就可以近似表示为: I ∗ W ≈ ( I ⨁ B ) α I*W\approx (I\bigoplus B) \alpha I∗W≈(I⨁B)α(记为等式(1)),这里的 ⨁ \bigoplus ⨁表示的是没有乘法的卷积运算,由于权重是二值化的,所以实现了只有加法和减法的卷积。二值化权重的卷积核相比于单精度浮点数内存占用减少了32倍,我们用 < I , B , A , ⨁ > <I,B,A,\bigoplus> <I,B,A,⨁>来表示权重二值化的CNN,这里的B是二值化张量的集合,A是正实数缩放因子 α \alpha α的集合,所以第l层的第k个卷积核权重 W l k ≈ A l k B l k W_{lk} \approx A_{lk}B_{lk} Wlk≈AlkBlk(这里的 A l k , B l k A_{lk},B_{lk} Alk,Blk相当于 W ≈ α B W\approx \alpha B W≈αB中的 α \alpha α和 B B B)。
Estimating binary weights:前面提到了用 α B \alpha B αB来近似原始的权重卷积核,那么这里的 α \alpha α和B是怎么获得呢?
这里先将W和B看成是 1*n 维的向量,其中
n
=
c
×
w
×
h
n=c\times w \times h
n=c×w×h。为了找到 一个最优的估算
W
≈
α
B
W\approx \alpha B
W≈αB,我们需要解决这样一个最优化问题:
J
(
B
,
α
)
=
∣
∣
W
−
α
B
∣
∣
2
J(B,\alpha)=||W-\alpha B||^{2}
J(B,α)=∣∣W−αB∣∣2(记为等式(2)),我们想要得到的
α
∗
,
B
∗
=
a
r
g
m
i
n
J
(
B
,
α
)
\alpha^{*},B^{*}=argminJ(B,\alpha)
α∗,B∗=argminJ(B,α);
将等式(2)扩展,我们有:
J
(
B
,
α
)
=
α
2
B
T
B
−
2
α
W
T
B
+
W
T
W
J(B,\alpha)=\alpha^{2}B^{T}B-2\alpha W^{T}B+W^{T}W
J(B,α)=α2BTB−2αWTB+WTW(记为等式(3))
在等式(3)中,由于 B ∈ ( + 1 , − 1 ) B \in(+1,-1) B∈(+1,−1),所以 B T B = n B^{T}B=n BTB=n是一个常量, W T W 也 是 一 个 常 量 , 因 为 W 是 一 个 已 知 变 量 W^{T}W也是一个常量,因为W是一个已知变量 WTW也是一个常量,因为W是一个已知变量,我们定义 c = W T W c=W^{T}W c=WTW,等式(3)可以写成: J ( B , α ) = α 2 n − 2 α W T B + c J(B,\alpha)=\alpha^{2}n-2\alpha W^{T}B+c J(B,α)=α2n−2αWTB+c,要让 J ( B , α ) J(B,\alpha) J(B,α)最小,那么最优的B应该为 B ∗ = a r g m a x ( W T B ) , s . t . B ∈ ( − 1 , + 1 ) n B^{*}=argmax(W^{T}B),s.t.B\in (-1,+1)^{n} B∗=argmax(WTB),s.t.B∈(−1,+1)n(记为等式(4))
最优的方案就是当
W
i
⩾
0
W_{i}\geqslant 0
Wi⩾0时
B
i
=
+
1
B_{i}=+1
Bi=+1,
W
i
⩽
0
W_{i}\leqslant 0
Wi⩽0时
B
i
=
−
1
B_{i}=-1
Bi=−1,因此最优的
B
∗
=
s
i
g
n
(
W
)
B^{*}=sign(W)
B∗=sign(W)。为了找到最优的缩放因子
α
∗
\alpha^{*}
α∗值,我们对J求关于
α
\alpha
α的导数,并令其为0得到:
α
∗
=
W
T
B
∗
n
\alpha ^{*}=\frac{W^{T}B^{*}}{n}
α∗=nWTB∗,将
B
∗
B^{*}
B∗用sign(W)替换掉,就可以得到:
α
∗
=
W
T
s
i
g
n
(
W
)
n
=
∑
∣
W
i
∣
n
=
1
n
∣
∣
W
∣
∣
l
1
\alpha ^{*}=\frac{W^{T}sign(W)}{n}=\frac{\sum |W_{i}|}{n}=\frac{1}{n}||W||_{l_{1}}
α∗=nWTsign(W)=n∑∣Wi∣=n1∣∣W∣∣l1
Training Binary-Weights-Networks:训练一个CNN网络时每一次迭代都涉及三个步骤:
- 前向传播:使用二值化权重 W ~ ≈ α B \tilde{W}\approx \alpha B W~≈αB做前向传播;
- 反向传播:反向传播的公式为
∂
C
∂
W
i
=
∂
C
∂
W
i
~
(
1
n
+
∂
s
i
g
n
∂
W
i
α
)
\frac{\partial C}{\partial W_{i}}=\frac{\partial C}{\partial \tilde{W_{i}}}(\frac{1}{n}+\frac{\partial sign}{\partial W_{i}}\alpha)
∂Wi∂C=∂Wi~∂C(n1+∂Wi∂signα),其中由于sign函数的导数几乎处处为0,所以在反向传播时使用的是sign函数的宽松化函数Htanh(x)=clip(x,-1,1)(图像如下),
∂
s
i
g
n
∂
γ
=
γ
1
∣
γ
∣
⩽
1
\frac{\partial sign}{\partial \gamma}=\gamma 1_{|\gamma |\leqslant 1}
∂γ∂sign=γ1∣γ∣⩽1,下面对反向传播的公式进行推导:
通过上面的分析我们知道: W i ~ = α B = ∑ ∣ W i ∣ n s i g n ( W i ) \tilde{W_{i}}=\alpha B=\frac{\sum |W_{i}|}{n}sign(W_{i}) Wi~=αB=n∑∣Wi∣sign(Wi)
则 ∂ C ∂ W i = ∂ C ∂ W i ~ ∂ W i ~ ∂ W i = ∂ C ∂ W i ~ ( 1 n ∂ ∑ ∣ W i ∣ ∂ W i s i g n ( W i ) + ∂ s i g n ( W i ) ∂ W i α ) = ∂ C ∂ W i ~ ( 1 n + ∂ s i g n ( W i ) ∂ W i α ) \frac{\partial C}{\partial W_{i}}=\frac{\partial C}{\partial \tilde{W_{i}}}\frac{\partial \tilde{W_{i}}}{\partial W_{i}}=\frac{\partial C}{\partial \tilde{W_{i}}}(\frac{1}{n}\frac{\partial \sum |W_{i}|}{\partial W_{i}}sign(W_{i})+\frac{\partial sign(W_{i})}{\partial W_{i}}\alpha)=\frac{\partial C}{\partial \tilde{W_{i}}}(\frac{1}{n}+\frac{\partial sign(W_{i})}{\partial W_{i}}\alpha) ∂Wi∂C=∂Wi~∂C∂Wi∂Wi~=∂Wi~∂C(n1∂Wi∂∑∣Wi∣sign(Wi)+∂Wi∂sign(Wi)α)=∂Wi~∂C(n1+∂Wi∂sign(Wi)α); - 参数更新:对参数和学习率进行更新,需要注意的是,在这里我们直接是对高精度的真实权重 W i W_{i} Wi进行更新,更新之后的 W i W_{i} Wi会得到新的 α \alpha α和 B B B,进而得到新的 W i ~ \tilde{W_{i}} Wi~。这是因为在梯度下降中梯度值通常很小,而直接对 W i ~ \tilde{W_{i}} Wi~进行更新会忽略这些变化使得训练目标没有变化;
一旦训练完成,就没有必要保存真实的权重值了,因为在推理阶段我们只需要二值化权重来完成前向传播。
3.2 XNOR-Networks
迄今为止,我们设计了BWN网络,使用缩放因子和二值化的权重对原始权重进行估算。卷积层的输入仍然是真实值张量,接下来我们将介绍如何涉及权重和激活值都是二值化的网络,这样的话卷积操作可以通过XNOR和位操作来高效实现,这也是XNOR-Networks的关键所在。
Binary Dot Product:输入为I,X为本次卷积中和W对应的输入部分,
X
,
W
∈
R
n
X,W\in R^{n}
X,W∈Rn,其中
n
=
c
×
w
×
h
n=c\times w\times h
n=c×w×h。
X
T
W
≈
β
H
T
α
B
X^{T}W \approx \beta H^{T} \alpha B
XTW≈βHTαB,即我们使用
β
H
T
α
B
\beta H^{T} \alpha B
βHTαB来估算原来的输入和权重的卷积结果,这里的
H
,
B
∈
(
−
1
,
+
1
)
n
H,B\in (-1,+1)^{n}
H,B∈(−1,+1)n,
β
,
α
∈
R
+
\beta ,\alpha \in R^{+}
β,α∈R+,和上面一样,我们把这个问题当作一个优化问题:
⨀
\bigodot
⨀表示的是元素之间的点乘运算,我们定义
Y
∈
R
n
Y\in R^{n}
Y∈Rn,且
Y
i
=
X
i
W
i
,
C
∈
(
−
1
,
+
1
)
n
,
C
i
=
H
i
B
i
Y_{i}=X_{i}W_{i},C\in(-1,+1)^{n},C_{i}=H_{i}B_{i}
Yi=XiWi,C∈(−1,+1)n,Ci=HiBi,同时
γ
∈
R
+
,
γ
=
α
β
\gamma\in R^{+},\gamma=\alpha\beta
γ∈R+,γ=αβ,等式(7)可以写成:
最优的答案就是同等式(2)类似,我们让:
由于
∣
X
i
∣
,
∣
W
i
∣
|X_{i}|,|W_{i}|
∣Xi∣,∣Wi∣是相互独立的,并且
Y
i
=
X
i
W
i
Y_{i}=X_{i}W_{i}
Yi=XiWi,那么:
E
[
∣
Y
i
∣
]
=
E
[
∣
X
i
∣
∣
W
i
∣
]
=
E
[
∣
X
i
∣
]
E
[
∣
W
i
∣
]
E[|Y_{i}|]=E[|X_{i}||W_{i}|]=E[|X_{i}|]E[|W_{i}|]
E[∣Yi∣]=E[∣Xi∣∣Wi∣]=E[∣Xi∣]E[∣Wi∣],因此有:
Binary Convolution:现在我们来看一下对于每一层的卷积操作,输入张量
I
∈
R
c
×
w
i
n
×
h
i
n
I\in R^{c\times w_{in}\times h_{in}}
I∈Rc×win×hin,权重
W
∈
R
c
×
w
×
h
W\in R^{c\times w\times h}
W∈Rc×w×h,其中
w
i
n
⩾
w
,
h
i
n
⩾
h
w_{in} \geqslant w,h_{in}\geqslant h
win⩾w,hin⩾h,我们需要计算的是对于I中所有可能的子张量(与W相对应的)的缩放因子
β
\beta
β,一层总共有
h
o
u
t
w
o
u
t
h_{out}w_{out}
houtwout个缩放因子。
上图中第一行是只对权重二值化时如何得到
α
和
B
\alpha和B
α和B,第二行展示了
X
1
和
X
2
X_{1}和X_{2}
X1和X2这两个子张量,由于它们之间存在重叠,所以计算所有的
β
\beta
β会有比较大的冗余计算,所以我们采用第三行的方法,先对输入I在通道这个维度求绝对值的均值得到
A
=
∑
∣
I
:
,
:
,
i
∣
c
,
A
∈
R
h
i
n
×
w
i
n
A=\frac{\sum |I_{:,:,i}|}{c},A\in R^{h_{in}\times w_{in}}
A=c∑∣I:,:,i∣,A∈Rhin×win,然后让A和2D的卷积核
k
∈
R
w
×
h
k \in R^{w\times h}
k∈Rw×h做卷积得到
K
=
A
∗
k
K=A*k
K=A∗k,这里的二维张量k中的每一个元素都
k
i
,
j
=
1
w
×
h
k_{i,j}=\frac{1}{w\times h}
ki,j=w×h1,由此可以得到的
K
∈
R
h
o
u
t
w
o
u
t
K\in R^{h_{out}w_{out}}
K∈Rhoutwout,包含了输入I对应的所有缩放因子
β
\beta
β。一旦我们得到了权重的缩放因子
α
\alpha
α和输入I所有sub-tensors的缩放因子
β
\beta
β,我们可以使用二值操作近似得到输入I和权重W的卷积结果:
I
∗
W
≈
(
s
i
g
n
(
I
)
⊛
s
i
g
n
(
W
)
)
⊙
K
α
I*W\approx (sign(I)\circledast sign(W))\odot K\alpha
I∗W≈(sign(I)⊛sign(W))⊙Kα
这里的
⊛
\circledast
⊛表示的是只使用XNOR和bitcount操作,这可以在Figure 2中最后一行体现出来,这里需要注意的是不是二值我们的网络中存在不是二值操作的运算,只不过它的计算量相比之下可以忽略。
Training XNOR-Networks:在CNN中典型的块包含几种不同的层,Figure 3(左)展示了CNN的典型块结构,它的顺序是:1-Convolutional、2-Batch Normalization、3-Activation和4-Pooling,BN层是通过input batch的均值和方差对卷积的输出进行标准化,激活层是元素级的非线性函数(如Sigmoid、ReLU等),在二值化的输入上应用最大池化会造成比较大的信息损失,因为其返回的结果都将为+1。因此,我们将在卷积层之后使用池化层,为了进一步降低二值化造成的信息损失,我们在二值化之前对输入进行标准化,使之均值为0,这使得量化损失大大降低了。在二值化的CNN中各层顺序如Figure 3(右)所示:
BinConc层是计算K和sign(I),在下一层BinConv,是通过等式(11)做二值卷积,接着在最后一层,我们做池化操作。一旦我们得到了二值化的CNN结构,训练算法和algorithm 1相同。
Binary Gradient:计算瓶颈在于每一层的反向传播要计算权重w和对输入的梯度 g i n g^{in} gin之间的卷积,和前向传播的二值化类似,如果我们在反向传播中对 g i n g^{in} gin二值化,这就可以通过位操作来提高训练效率。需要注意的是如果我们利用等式(6)来计算 g i n g^{in} gin的缩放因子,那么SGD算法的最大梯度的方向就会消失,为了保留所有维度上的最大变化,我们使用 m a x i ( ∣ g i ∣ ) max_{i}(|g^{i}|) maxi(∣gi∣)作为缩放因子。
k位量化:这篇文章介绍的是利用sign(x)来将权重和输入量化到1位。我们也可以利用 q k ( x ) = 2 ( [ ( 2 k − 1 ) ( x + 1 2 ) ] 2 k − 1 − 1 2 ) q_{k}(x)=2(\frac{[(2^{k}-1)(\frac{x+1}{2})]}{2^{k}-1}-\frac{1}{2}) qk(x)=2(2k−1[(2k−1)(2x+1)]−21)替代sign函数,这里的[]表示一个取整操作并且 x = c l i p ( x , − 1 , 1 ) ∈ [ − 1 , 1 ] x=clip(x,-1,1)\in[-1,1] x=clip(x,−1,1)∈[−1,1]。
4. 实验
在标准卷积中,操作量为
c
N
W
N
I
cN_{W}N_{I}
cNWNI,其中c是通道数,
N
W
=
w
h
,
N
I
=
w
i
n
h
i
n
N_{W}=wh,N_{I}=w_{in}h_{in}
NW=wh,NI=winhin,在一些先进的CPU中我们已经可以将加法和乘法在一个时钟周期,XNOR-Net的卷积中(等式11)有
c
N
W
N
I
cN_{W}N_{I}
cNWNI次二值操作和
N
I
N_{I}
NI次非二值操作,现在的CPU可以在一个时钟周期执行64次二值操作,因此可以加速的倍数为
S
=
c
N
W
N
I
1
64
c
N
W
N
I
+
N
I
=
64
c
N
W
c
N
W
+
64
S=\frac{cN_{W}N_{I}}{\frac{1}{64}cN_{W}N_{I}+N_{I}}=\frac{64cN_{W}}{cN_{W}+64}
S=641cNWNI+NIcNWNI=cNW+6464cNW。
由此我们可以发现加速只取决于卷积核尺寸和通道数,而和输入尺寸无关。在上图Fig 4中的(b)和©中我们展示了加速和通道数和尺寸之间的关系,当我们取
c
=
256
,
n
I
=
1
4
2
,
n
w
=
3
2
c=256,n_{I}=14^{2},n_{w}=3^{2}
c=256,nI=142,nw=32,使用我们的方法理论上可以获得62.27x的加速。我们发现对于小的通道数(比如c=3)和卷积核尺寸(如
N
W
=
1
×
1
N_{W}=1\times1
NW=1×1),加速效果并不明显,这给了我们一个灵感——避免在第一层和最后一层使用二值化,因为第一层的通道数是3,最后一层的卷积核尺寸为1x1。我们的方法的内存和计算量与BinaryNet在同一个量级,不同之处是我们使用了缩放因子,这使得在没有改变效率量级的同时在准确率上有一个很大的提升。
在table 1中我们比较了BC和BNN与我们的方法相比的准确率,我们发现缩放因子
α
\alpha
α要比缩放因子
β
\beta
β重要很多,将
β
\beta
β移除只会使得精度掉一点(小于1%的top-1 AlexNet)。