[Neural Network Console Challenge]NNCを使って人の感情で画像を分類してみた

#はじめに
Sonyとレッジが企画するAI開発コンテスト「[Neural Network Console Challenge](https://nnc-challenge.com/)」に参加しました！
私は『NNCで画像を学習し人の感情によって分類』に挑戦し、PIXTAの写真素材をポジティブな感情の画像とネガティブな感情の画像に分類し、約80%の精度を出すことができました。

[追記]
https://support.dl.sony.com/public-projects/2020/04/01/nnc-challenge_faceemotionclassification/
プロジェクトを公開しました。
Neural Network Console をご利用の方は上記ページ中の「Copy the project to Neural Network Console Cloud」からプロジェクトをコピーできます。

#動機
今回このコンテストに参加した動機は、

- NNC愛用家であること
- 1万枚のデータセットがあること
- GPU利用枠10,000円分を付与されること

です。
今まで無料のNNC（windows版）を使っていたので私のGPUなしPCでは画像を使った学習はしたくてもできませんでした...
なので、3つ目のGPU利用枠10,000円分はかなり大きな決め手となりました。
今回初めてGPUを使って、圧倒的計算能力に感動したのでGPUとCPUの比較も最後に載せています。

#アノテーション
このコンテストはテーマが自由な分、アノテーションも自分でしないといけない...

> 手順4 新たな画像カテゴリ分類を考え、ダウンロードしたデータにアノテーション（タグ付け）する

正直、１万枚の画像のアノテーションは気が滅入る...
せめてもの作業効率化のために、簡単な画像仕分けプログラムを書いて暇なときにぼちぼちやりました。

##分類する感情のカテゴリ
そもそも感情って何種類あるんだ？どこまで細分化するんだ？
という疑問が湧き、調べてみるとこんな本がありました。

> [『感情表現辞典』 中村 明](https://www.amazon.co.jp/%E6%84%9F%E6%83%85%E8%A1%A8%E7%8F%BE%E8%BE%9E%E5%85%B8-%E4%B8%AD%E6%9D%91-%E6%98%8E/dp/4490103395)

この本は人間の感情を喜，怒，哀，怖，恥，好，厭，昂，安，驚の10種類に分類し、それぞれに合った表現の言葉を収録しています。
これなら人間の感情を網羅できているみたいですが、細かすぎるかも...(喜と好の区別とか)

さらに調べてみるとこんな論文が見つかりました。

> [多次元感情ベクトルを考慮した名言検索手法の提案](https://ipsj.ixsq.nii.ac.jp/ej/?action=repository_action_common_download&item_id=75505&item_no=1&attribute_id=1&file_no=1)

この論文では『感情表現辞典』をもとに感情の次元圧縮をしています。
その結果、

- 喜，好，昂，安
- 哀，怖，恥，厭
- 怒
- 驚

の４種類に分類。
これをもとに１万枚のデータセットを仕分けしてみました。
しかし、数百枚仕分けして気づいたことが...
このデータセット、怒と驚がほとんどない！
といことで、

- ネガティブ（哀，怖，恥，厭，怒）
- ポジティブ（喜，好，昂，安，驚）

の２つのカテゴリに分類しました。
また、このデータセットには風景の画像もあり、感情が読み取れないので風景は別にしました。

その結果、下のようになりました。

- ネガティブ 5704枚
- ポジティブ 4121枚
- 風景 175枚

###ネガティブの画像例
![pixta_21936140_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/de4bfe0c-7350-dba3-6cc7-ec5e7b5f82a1.jpeg)![pixta_26390829_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/3aa9a9f1-d91d-8ef7-c6e8-0a008a3b1f5a.jpeg)

###ポジティブの画像例
![pixta_22374690_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/9985bd2e-863f-47ae-75e7-064f01174186.jpeg)![pixta_26390326_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/550b2e73-7e21-e5f6-1805-cf1e39fe759d.jpeg)

###風景の画像例
![pixta_16544720_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/ccd35289-a447-3a69-1f6e-325ada18b7e1.jpeg)![pixta_21790230_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/0e3fc7f0-8805-bd9c-13cf-29c257bf1bf4.jpeg)
学習用データ提供：PIXTA

#学習
学習にはもちろんNNCを用いました。


##データの整形
このデータセットの画像はサイズが様々でリサイズする必要があります。
そこで、NNCのデータセット作成機能を使ってデータの整形を行いました。
整形後の画像サイズは顔の表情をある程度読み取れるくらいのサイズとして256x256にしました。

Shaping Mode : Padding
Output Color Ch : 3(RGB)
Output Width : 256
Output Height : 256
Training ratio : 90%
Validation ratio : 10%
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/4cb121bc-b312-c0af-3b8b-2192f724a7f2.png)

##まずはそのまま

学習モデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/a94bf83e-92d2-10ce-af52-7255ab14678d.png)

学習曲線
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/0fd511ec-b17c-e0bc-a4e8-bc51b3337eed.png)


混同行列
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/1704f7da-2dbb-0f28-633b-27baa8a820c3.png)


精度71%！
でも、ポジティブの分類精度が悪いなぁ...
風景はデータ数が少ないので仕方ない気がします。


##顔に注目したい！
写真から感情を読み取るには顔の表情が重要ということで、顔検出データセットで事前学習することにしました。
顔検出データセットには

> [kaggle : Face Detection in Images](https://www.kaggle.com/dataturks/face-detection-in-images)

を用いました。
このデータセットには409枚の複数人が写っている画像があり、顔領域のバウンディングボックスもあります。

学習には下のようなモデルを用い、感情分類にも用いれるように入力は同じ形にしました。
この学習モデルは感情分類にも用いる前半部分(Share_Unit)と顔検出用の後半部分(Face_Unit)に分かれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/4ce4d888-5b8f-6e92-9131-7d70cf02b04a.png)


##再学習
再学習では事前学習の学習済みモデルのShare_Unitの重みを初期値として用いました。
また、Face_Unitに代わって感情分類のためのEmotion_Unitを作り、下のようなモデルで学習しました。

学習モデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/6c9c3e86-c98d-fc8a-3fb1-a68908bb5ae9.png)

学習曲線
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/b38f2779-a3f9-b86f-3996-e94b4fa6baca.png)


混同行列
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/6a4f9496-f173-be2a-962f-71601c0d0d33.png)

精度79.4%！！！
なんと、ポジティブの精度が50.23%から69.35%に上がりました！！！
おそらく、顔に注目したことにより笑顔をきちんと認識できるようになったのではないでしょうか。

#分類結果
##正しく分類された画像例
###ネガティブ
![pixta_21936140_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/de4bfe0c-7350-dba3-6cc7-ec5e7b5f82a1.jpeg)![pixta_26390829_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/3aa9a9f1-d91d-8ef7-c6e8-0a008a3b1f5a.jpeg)

###ポジティブ
![pixta_22374690_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/9985bd2e-863f-47ae-75e7-064f01174186.jpeg)![pixta_26390326_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/550b2e73-7e21-e5f6-1805-cf1e39fe759d.jpeg)

###風景
![pixta_16544720_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/ccd35289-a447-3a69-1f6e-325ada18b7e1.jpeg)![pixta_21790230_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/0e3fc7f0-8805-bd9c-13cf-29c257bf1bf4.jpeg)
学習用データ提供：PIXTA




##誤って分類された画像例
###ネガティブがポジティブに分類された例
![pixta_22857001_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/125cbee6-769b-766c-e202-c7262764bf81.jpeg)![pixta_35235896_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/223a5303-3f33-de3d-d64f-440a5c9cd179.jpeg)



###ポジティブがネガティブに分類された例
![pixta_24785471_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/ade2a068-e90d-8b17-20cc-c43a07c34954.jpeg)![pixta_25108831_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/83cfff5c-665b-b4f3-416a-8efa1552ac4a.jpeg)

###風景がネガティブに分類された例
![pixta_31213454_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/b817743d-70ca-6ddc-0d7f-d48c74f6d815.jpeg)![pixta_21790213_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/4d5b5d2f-5a93-5651-0139-75b3ac12293e.jpeg)
学習用データ提供：PIXTA



#GPUとCPUの比較
再学習の時に用いた学習モデルでGPUとCPUの比較を行いました。
ちなみに、
GPUはTesla V100
エポック数は200
バッチサイズは64
です。

GPU
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/3907a53b-499d-0de5-8c13-0e08b57b2992.png)

CPU(学習が全然終わらなくて10エポックが終了したところで止めました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607813/12c044ee-dfe9-72aa-eae7-aee0a326c774.png)

結果、
GPUは53分
CPUは14日15時間

その差は約400倍と圧倒的な差でした（笑）