[Survey]XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks

[XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks](http://arxiv.org/pdf/1603.05279v1.pdf)

この論文は、**二値化(binarization)**によってNeural Networkの高速化と省メモリ化を図るというものです。
binarizationの対象は、**weight**と**input**です。
このbinarizationによりメモリ使用量が**1/32**、速度が**58倍**速くなっています。
full 精度の性能と比較して**2.9%**以内の劣化にとどまっておりかつ、比較対象となっている**BinaryConnect**や**BinaryNet**と比べて**16%**性能が上回っています。

Deep Neural Networkでは、いろいろな分野で様々な成果をあげていますが、Parameter数が非常に多く、メモリと計算コストを大量に必要とします。例えば、この論文では性能比較にAlexNetを使用していて、AlexNetのParameter数は**61M**で総容量は**249MB**になります。
Mobile機器などの計算資源が少ないDeviceに適応する場合に、こういったことは問題となってきます。

Binarizationのメリットとしては、
1. メモリ量がSingle Precisionと比較して**1/32**になる
2. Convolution演算が**XNOR**と**bitcounting**になり高速化できる
という２つの点が挙げられます。

この論文では、**Binary-Weight-Networks**という重みのみ２値化したものと、**XNOR-Networks**という重みと入力の両方を２値化した２つのNetworkを提案しています。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/0c664090-7388-218f-0e06-031c0113fdbb.png)


# Related Work

|Approach|Description|
|:-------|:--------|
|Shallow networks|Shallow Networkでどんなdecision boundaryも描けることがわかっているが学習が困難でかつ、結局Parameter数がDeep Networkと同じぐらい必要で、それほどメリットがないので、この論文では一般的なDeep Neural Network構造を使用。|
|Compressing pre-trained deep networks|Pruning（枝狩り）で冗長性をなくすという方法がいろいろ行われている。weight decayもその一つ。weight decayはL2 regularization項を入れることで重みを小さくするというもの。その他にHashを使って同じHush KeyのWeightは同一Parameterにするというものもある。|
|Designing compact layers|Fully connected layerはParameter数が多いのでやめて、global average poolingにする方法や、ResNetのようにBottleneck構造にしてParameter数を減らすというものもある。|
|Quantizing parameters|Parameterの精度を制限する方法。+1/0/-1の３値という方法もある。ただし、その手法はBack Propagationの時のみ３値で、Test Phase、Forward Propagationはfull precisionで処理している。|
|Network binarization|この論文が属するApproach.この論文以外にもBinaryConnectやBinaryNetという手法がある。|

# Binary Convolutional Neural Network
## 変数の定義
|変数|定義|
|:------|:------|
|$I={\cal I}_{l(l=1,...,L)}, I\in {\mathbb R}^{c\times win \times hin}  $|$l^{th}$ layerの入力Tensor $(c, w_{in}, h_{in})$=channel数、画像のwidth, height|
|$W={\cal W}_{lk(k=1,...K^l)}, W\in {\mathbb R}^{c\times w \times h}$|$l^{th}$ layerの$k^{th}$ weight $(c, w, h)$=channel数、filterのwidth, height|
|$K^l$|$l$ layerのfilter数|
|$*$|convolutional operation|
|$\oplus$|掛け算なしのconvolutional operation|
|$B \in \\{+1, -1\\}^{c \times w \times h}$|binary filter|
|$\alpha \in {\mathbb R}^{+}$|scale factor (positive real value)|


## Binary Weight Network
**Convoluation**演算に**binarization**を適応します。基本は下記のようにbinary filter $B$とscaling factor $\alpha$に分解して近似するだけ。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/0a0f7701-b976-f859-1ccc-28ab8cd9d1de.png)

なるべくもとの値に近い$B$と$\alpha$を求めたいので下記のように近似誤差を定義します。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/4c16074f-4b7c-b7e3-62dd-3bab233c826d.png)

展開すると下記のようになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/6cb76a91-a42f-8b03-6485-3cc669d3c75e.png)

ここで$B^TB$と$W^TW$は定数なので下記のように書けます。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/b6d4600a-20d3-facd-b315-0d72ba1c0b55.png)

$J(B, \alpha)$を最小化すればよいので、$\alpha$は正の値だから、$W^TB$を最大化するように$B$を求めると良い。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/a82f4769-72bc-628b-1320-ac8b278cce8c.png)

これを最大化するには$W$の要素$W_i$が$W_i \ge 0$のとき、$B_i=+1$に、$W_i \lt 0$のとき、$B_i = -1$にするとよい。

ということは。最適値$B^*$は下記のようになり、結局は$W$の符号を値とする行列になります。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/de81bf91-22ea-eacf-e445-4648baea1371.png)

$\alpha$の最適値は、$J(B,\alpha)$を$\alpha$に関して偏微分して$0$とおいて解くと下記のようになります。

```math
\begin{eqnarray}
\frac{\partial J(B,\alpha)}{\partial \alpha}=2\alpha n - 2 W^TB^* = 0\\
\alpha^* = \frac{W^TB^*}{n}\\
\end{eqnarray}
```

これに$B^*$を代入すると$W$のL1ノルムを$n$で割ったものになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/039dd498-5ef8-045e-aab9-aa18211a6aa5.png)

### Training Binary-Weights-Networks

Training algorithmは下記の通り

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/fba89016-f7ac-909c-d25d-9e54e592b5d6.png)

要約すると、

1. weightを２値化 $B,A$を求める
2. **Forward propagation**　$(B\oplus I)\alpha$を使用
3. **Back propagation** $W$は２値化したもの${\cal {\tilde W}}$を使う
4. parameter $W$とlearning rateを更新する（update更新時だけbinary値を使わない）

update時にbinarizationしない理由は、update時の更新量は非常に小さいの更新後に２値化するとこれらの変化が消え去り、Parameterが更新されなくなるため。

一旦Trainingが終われば、実数値のweightは必要なく、推定時はbinary weightだけでforward propagationを行います。

## XNOR-Networks
weightとinputの両方を2値化する。これによりconvolution演算がXNORとbitcounting演算だけになります。

先ほどと同様にbinaryの行列とscalerに分離します。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/dc914e90-56bf-7534-5c6c-05f4fd17d0cd.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/cb9513a1-bbe9-429d-df93-a60bddce921d.png)

同じように下記を満たす $\alpha*$, $\beta*$, $B^*$, $H^*$を求めます。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/b6b04cb4-fb4e-6d8f-4d36-9b1822298298.png)

ここで$Y_i = X_iW_i$のように要素ごとの積を計算したものを$Y_i \in {\mathbb R}^n$とする。
さらに$C_i = H_iB_i$と$\gamma = \beta\alpha$とおくと、上記の式は下記のように書けます。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/25979891-c917-fa30-66ab-c18397cf8f34.png)

これは掛け算だけ先に計算して、$1^T$と内積を取ることで、後で足し算を行っていることに相当します。$1^T$は要素がすべて１のベクトル。
これで最初の時と同じように$C$と$\gamma$の最適値が求められ下記のようになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/c96b33cd-ff2c-75d8-26b7-80005ae215de.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/495c40c5-5a96-4642-d512-9217d15691b6.png)

### Binary Convolution
異なる場所のbinary convolutionを計算するときに重複して計算している部分があります。
それを示したのが下図の中段(2)の赤い時の部分。
重なっている部分を計算するのは無駄なので、(3)のようにchannel方向に絶対値の平均を計算して$A$を求めて、その後で2D filter $k \in {\cal R}^{w \times h}$とconvolution演算をする。ただし、$k$の要素は$k_{ij}=\frac{1}{w \times h}$。
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/a27a1888-28d1-dd54-ef58-ff813fadf2ef.png)

最終的にinputとweightのconvolutionは下記のように分解される。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/298cfb87-129b-f285-f2cf-709b286862d0.png)

$\circledast$はXNORとbitcountによるconvolutional operation。
$\odot$は要素ごとの掛け算。

### Training XNOR-Networks
一般的なCNNは、
1. Convolutional
2. Batch Normalization
3. Activate
4. Pooling
の順で構成される。
２値化されたデータにmax poolingを適応しても、+1にしかならないので、lossが大きいから順番を右のように変更する。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/48a91354-ef41-82fb-5d4c-b53d25019019.png)

1. Batch Normalization
2. BinActiv
3. BinConv
4. Pooling

BinActivでは${\rm K}$と${\rm sign(I)}$を計算する。
sign function$q=sign(r)$のgradientは、BinaryNetと同じように$g_r=g_q1_{|r|\le1}$とする。

BinConvでは![image](https://qiita-image-store.s3.amazonaws.com/0/100523/298cfb87-129b-f285-f2cf-709b286862d0.png)を計算する。

# Experiments

## memory効率の比較
各モデル毎のdouble precisionとbinary precisionの必要メモリ量の比較
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/c08d5749-ec0d-5704-516e-6d505067b754.png)

## operation数の比較

standard convolutionとbinary convolutionのoperation回数の比率は下記のようになる。
64は一般的なCPUには64bit operationがあるというところから来ている値。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/85bcfb37-19f5-6eb4-71f9-7fe29508bba8.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/4fc68857-d53c-cc4c-8b59-b315fd5f5d30.png)

左が$c$を変えた時のグラフで、右が$N_w$を変えた時のグラフ
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/9632e821-41ab-1af0-75c1-f3f1d344c393.png)

ResNetのArchitectureから$c=256, n_I=14^2, n_W=3^2$とした時、$S=62.27$になる。ただしoverheadがあるので、実際には１ convoluation演算あたり58倍高速化される。
ただし、グラフ(b)をみると$c$が小さい値ではそれほど高速化されない。例えばfirst layerやlast layerでは一般的にchannel数が少ないのでBinaryNetと同じようにbinarizationは行わない。

## Image Classification on ILSVRC2012

###Dataset
・ILSVRC2012
・1.2M Training Data
・1K categories
・50K validation image

### Networks
・AlexNet
・5 convolutional layer and 2 fully connected layer
・Parameter数 61M

### 比較対象
**BinaryConnect**
・forward propagation, backward propagation時binarizationを行う
・update時はreal valueを使用する
・deterministic binarizationとstochastic binarizationが記載されているが、deterministicを使用。
　deterministicではweightが0以上の時は+1,それ以外は-1とする。
**BinaryNet**
・推定時と学習時のgradient計算時にweightとactivationをbinarizationする

###Training
・画像の縦横の短い方が256になるようにresizeする
・224x224でrandom croppingする
・epoch数16
・batch size 512
・SGD (momentum 0.9) Binary-weight-networksとBinaryConnect比較時
・ADAM XNOR-NetworksとBInaryNet比較時
・learning rate 初期値 0.1 4 epoch毎に0.01 減衰させる

結果は下記の通りで、Binary-Weight-Networks,XNOR-Networksともに比較対象と比べて17%ぐらい性能が良い。
dashedがtraining dataでsolidがvalidation dataの結果

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/e486b10b-d0a1-1fe6-15ff-04fa03f3ed80.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/4a24fac4-2a25-5d7a-8589-0a76245e8038.png)


## Residual Net/GoogleNet Variantで比較
・比較対象はFull Precision、Binary-Weight-Networks,XNOR-Networks
**ResNet**
・ResNetは18 layerを使用
・short cut connectionとしてA, B, CがあるがBを使用
　A,B,Cはshortcutした時の合流時点で次元数が異なる場合の処理の違い
　　A Zero Padding
　　B 次元数が異なるところだけProjectionで同じ次元にする
　　C 次元数の違いによらず全部Projectionする
・画像の縦横の短い方を256か480にRandomでResizeする
・224x224でrandom croppingする
・epoch数 58
・batch size 256
・learning rate 初期値 0.1 30epochと40epochで0.01 減衰させる
・Test時は中心部分を224x224でcropして使用する

**GoogleNet Variant**
・straightforward network (no branching)
・21 convolutional layer
・filter size 1x1, 3x3 
・画像の縦横の短い方を256か320にRandomでResizeする
・224x224でrandom croppingする
・epoch数 80
・batch size 128
・learning rate 初期値 0.1 polynomial rate decay $\beta=4$
・Test時は中心部分を224x224でcropして使用する
polynomial rate decayの記載は無いが多分こんな感じ

```math
learning rate=0.1\times (1-\frac{epoch}{80})^4
```
![polynomial.png](https://qiita-image-store.s3.amazonaws.com/0/100523/f3443d39-e5f1-c660-ec13-f71225c7ed09.png)

結果は下記の通り
dashedがtraining dataでsolidがvalidation dataの結果
Binary-Weight-Networksの方が性能が良い。
Full Precisionと比べて性能はそれほど劣化していないが、他手法との比較が無いのでよくわからない。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/52606a50-3971-4cd0-fa9b-c26658fa8296.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/d3124f14-7786-7b8e-70de-480d6e5ebe58.png)

## Scaling factorとblock structureの比較
**左：scaling factorを固定パラメータとした時の比較**
scaling factorの有効性チェックのため
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/039dd498-5ef8-045e-aab9-aa18211a6aa5.png)

**右：block structure比較**
一般的なStructureと提案手法のStructureを比較して有効性をチェックするため
C-B-A-Pが一般的なStructureでB-A-C-Pが提案手法のStructure
![image](https://qiita-image-store.s3.amazonaws.com/0/100523/48a91354-ef41-82fb-5d4c-b53d25019019.png)

どちらも性能が向上している。

![image](https://qiita-image-store.s3.amazonaws.com/0/100523/b6d5caa8-d5dc-e325-ad3f-711b0072bb08.png)

# 最後に
結局のところ、weightとinputを符号ビットとscale factor(filter領域の絶対値平均)に分解して効率化したという感じでしょうか。
構造はなるべく近似誤差が大きくならないように順番をアレンジしています。