EfficientNetの各モデルの係数について

# はじめに

軽量かつ高性能で知られるEfficientNetだが、モデルとしてはB0からB7まで八つある。それぞれどのようにして設計されているかについて、あまり記事が見当たらない(というか論文にもはっきり書いてない)ので、調査結果を記事にする。

# EfficeintNetとは

元論文
[EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks]( https://arxiv.org/abs/1905.11946) (ICML 2019)

論文冒頭に主旨が書いてあるので引用する。

>Convolutional Neural Networks (ConvNets) are commonly developed at a fixed resource budget,and then scaled up for better accuracy if more resources are available.   In  this paper,  we systematically study model scaling and identify that carefully balancing network depth, width, and resolution can lead to better performance.  

意訳すると、以下の様なことだろう。

* CNNでは一般的には、最初に限られたリソースで比較的軽量のモデルを作る。
* その後、精度を上げたい場合には、モデルをスケールアップしたくなる。
* そんな時、深さ、幅、解像度といったところを増やしたくなるが、どれをどう増やしたらよいかわからない。
* この論文では、それらのパラメータをうまくバランスをとって増やしていく方法を提案。

つまり、モデル自体には大きな意味はなく、それを「どのようにスケールアップさせるのか」が主眼となっている。ただ、研究の過程でベースとなるモデルを作ったがそれがかなり優秀で、スケールアップさせたらすごい性能が出た、ということのようだ。

肝心のスケールアップ方法だが、以下の様な式が示されている。

![Efficeint.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824193/244d6f36-6356-a07d-4672-122aa13f8a79.png)

$\alpha$、$\beta$、$\gamma$はモデル固有の定数で、$\phi$だけを変更してモデルをスケールアップすればよいとしている。

* widthはベースモデルのフィルタ数に掛ける係数。
* depthはベースモデルのブロック数に対して掛ける係数。同じフィルタ数のブロックをひとつのまとまりとして、その単位でブロック数を増やす。
* resolutionは画像サイズの比（224x224が1.0なら、560x560が2.5、と論文中に示されている）。

# 各モデルの実装について

論文に示されているベースモデルB0の各定数は下記の通り。

|$\alpha$|$\beta$|$\gamma$|
|:-:|:-:|:-:|
| 1.2|1.1 | 1.15|

これに対して$\phi$を変更して適用しモデルを作成したのが、B1からB7とされている。(論文には示されていないが、B8とL2というのもある模様)

実際の実装としてはモデル生成時に引数として、計算済みのwidth_coefficientとdepth_coefficientを渡している。

各モデルに対する係数は以下の様になっている。(resolutionは係数としてではなく画像サイズで指定)

| Model| size| width | depth |
|---|---|---|---|
|B0 |224|1.0|1.0|
|B1 |240|1.0|1.1|
|B2 |260|1.1|1.2|
|B3 |300|1.2|1.4|
|B4 |380|1.4|1.8|
|B5 |456|1.6|2.2|
|B6 |528|1.8|2.6|
|B7 |600|2.0|3.1|

B0がベースとなるモデルで係数は全て1.0。それ以外は上記の式でバランスの取れたスケールアップができた、としている。

なぜか論文では各モデルの係数も$\phi$も掲載されていないので、この辺はコードを見ないとわからない。
[論文にも記載されている公式コード](https://github.com/tensorflow/tpu/blob/master/models/official/efficientnet/efficientnet_builder.py)

ここでコードには$\phi$が書かれていないので、「なぜこのような係数になったのか」が実は明記されていないのだが、上記の式で$\phi$以外は定数なので、逆算できる。
例えば、画像サイズを224で割るとresolutionが確定し、$\gamma$が定数なのだから$\phi$も決まる。

上記のような計算で求めた$\phi$(phi)と各係数は以下の通りとなった。カッコ内の数値は実装での係数。

| Model| size| phi |width | depth |resolution|
|---|---|---|---|---|---|
|B0 |  224 | 0.00 | 1.00(1.0) | 1.00(1.0) | 1.00 |
|B1 |  240 | 0.49 | 1.05(1.0) | 1.09(1.1) | 1.07 |
|B2 |  260 | 1.07 | 1.11(1.1) | 1.21(1.2) | 1.16 |
|B3 |  300 | 2.09 | 1.22(1.2) | 1.46(**1.3**) | 1.34 |
|B4 |  380 | 3.78 | 1.43(1.4) | 1.99(**1.8**) | 1.70 |
|B5 |  456 | 5.09 | 1.62(1.6) | 2.53(**2.2**) | 2.04 |
|B6 |  528 | 6.14 | 1.79(1.8) | 3.06(**2.6**) | 2.36 |
|B7 |  600 | 7.05 | 1.96(2.0) | 3.62(**3.1**) | 2.68 |

widthについては計算と一致している。しかしdepthはB3以降ずれが大きくなっている。計算より少ない係数で実装および評価をしたようだ。
恐らく計算量(FLOPs)で上限をかけて、そこにおさまるようにdepthを調整したと思われる。この制限については論文中には記載されていないようだ（そもそも係数を論文に記載していないのはどうかと思うが）。

以下、計算に使ったコード。

```Python
import math
def make_param(modelname, size, alpha, beta, gamma):
    phi = math.log( size/224,gamma)
    print ( f'|{modelname} |  {size} | { phi:.2f} | { alpha**phi:.2f} | { beta**phi:.2f} | { gamma**phi:.2f} |' )

make_param('B0', 224, 1.2, 1.1, 1.15)
make_param('B1', 240, 1.2, 1.1, 1.15)
make_param('B2', 260, 1.2, 1.1, 1.15)
make_param('B3', 300, 1.2, 1.1, 1.15)
make_param('B4', 380, 1.2, 1.1, 1.15)
make_param('B5', 456, 1.2, 1.1, 1.15)
make_param('B6', 528, 1.2, 1.1, 1.15)
make_param('B7', 600, 1.2, 1.1, 1.15)
```