ヒストグラムを活用した、オノマトペな様々な情景を連想させる画像の分類

１．はじめに
============
　Sonyとレッジが企画するAI開発コンテスト「[Neural Network Console Challenge](https://nnc-challenge.com/)」に挑戦。３つあるテーマの一つの『人物画像をNNCで学習させ新しいオノマトペ（擬音語/擬声語/擬態語）の画像カテゴリ分類を作り出す』に挑んでみました。

【更新】受賞ならず！しかも、ツイッターライブであった表彰式で「受賞作以外の興味深いアウトプット」の一つとして取り上げられるという、逆に悔しい結果となりました＞＜。。。ｸｿｰ笑

２．実験環境＆データ
============
・Google Colaboratory(GPU,python3)
・Neural Network Console(NVIDIA_Tesla_V100、K80（クラウド）＆ローカル版)

・学習用データ提供：PIXTA

３．オノマトペ（擬音語/擬声語/擬態語）とは
============

　グーグルによると、
>自然界の音・声、物事の状態や動きなどを音(おん)で象徴的に表した語

らしいです。ここではこの[HP](https://rondely.com/zakkaya/dic5/index.htm)を参考に、様々な情景を連想させる６つの擬態語に関する画像分類を試みます。採用した単語は以下の通りです。

・にこにこ（「笑う」、「微笑む」といったキーワード）
・わいわい（「元気」、「楽しい」　　　　〃　　　　 ）
・きらきら（「光る」、「明るい」　　　　〃　　　　 ）
・のんびり（「ゆるい」、「怠ける」　　　〃　　　　 ）
・ふんわり（「弱い」、「柔らかい」　　　〃　　　　 ）
・じろじろ（「見る」、「眺める」　　　　〃　　　　 ）

４．学習データ
============
　コンテストでは、PIXTA社が提供する人物画像1万枚が学習データとなります。問題は、データにアノテーション（タグ付け）する工程。タスクの拡張性も踏まえ、手作業でのタグ付け作業を減らすための手法も検討し、「擬音と画像のヒストグラムが結びつけられれば、アノテーションの自動化ができるのでは？」と思い至りました。そこで今回は、以下の方法でデータを作っていきます。

###手順① 分類したい擬音語を連想させる画像を目視で抽出
まず、以下の画像セットを作りました。
1.にこにこ
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/b724e054-0c23-5059-598b-0ab16d849556.png)
2.わいわい
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/930deddc-ef40-06a0-32c0-ca5a57cabce6.png)
3.きらきら
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/850979d2-c59a-a348-2f35-92f9dcdcb4e5.png)
4.のんびり
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/dfa7ef04-8854-72aa-5f28-3eb616e9f7dd.png)
5.ふんわり
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/88f7b1f3-ca15-5a12-76e5-4f1b8ffe4daf.png)!
6.じろじろ
![learning_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/f317ef4c-814f-76ef-bb9b-963886b385f5.png)
###手順② 残りのPIXTA画像から学習データを量産
　opencvを用い①で抽出した画像のヒストグラムを計算。残りのPIXTA画像のヒストグラムも求め、各抽出画像との類似度を算出していき、値が近い画像が属するカテゴリーに分類していきます。Google Colaboratory上で以下のプログラムを用いて処理しました。

```python
import requests
import json
import numpy as np
import csv
import cv2
import matplotlib.pyplot as plt
import os
import shutil

#分類元フォルダー
image_dir =  "./image_dir"
image_arr = os.listdir(image_dir)

#親ディレクトリー
train_dir_arr = os.listdir("./onomatope")

result_arr = []
for img_name in image_arr:
    #分類元の画像ヒストグラム
    target_img_path = image_dir + "/" + img_name
    img = cv2.imread(target_img_path)
    target_hist = cv2.calcHist([img], [2], None, [256], [0, 256])
    max_value = 0

    for train_dir in train_dir_arr:
      train_img_arr = os.listdir("./onomatope/" + train_dir)
      for train_img in train_img_arr:
        try:
            target_img_path_2 = "./onomatope/" + train_dir + "/" + train_img
            img_2 = cv2.imread(target_img_path_2)
            comparing_hist = cv2.calcHist([img_2], [2], None, [256], [0, 256])
            #最近傍を計算
            #ヒストグラムを比較する
            result = cv2.compareHist(target_hist, comparing_hist, 0)
            if result > max_value:
                max_value = result
                max_category = train_dir
        except:
          import traceback
          traceback.print_exc()
    #カテゴリーフォルダーにコピー
    if max_value > 0.7:
       shutil.copy(target_img_path,  "./drive/NNCC/onomatope/" + max_category)

```
この処理を通して、計4341枚の学習データを準備しました。

５．ニューラルネットワークで機械学習
============
　準備した学習データを使い、画像分類するためのネットワークを構築します。ローカルのNNCで、6クラスある128*128*3の入力画像をリサイズして作成し、80％を学習データに、残りの20％を検証用データに分けてクラウド版NNCにアップロード。サンプルプログラムの一つの「ResNet-50」を元に1000エポックの学習を実施しました。
![training_result_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/94beb5e3-50e3-c986-8451-32b1fb9ea83d.png)
　要した学習時間は、NVIDIA_Tesla_V100を使って約66分でした。全データでの比較はしていませんが、小規模データでの実測値だとCPUと比較し１０分の１ほどの時間で学習を完了させることができました。

６．精度評価
============
　評価データの分類結果は以下図の通りとなりました。Accuracy：0.7894、Avg.Precision：0.8045と8割近い精度をあげることができました。各ラベルはそれぞれ、

+ label=0 --- ふんわり
+ label=1 --- じろじろ
+ label=2 --- きらきら
+ label=3 --- にこにこ
+ label=4 --- のんびり
+ label=5 --- わいわい

となります。
![learning_result_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/e12e6086-0dc5-e091-cf78-6b080617f7ef.png)
　label=4(のんびり)は、Recall,Precision共に数値が高く0.9を上回り、うまく分類ができているといえそうです。学習元となる画像が赤色によった画像なため、高い精度が上げられたと考えられます。
　興味深かったのは、見た目の色合いが近いにも関わらずlabel=3（わいわい）、label=5（わいわい）で高い分類精度を残せた点。色合いだけでなく、機械学習で特徴量をうまく抽出できた結果だと思われます。
　一方で精度の低かったlabel=1（じろじろ）は、他に比べ学習元となる画像数が１割未満と少なかったため、精度が上げられませんでした。

評価画像の分類結果の一部は以下の通り（分類に失敗している画像も含みます）。

+ label=0 （ふんわり）
![funnwari.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/f15644fa-dd6f-b99c-df58-681f59f678df.png)
+ label=1 （じろじろ）
![jirojiro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/fba4b2e5-0a38-7c62-2c55-23767b5d7d66.png)
+ label=2 （きらきら）
![kirakira.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/a8b1d23b-a00c-5d40-e623-65ab6d43026b.png)
+ label=3 （にこにこ）
![nikonko.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/9155b906-f8d8-8ced-366c-bea95a82041f.png)
+ label=4 （のんびり）
![nonbiri.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/1a199fbe-cbbc-c83f-316a-e5b95261116e.png)
+ label=5 （わいわい）
![waiwai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590631/19e26036-4765-bc9c-a6b8-f4fd469fb189.png)

７.まとめと考察
============
+ 画像のヒストグラムを元にした、様々なシーンを想起させる６種の擬音を分類可能なモデルをResNetを活用し構築した
+ 80％近い分類性能を達成
+ 学習データ作りのためのタグ付けの作業負荷を軽減するスキーマーも併せて考案できた

　今回は実験期間とリソースが限られるため、小規模での学習に留まりヒストグラムもRGBの中の赤色のみしか考慮できませんでした。これらを踏まえ、本手法は他のオノマトペ画像の分類も考慮した、より高精度の新たなモデルが比較的容易に作成できる可能性も残していると思われます。