VGG以降のネットワークは本当に進歩しているの？という話

# 1. はじめに
　本記事では[AI competitions don’t produce useful models](https://lukeoakdenrayner.wordpress.com/2019/09/19/ai-competitions-dont-produce-useful-models/?utm_campaign=piqcy&utm_medium=email&utm_source=Revue%20newsletter)で問題定義されている最近のネットワークアーキテクチャはデータセットに過学習してるだけ&運ゲーで上振れしているだけじゃないの？という話を広角眼底データセット[^1]で調べてみることを目的とします。また、入門向けとして、`tf.keras`で実装済みのネットワークを用いてImageNet[^2]の学習済み重みからFine-turningする方法を解説します。

[すべてのコード] (https://github.com/burokoron/StaDeep/tree/master/Image_classification/fine-turning)

# 2. 環境
- PCスペック
  - CPU: Intel Core i9-9900K
  - RAM: 16GB
  - GPU: NVIDIA GeForce GTX 1080 Ti
- ライブラリ
  - Python: 3.7.4
  - matplotlib: 3.1.1
  - pandas: 0.25.1
  - tqdm: 4.31.1
  - pillow: 6.1.0
  - scikit-learn: 0.21.3
  - tensorflow-gpu: 2.0.0

# 3. AI competitions don’t produce useful models
　[記事(AI competitions don’t produce useful models)](https://lukeoakdenrayner.wordpress.com/2019/09/19/ai-competitions-dont-produce-useful-models/?utm_campaign=piqcy&utm_medium=email&utm_source=Revue%20newsletter)の概要を説明します。
　機械学習コンペは最終的なテストデータの結果はオープンにしないようにしたりすることで、実質的には1回しかモデルの評価が行えないようにしている。これによって、モデルガシャができないようになっている。たしかに1チーム1回しか評価を得られないのでこの対策は上手くいっているように思える。しかしコンペ全体として見るとそうではない。例えば100チームが参加している場合、100回モデルガシャをしていることになる。優勝したチームはこのガシャに運よく勝利しただけで手法がもっとも優れていたとはわけではない。また、いくつかのコンペにおいて上位チームの成績が拮抗している。有意差検定を行うと上位チームの成績はただの誤差であり、有意差を出すにはもっと大量のテストデータを用意しなければならない。さすがにVGGまでは精度向上してると思われるが、それ以降は疑問であり、テストデータに過学習しているだけの可能性がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405329/3d734744-0c15-9479-9746-8e2cca1b20c5.png)

　今回は広角眼底データセット[^1]を使用してVGG16[^3]、DenseNet121[^4]、ResNet50[^5]、InceptionV3[^6]、NASNetMobile[^7]、EfficientNet-B0[^8]の性能評価を行うことで、本当にVGG16以降のネットワークが進歩していないのか調べます。

# 4. 広角眼底データセット＆データ分割
　広角眼底データセットの説明とどのようにデータ分割したかはこちらの[記事(広角眼底画像データセットで画像分類)] (https://qiita.com/burokoron/items/8c011c219b7545c50355)を参照してください。

# 5. モデル構築＆学習
　この章では入門向けとして実装済みネットワーク＆ImageNet[^2]の学習済みモデルでFine-turningする方法を説明します。ちなみに広角眼底データセットはImageNetと画像のドメインが違いすぎるのでFine*turningは精度向上に貢献しないですが、収束速度向上には貢献します。詳細はこちらの[記事(医用画像への転移学習の有効性について)] (https://speakerdeck.com/uchi_k/lun-wen-shao-jie-yi-yong-hua-xiang-hefalsezhuan-yi-xue-xi-falseyou-xiao-xing-nituite-transfusion-understanding-transfer-learning-for-medical-imaging)を参照してください。
　こちらの[記事(広角眼底画像データセットで画像分類)] (https://qiita.com/burokoron/items/8c011c219b7545c50355)からモデル構築部分を変更します。学習パラメータは学習率を`0.00001`に変更しました。まずはライブラリを`import`します。

```py
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Activation
```

そしてネットワークを構築します。今回はVGG16を例に説明します。まず、VGG16をベースモデルとして読み込みます。今回はImageNet[^2]の学習済み重みからのFine-turnigが目的なので`include_top=False`として最終畳み込み層までのネットワークを構築し、`weights='imagenet'`でImageNet[^2]の学習済み重みを読み込みます。そして[記事(広角眼底画像データセットで画像分類)] (https://qiita.com/burokoron/items/8c011c219b7545c50355)と同じように、全結合層を読み込んだVGG16に組み合わせます。

```py
base_model = VGG16(include_top=False, weights='imagenet', pooling='avg',
                   input_shape=(image_size[0], image_size[1], 3))
x = Dense(256, kernel_initializer='he_normal')(base_model.output)
x = Dense(classes, kernel_initializer='he_normal')(x)
outputs = Activation('softmax')(x)
model = Model(inputs=base_model.inputs, outputs=outputs)
```

他のネットワーク、例えばResNet50を使用する場合は`VGG16`を`ResNet50`に変更すれば利用できます。他のネットワークでのサンプルコードは[こちら] (https://github.com/burokoron/StaDeep/tree/master/fine-turning)にアップロードしています。ちなみにEfficientNet-B0はリリースはされてないですが、実装はされているので、GitHubの[keras-team/keras-applicationsのefficientnet.py](https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py)をダウンロードして使用しました。

　学習結果は以下のようになりました。NASNetMobile[^7]は唯一学習lossと検証lossの乖離がないですね。accracyは乖離してますが。EfficientNet-B0[^8]はさすが最新モデルだけあってなんか美しい？です。
![ネットワーク比較.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405329/2fdaf5cd-c927-9dad-9f0e-243c0371ff2e.png)

# 6. 評価
　評価はこちらの[記事(広角眼底画像データセットで画像分類)] (https://qiita.com/burokoron/items/8c011c219b7545c50355)と同様にF値で行いました。結果を以下に示します。

<details><summary>詳細結果</summary><div>

```py
# VGG16
              precision    recall  f1-score   support

         AMD       0.28      0.53      0.37        75
       DR_DM       0.81      0.75      0.78       620
         Gla       0.73      0.76      0.74       459
          MH       0.12      0.22      0.16        32
      Normal       0.75      0.75      0.75       871
          RD       0.93      0.77      0.84       176
          RP       0.91      0.78      0.84        50
         RVO       0.84      0.60      0.70       107

    accuracy                           0.73      2390
   macro avg       0.67      0.65      0.65      2390
weighted avg       0.76      0.73      0.74      2390

# ResNet50
              precision    recall  f1-score   support

         AMD       0.26      0.56      0.36        75
       DR_DM       0.95      0.61      0.74       620
         Gla       0.78      0.61      0.68       459
          MH       0.30      0.25      0.27        32
      Normal       0.64      0.84      0.73       871
          RD       0.85      0.85      0.85       176
          RP       0.64      0.88      0.74        50
         RVO       0.85      0.57      0.68       107

    accuracy                           0.71      2390
   macro avg       0.66      0.65      0.63      2390
weighted avg       0.76      0.71      0.71      2390

# InceptionV3
              precision    recall  f1-score   support

         AMD       0.28      0.53      0.37        75
       DR_DM       0.84      0.68      0.75       620
         Gla       0.74      0.68      0.71       459
          MH       0.29      0.16      0.20        32
      Normal       0.69      0.81      0.74       871
          RD       0.91      0.80      0.85       176
          RP       0.83      0.76      0.79        50
         RVO       0.64      0.52      0.57       107

    accuracy                           0.72      2390
   macro avg       0.65      0.62      0.62      2390
weighted avg       0.74      0.72      0.72      2390

# DenseNet121
              precision    recall  f1-score   support

         AMD       0.25      0.60      0.36        75
       DR_DM       0.94      0.66      0.78       620
         Gla       0.82      0.58      0.68       459
          MH       0.45      0.16      0.23        32
      Normal       0.65      0.87      0.74       871
          RD       0.94      0.82      0.88       176
          RP       0.98      0.86      0.91        50
         RVO       0.91      0.64      0.75       107

    accuracy                           0.73      2390
   macro avg       0.74      0.65      0.67      2390
weighted avg       0.78      0.73      0.73      2390

# NASNetMobile
              precision    recall  f1-score   support

         AMD       0.25      0.52      0.34        75
       DR_DM       0.84      0.66      0.74       620
         Gla       0.59      0.81      0.69       459
          MH       0.16      0.22      0.18        32
      Normal       0.72      0.70      0.71       871
          RD       0.94      0.76      0.84       176
          RP       0.94      0.60      0.73        50
         RVO       0.75      0.43      0.55       107

    accuracy                           0.69      2390
   macro avg       0.65      0.59      0.60      2390
weighted avg       0.73      0.69      0.70      2390

# EfficientNet-B0
              precision    recall  f1-score   support

         AMD       0.32      0.44      0.37        75
       DR_DM       0.94      0.60      0.73       620
         Gla       0.79      0.57      0.66       459
          MH       0.21      0.38      0.27        32
      Normal       0.63      0.88      0.73       871
          RD       0.94      0.85      0.89       176
          RP       0.80      0.80      0.80        50
         RVO       0.83      0.56      0.67       107

    accuracy                           0.71      2390
   macro avg       0.68      0.63      0.64      2390
weighted avg       0.76      0.71      0.71      2390
```
</div></details>

また、ImageNet[^2]での結果と今回の結果を以下の表にまとめました。ImageNet[^2]での結果はGitHubの[keras-team/keras-applications] (https://github.com/keras-team/keras-applications/blob/master/README.md)から取得しました。ImageNet[^2]ではVGG16以降のネットワークはたしかにVGG16より高精度な結果になっていますが、今回の広角眼底データセット[^1]ではVGG16より優れていたネットワークはDenseNet121のみとなりました。さらに、テストデータは2390件なので、95%で有意差検定すると±1～2%くらいブレが生じることになるので、DenseNet121が統計的にVGG16より優れているとは言えない結果となりました。

|ネットワーク|ImageNet Top-1 Acc [%]|広角眼底データセット F1-score|
|:--:|:--:|:--:|
|VGG16|71.268|0.65|
|ResNet50|74.928|0.63|
|InceptionV3|77.898|0.62|
|DenseNet121|74.972|0.67|
|NASNetMobile|74.366|0.60|
|EfficientNet-B0|77.190|0.64|

# 7. まとめ
　本記事では広角眼底データセット[^1]を用いて本当にVGG16以降のネットワークは進歩しているのかを調べました。また、入門向けとして、実装済みネットワーク＆ImageNet[^2]の学習済み重みをFine-turningする方法を説明しました。実験の結果、VGG16より優れていたのはDenseNet121のみでした。しかし、有意差はなく、統計的に優れているとは言えませんでした。
　今回は広角眼底データセットで行いましたが他のデータセットで行うとまた違う結果になると思いますし、画像拡張処理はほとんどしていないので、そのあたりも最新手法にすれば結果が変わってくる可能性もあります。ただ、私は普段、主に眼科領域の医用画像を扱っていますが、だいたいDenseNetが良い結果を出すので、経験通りの結果かなと思います。(なぜDenseNetが良い傾向があるのかわからないので誰か教えてほしいです。)
　ちなみに[前回(広角眼底画像データセットで画像分類)] (https://qiita.com/burokoron/items/8c011c219b7545c50355)の単純な10層CNNのF値は0.59だったので、ネットワークをDenseNet121にすることで0.08向上して0.67にすることができました。今後もいろいろな最新手法を適用して精度向上をめざしたいと思います。

[^1]: [Tsukazaki Optos Public Project] (https://tsukazaki-ai.github.io/optos_dataset/)
[^2]: [ImageNet: A large-scale hierarchical image database] (https://ieeexplore.ieee.org/document/5206848)
[^3]: [Very Deep Convolutional Networks for Large-Scale Image Recognition] (https://arxiv.org/abs/1409.1556)
[^4]: [Densely Connected Convolutional Networks] (https://arxiv.org/abs/1608.06993)
[^5]: [Deep Residual Learning for Image Recognition] (https://arxiv.org/abs/1512.03385)
[^6]: [Rethinking the Inception Architecture for Computer Vision] (https://arxiv.org/abs/1512.00567)
[^7]: [Learning Transferable Architectures for Scalable Image Recognition] (https://arxiv.org/abs/1707.07012)
[^8]: [EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks] (https://arxiv.org/abs/1905.11946)