TPUを使った写真の美しさスコア付けモデルの学習

# 概要
TPUの勉強のため、1から10の10段階で写真の美しさをスコア付けするDeep Learningモデルを学習させました。

# 写真の美しさのスコア付け
入力された写真を1から10の10段階でスコア付けをします。類似の研究事例としてはGoogleの[NIMA](https://arxiv.org/abs/1709.05424)[1]などがあります。学習用データセットとして[AVA dataset](http://refbase.cvc.uab.es/files/MMP2012a.pdf)[2]を使用しました。AVA datasetは約25万枚の写真に対し、複数のアノテータが10段階のスコア付けを行ったデータセットになります。加重平均を取ることで、その写真に対する美しさのスコアを得ることができます。

# ソースコード
ソースはこちらに格納しました。
https://github.com/myzkyuki/aesthetic_image

# TPUの利用
Google Colabにおいて無料で利用でき、高速な学習が可能なTPUを使用しました。TPUの利用にあたっては以下のサイトを参考にさせていただきました。

- [TensorFlow2.0 with KerasでいろいろなMNIST（TPU対応）](https://qiita.com/koshian2/items/5029028fe6d01b243f44)
- [Tensorflow 2.0 と Colab TPU, GCS を使った楽しいfine-tuning](https://colab.research.google.com/drive/1PfQizpQrs1SZhXdycREUJJMyUzg6CJbL)
- [Google Cloud Colabノートブック](https://cloud.google.com/tpu/docs/colabs?hl=ja)
- [Custom training with tf.distribute.Strategy](https://www.tensorflow.org/tutorials/distribute/custom_training)
- [Distributed training with TensorFlow](https://www.tensorflow.org/guide/distributed_training)
- [tensorflow/modelsのコード](https://github.com/tensorflow/models/blob/master/official/modeling/training/distributed_executor.py)

# 学習時の工夫点
学習では色々ハマりどころがあり、以下の点を工夫しました。

## Cloud Storageの使用
[TPUではローカルファイルシステムを使用できない](https://cloud.google.com/tpu/docs/troubleshooting?hl=ja#cannot_use_local_filesystem)ため、TPUを使った学習を行う場合Cloud Storageを使用する必要があります。この際、学習時間を短くするため、作成するバケットは`us-central1`に作成します。当初、`asia-northeast1`に作成したところ、TPUを使っているのに学習が非常に遅くなってしまいました。詳細は[コチラ](https://qiita.com/kasagon/items/2dd5475ce00f16333a6a)をご参照ください。

## データ拡張
一般的に画像の学習ではデータ拡張として、回転・平行移動・明るさ変更・切り抜きなどを行います。しかし、それらを行ってしまうと写真の美しさに影響すると考えられるため、今回のデータ拡張は左右反転のみ適用しました。

## 画像サイズの正規化
CNNの入力に対しては縦横を同じ長さに揃えてリサイズする必要にあり、3種類の方法があります。いずれも写真の美しさスコアへの影響が考えられますが、一番影響が少なそうな`1. アスペクト比を変更してリサイズ`を行いました。

|#|リサイズ方法|スコアへの影響の懸念点|
|:-:|:----------|:------------|
|1|アスペクト比を変更してリサイズ|画像中のオブジェクトの形が歪む。|
|2|アスペクト比を維持してパディング|余白に挿入された黒帯がスコアに影響する。微妙な写真でも評価が高い写真と似たアスペクト比だとスコアが高くなりそう。|
|3|アスペクト比を維持して切り抜く|美しさの評価に影響するオブジェクトが取り除かれ、構図が崩れる。|

## モデル
モデルには軽めのSoTAモデルであるEfficientNet-B0を使用しました。

## ロス関数
2つのロス関数を試しましたが、Multi Lossの方が精度が高くなりました。

- 蒸留のようにアノテータによるスコア付けの分布を学習させるためKLDivergence
- CategoricalCrossentropyとMSEの和をとった[Multi Loss](https://arxiv.org/abs/1710.00925)[3]


## 最適化関数
当初EfficientNetで使用されている、ExponentialDecayを用いたRMSpropを試したのですが、勾配爆発してしまったため、Adamにしたところうまく進みました。

# 結果
15エポックほどの学習により、以下の結果が得られました。

## Train lossとValidation Loss
Golabの時間制限により何回かチェックポイントから始めたため、Train Lossは余計な線が入ってしまっていますが、学習がちゃんと進んでいることがわかるかと思います。
<img width="352" alt="train_loss.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336552/0d092de3-ea38-4dd2-bacb-833d44dae78e.jpeg">
<img width="352" alt="val_loss.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336552/51fae5b0-717e-9234-7584-746daaafaf5f.jpeg">

## 正解スコアと予測スコアの分布
Validationデータにおける正解スコア(true)と予測スコア(pred)の分布は以下のようになりました。まだ、バラツキがありますが、緩やかな相関関係はあるかと思います。
![prediction_plot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336552/8e93519d-0b8e-6a7b-b5e8-1669443c673c.jpeg)

## 予測サンプル
AVA datasetに対する予測とと正解のサンプルです。予測スコアとしては差がありますが、スコア順に並べると大体近い順序になるのではないかと思います。

Landscape写真
![landscape_prediction_samples.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336552/78359aee-d1e6-0885-acc5-0defe36102e6.jpeg)

Animals写真
<img width="999" alt="animals.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336552/d52838ff-ce2c-3ccf-457f-dc07cb2c1e6d.jpeg">

# まとめ
TPUを使ってAVA datasetを用いた写真の美しさスコア付けを行うモデルの学習を行いました。精度は改善の余地がありそうですが、それなりに納得性のあるスコア付けをできているのかと思います。こういった、人によってアノテーション結果が分かれるデータの学習は評価が難しいと思いました。画像によっては予測スコアの方が正解スコアよりも納得感がある画像もあったりします。

# 参考
以下の文献を参考にさせていただきました。
[1] [NIMA: Neural Image Assessment](https://arxiv.org/abs/1709.05424)
[2] [AVA: A Large-Scale Database for Aesthetic Visual Analysis](http://refbase.cvc.uab.es/files/MMP2012a.pdf)
[3] [Fine-Grained Head Pose Estimation Without Keypoints](https://arxiv.org/abs/1710.00925)