【論文読み・実装】VoVNet（理論編）

arxiv: https://arxiv.org/abs/1904.09730
正式な論文タイトルは "An Energy and GPU-Computation Efficient Backbone Network for Real-Time Object Detection".
つまり、この論文では**GPU上でリアルタイム実行するときに本当に性能の良いモデルはなにか**ということを理論的に考察している。また、考察の結果として**One-Shot Aggregation**というアーキテクチャを提案している。

# 既存の研究とその問題
**[DenseNet](https://arxiv.org/abs/1608.06993)**は出力をすべての後続のレイヤーの出力にconcatする。
<img width="738" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/fb8a1b59-cd78-1141-c2c9-50b863b62e69.png">

ResNetと比べて前のレイヤーの情報を累積・保存できるという点で優れているが、

* **層の深さの２乗に比例**してメモリアクセスが増える
    * MAC(Memory Access Cost)が大きくなる（後述）
* そのままではえげつないペースで入力チャンネル数が増えるので、Dense Block内で1x1 conv (bottleneck layer)→3x3 convという構造にし、チャンネルの増加率を**成長率k**に減らしている
	* ![](https://camo.qiitausercontent.com/d5e4b036a91fb6a987a229f3222a1d30777f9350/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3233323038382f31366364323065362d653263392d313661322d396630612d6237613334616533383161372e706e67)[^citation_shikoan]
	* しかし、それは巨大なテンソルの計算に適したGPUの長所を削る結果になってしまっている

[^citation_shikoan]: この画像は[こしあんさんの記事](https://qiita.com/koshian2/items/01bd9f08444799625607)よりいただきました。

まとめると、DenseNetは**理論上のFLOPSは小さいが実際のGPU上ではエネルギー・時間的に非効率的**である。

（なお、これらの性質自体はすでに知られていた。例えば……

* ShuffleNet v2はMobileNet v2と同じくらいのFLOPSだがより速く走る
* SqueezeNetのパラメータ数はAlexNetの５０分の１だが、エネルギー消費量はむしろ大きい）

→FLOPSやパラメータ数より実用的な測定基準として、**FPS**[image/sec]と**energy per image**[J/image]でこの論文では考える。実際の計算時は

```math
\text{Energy per iamge[J/image]} = \frac{\text{Average Power[J/sec = W]}}{\text{FPS[image/sec]}}
```

で求めている。$\text{Average Power}$はご存知`nvidia-smi`で測定する

# モデルの効率に対する考察

## MAC

**メモリアクセスコスト (MAC)** は

```math
\operatorname{MAC}=h w\left(c_{i}+c_{o}\right)+k^{2} c_{i} c_{o}
```

で表される

* 第一項が画像へのアクセス
* 第二項がフィルターへのアクセス
* 一度アクセスすればキャッシュに保存しておけるとする

パラメータ数に関係なく、たとえば特徴マップ ($hw$) が大きければMACは大きくなり、また計算量も増える

**CNNのエネルギー消費の主要な原因はメモリアクセス**であり、またメモリアクセスは時間もかかるので**計算時間のボトルネックにもなりうる。**MACを小さくすることは重要である。

## GPU計算効率

上述したように、GPUは巨大なデータテンソルの計算が得意である。
大きなconvの前に1x1を挟んだり、1x1+depthwiseに取り替えることも、一見FLOPSやパラメータ数をへらすが、GPU的にはあまり嬉しくない。

# 提案手法

## DenseNetの問題点まとめ


* DenseNetでは、層が深くなるごとに線形にチャンネルがガンガン増える
 * FLOPSあたりに新しく得られる特徴量が少ない
 * Dense Connectionのおかげで**特徴の質は良いが、特徴の量はあまり増やせなくなってしまった**

* メモリアクセスコストが大きい
	* 相加相乗平均より$c_i = c_o$のときにMACは最小になる、すなわち

	* ```math
	 MAC \geq 2hw\sqrt{c_ic_o} + k^2c_ic_o = 2 \sqrt{\frac{h w B}{k^{2}}}+\frac{B}{h w}
	 ```

		* $B=k^{2} h w c_{i} c_{o}$はFLOPS。FLOPSによってMACの下界が決まっている、言い換えれば、**FLOPSが同じなら$c_i = c_o$を満たすと一番嬉しい**
	* だがDenseNetでは$c_o$が一定であるのに対して$c_i$が線形に大きくなるのでこれらが大きく異なり、MACも大きくなってしまう（詳しくは[下の図](#one-shot-aggregation)を見よ）

* GPUの並列計算に対する強さを損なう
	* 1x1 convはGPU的にはあまり嬉しくないので


## 重みの考察

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/ce1268ca-1aaa-ebf5-fbe6-84271af91845.png)

Dense Block3でTransition Layerはあまり中央のレイヤーを使っていない（②）が中央のレイヤーは中央のレイヤー自身をよく使っている（①）。Dense Block1では逆。
→負の相関があり、片方があれば十分ということは、無駄に情報を伝えている？

## One-Shot Aggregation

これは無駄なので、最終層でのみconcatする新たなアーキテクチャ(**One-Shot Aggregation, OSA**)を提案
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/f7ee5ebf-88a9-d1af-03ca-5c350ef2f832.png)

* これは各コンボリューションに対して$c_{i}=c_{o}$、MAC最小化条件を満たす
	* 上の図にチャンネル数を明記すると以下のようになる：
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/6575ef8e-8553-f5a7-f064-422771e9694b.png)
	* Denseblockでは入力チャンネル数と出力チャンネル数がだんだん食い違っていくが、OSAでは常に同じであることがわかる
* 1x1 convはブロック（OSA Module）の最後にのみ使われ、一気にチャンネルを圧縮する

モデルの詳細な仕様は以下の通り：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/d4db7409-9139-d7c3-646f-0aa2901ce2a8.png)

* まずStem Stageと呼ばれる初めの層で基本的なConvolutionを行う[^why_not_OSA]
* その次にOSA Moduleを4回積み重ねる
	* OSA Moduleの設定が3つの各モデルで異なる
	* 例えば27-SlimのStage 2だと、各convが64チャンネル出力するので、最後に$64\times 5=320$チャンネルがconcatenateされ、それを1x1 convで128にまで減らす

[^why_not_OSA]: 最初の層からOSAを行わない理由は論文に明記されていなかったが、おそらくここで取り出される特徴は非常にプリミティブ（線とか色の変化）なので、あとの層に送っても意味がなかったのだろう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/a31fa5a6-5a9c-af5d-23f8-e63f6e0e87cc.png)

また、OSA Module内のconvの回数を最初は12回にしていたが、③に示されるように最後の方のレイヤーの出力は最後の1x1 convであまり使われていない。
これを取り除いてもさして影響はないと思われたので、最終的に**ひとつのOSA内のconvの数は5回**とされた。

# 実験

## VoV vs Dense

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/1163c980-49ef-3c9c-27da-974c7d747f45.png)

* SSD300-MobileNetがベースライン
* PeleeはDenseBlockやprediction blockにResblockを導入した新しい画像認識モデル

### 結果 

* VoV27は同程度のパラメータ数であるDense67に実測値で勝利。
	* FLOPS自体も同程度だが、計算効率(Computation Efficiency)が2倍近く良いので結果としてFPSでは圧勝
	* エネルギー効率も4.1倍良い
* PeleeはFLOPS的にはこれらより小さいのに、実際の推論速度はDense67並で残念な感じ
	* GPU的にはPeleeの特徴であるdense blockの小さい切り分けは嬉しくないのだろう
	* 【参考】(a)がDense Layer, (b)がPeleeで使われた2way dense layer<img width="648" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/011b46ae-39b0-47b6-ee1d-259638fe0612.png">
	* 中間特徴マップの数も増えてしまうので、メモリアクセスも大きくなってしまう
* MobileNetはメモリー消費量的には小さいのに、エネルギー効率は悪い
	* depthwise convがばらばらに (fragmented) メモリアクセスするから効率が悪い



## Ablation study on 1x1 conv bottleneck
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/e541883a-d6b3-b916-ca0d-cb3b3c11573a.png)
3x3 convのあとに逐一bottleneck layer(1x1 conv)を挟んだら、**FLOPSもパラメータ数も減ったけど実際の実行時間とかは伸びてしまったよ😢**という図
「1x1 convはリアルタイム推論にとって嬉しくない」という仮説を交絡因子を減らして示した対照実験と言える
もちろん精度も微減😢

## RefineDetにいろいろなものを載せてみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102429/c45ebcb1-6979-95ad-1658-41867bf17046.png)

### 結果

* DenseNet-201(k=32)がDenseNet-161(k=48)より**FLOPSは少ないのに遅い**
	* 計算効率が悪いことがわかる
	* **（特徴マップが）薄く、深層であるモデルはGPUの並列計算的には非効率**であると考えられる[^only_for_real_time_inference]
* 同じVoVNetでも、メモリフットプリントが少ないもののほうがエネルギー効率はいい
* **小さい物体の検出にはVoVNet/DenseNetが強い**
	* concatによる特徴表現の集積が効いていると思われる

[^only_for_real_time_inference]: リアルタイム実行のときは1フレームずつ推論されるため。大量の画像を一括で処理するような課題だった場合、メモリに載るか否かが律速になり差が小さくなる可能性はある

# Kerasによる実装例
DenseNetと同じく実装は非常に簡単。Classifierとして軽く訓練してみたが、**DenseNetより速くて性能も良い**感じだ。

[gistリンク](https://gist.github.com/woodyZootopia/25e7940bf98fe05a631038f88dcbb8a0) [^citation_shikoan2]

[^citation_shikoan2]: Kerasは殆ど書いたことがなかったのでこのコードは[こしあんさんの記事](https://qiita.com/koshian2/items/01bd9f08444799625607)のものを雛形にしました。


次回は、これを用いて訓練スピードなどを定量的にDenseNetと比較していこうと思う。乞うご期待！

*この記事は、METRICAの社内勉強会用の資料を改稿して作りました。*

[2019/7/7追記][後編できました。](https://qiita.com/woody_egg/items/325fc9555598d87bc59c)