音声データの喜怒哀楽分類とレコメンド

# はじめに
Neural Network Console Challengeコンテストのレポートです。第二回目はAudiostockの音声（BGM）データ約10,000曲をNeural Network Console（以下NNC）を用いて解析します。
[Neural Network Console Challenge](https://nnc-challenge.com/)

テーマは「自由な発想で音声データを解析する」を選択しました。音楽を選ぶ際にJ-Pop、ロック、ジャズなどジャンルから選ぶことが多いですが、もう少しだけ明るい曲、もう少し落ちつた曲など、微調整が難しいです。スマートスピーカーに微調整を指示する言葉が見つかりません。そこで音楽を喜怒哀楽の尺度で数値化し、類似度の高い曲のレコメンドに取り組みました。

## 作業環境等
NNCはクラウド版を使用しました。機械学習で音声の波形データを扱うのは初めてでしたので、チュートリアル動画やインターネット検索などで事前学習しました。

- [クラウド版チュートリアル：はじめてのNeural Network Console~セットアップからサンプルプロジェクトの実行まで~（動画）](https://youtu.be/b3wfiozov6k)
- [Windows版チュートリアル：5分で構築するCNN](https://www.youtube.com/watch?v=Vj7yfyiux0w)


# BGMデータの分析とテーマの決定
1曲24秒に加工されたデータが提供されていました。短い曲は無音で埋める、長い曲は打ち切られていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/f7da4963-6758-1c56-5834-a74dc19d91cb.png "BGMデータの波形サンプル")

## タグ情報の分析
曲ごとのタグ情報をテキストマイニングツールで分析しました。明るい、楽しい、切ないなど感情に関わるキーワードが含まれており、このタグをベースに喜怒哀楽を分類する方向にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/9c59025f-4e3d-7958-ee80-cd0795be3f74.png "ワードクラウド")
【参考】[User Localテキストマイニングツール](https://textmining1.userlocal.jp/)

## BGMの感情タグと曲数
|感情分類 |タグ |曲数 |
|---|---|---|
|喜 |明るい, 楽しい |1699|
|怒 |激しい, 力強い, 踊る, 弾む, 走る |624|
|哀 |切ない, 悲しい, 寂しい |562|
|楽 |落ち着く, 優しい, 癒す |788 |
※複数分類に跨る曲が含まれています。


# 音声データ学習の試行
タグの喜怒哀楽がそのまま使えるか分かりませんでしたが、NNCで分類して評価してみました。

## ネットワーク設計
チュートリアル動画を参考に波形データをCNNで処理しています。結果は回帰による喜怒哀楽の度合いを求めるようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/edd84d83-a4d5-4ee0-9333-6da1fc18cb6a.png "ネットワーク設計")

【入力層のコツ】
波形データの入力(ヘルツ × 秒数, 1)
波形を-1～1に変換する(32768で割る)
画像と同じ3次元に変換

【中間層のコツ】
Convolutionのフィルターは1次元（3×3 → 1×3）
MaxPoolingは1次元（2×2 → 1×2）
最後が10以下になるように調整

【出力層のコツ】
Global Average Poolingで位置に不変な認識に
回帰は全結合層＋SquareError

## 学習データ
訓練用300曲、検証用100曲です。

|感情分類|訓練用 |検証用 |
|---|---|---|
|喜 |196 |34 |
|怒 |52 |27 |
|哀 |41 |21 |
|楽 |49 |18 |

## 学習結果の評価
CPUで学習を実行したところはメモリサイズエラーとなりましたので、GPUで学習しました。GPU【NVIDIA® TESLA® K80 GPU x1】での学習は3分44秒でした。学習結果の混同行列では、Accuracyが0.39と低め、Recallの「怒、哀」もかなり悪い結果でした。
ネットワークの改良はしてみたもの、提供されたタグそのままのではダメそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/2fea3ead-bb09-fa51-0abc-5f5cadebd088.png "NNC試行結果の混同行列")


# アノテーションと学習
アノテーションと学習で改良したポイントです。ひたすら音楽を聴いて、喜怒哀楽が明確になるように分類しました。３周してようやく分類基準がまとまってきました。

- 喜怒哀楽の分類基準が曖昧　⇒　定義を明確にする
- 1曲に複数分類がある（開始は哀しいが途中から明るくなる）　⇒　除外
- 分類に迷った曲　⇒　除外
- 短い曲の扱いが不明　⇒　3秒以下は除外
- 1曲の喜怒哀楽4種類の度合いをアノテーションするのは難しい　⇒　1曲1分類、特徴有無を0,1で分類
- 訓練用、検証用データをランダムに選ぶ

## 学習イメージ
一度に喜怒哀楽の４分類にするのは難しく、個々にデータを用意して学習しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/8243d79a-bca6-c3e5-c681-77735a9d60e8.png "概念図")

## 特徴量「喜怒哀楽」の定義
喜怒哀楽とは、喜びと怒り、悲しみと楽しみという様々な感情の代表的な4つです。「喜び」と「楽しみ」が似通っているように思えますが、「喜」は成し遂げたことにうれしく思い湧き上がってくる感情、「楽しみ」は外部からの刺激によって味わう愉快な気持ちのようです。
個人的な感覚となりますが、下記の基準でアノテーションしました。

|感情分類 |アノテーション基準 |ドラクエBGMに例えると|
|---|---|---|
|喜 |明るい, 楽しい, アップテンポ, 高音, 朝 |オープニング, レベルアップ, 町, フィールド（行進）|
|怒 |激しい, 力強い, ハイテンポ, 重低音, 夜, ロック |戦闘, 洞窟, 呪い|
|哀 |切ない, 悲しい, スローテンポ |全滅, 教会, 牢獄|
|楽 |落ち着く, 癒し, スローテンポ, 高音, 昼・夕, バラード |城, 宿屋に泊まる, セーブ|
【参考】[喜怒哀楽とは？](https://biz.trans-suite.jp/10648#i-2)

## アノテーション後の曲数
計1266曲、訓練用950曲、検証用316曲ができました。訓練用と検証用はランダムに分けています。

|分類|訓練用 |検証用 |
|---|---|---|
|喜 |371 |124 |
|怒 |256 |85 |
|哀 |106 |35 |
|楽 |217 |72 |

## ネットワーク設計見直し
出力を1つに変更し、喜怒哀楽の個々に実行するようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/5fb3ea40-bb99-ab93-e8c6-1030b0780456.png "ネットワーク設計")

## 学習
GPU【NVIDIA® TESLA® K80 GPU x1】での学習は喜怒哀楽のいずれも8分程度で終わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/661a4e7f-5737-cd09-258a-2bc930e389e7.png "喜怒哀楽４種類の学習曲線")

## 学習結果の評価
「怒」はよい数値が出ていますが、「哀」は再現率Recallが今一つです。他と比べてデータが少なかった、アノテーションが不十分のが原因かもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/cc60c543-f013-95f6-974e-b2f73ace482f.png "喜怒哀楽４種類の学習結果")

別表にまとめたものです。

|分類 |Accuracy |Avg.Precision |Avg.Recall |Avg.F-Measures |
|---|---|---|---|---|
|喜 |0.769 |0.7765 |0.7314 |0.7403 |
|怒 |0.919 |0.889 |0.8548 |0.8697 |
|哀 |0.8892 |0.4446 |0.5 |0.4707 |
|楽 |0.807 |0.7988 |0.596 |0.6085 |

下表は曲ごとの評価結果です。上段が哀しくない曲、下段が哀しい曲です。「哀」とそれ以外には差がついており、特徴量が出せています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/0364c8cc-ca31-c044-88b5-70580c3600f7.png "a")


# 学習モデル公開とBGMデータへの推論実行
クラウドにアップしたモデルをAPIで呼び出し、BGMに喜怒哀楽の特徴量を付与しました。

## 学習モデル公開と推論実行
喜怒哀楽の4種の学習モデルをAPIとして公開しました。Pythonのサンプルコードを編集してAPIを呼び出し、喜怒哀楽4曲ずつ、計16曲に特徴量を付与しました。1リクエスト当たり、2秒程で結果が返ってきました。（訓練や検証で未使用のデータです。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/d0504220-00b1-7882-1bbc-480a459ed526.png "Published API")

## 推論結果の評価
推論結果は0～1の範囲に正規化しました。「喜怒」はアノテーション分類とそれぞれの推論結果が概ね一致しています。「哀」の一行説明に「力強い」が混じっていますが、実際のBGMで確認すると８割方哀しいで合ってそうです。「楽」は「哀」の数値も高めに出ており、改善の余地はありそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/fb5fc880-ba67-96dd-2504-23eeaa508bd7.png "推論結果")

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/cbbc7789-be6d-2e95-a62e-4e96b6f89c0b.png "推論結果レーダーチャート")


# 喜怒哀楽によるBGMレコメンド
学習に使わなかった200曲に喜怒哀楽の推論を実行しました。プロトタイプとして、喜怒哀楽の度合いを入力すると類似度の高い曲名をレコメンドするExcelを作成しました。

## 200曲への推論実行
クラウド版API機能での推論もCPU、GPUを指定できます。CPU100件、GPU100件の推論速度を比較しました。リクエスト数では100曲×4種類=400件です。処理速度に大差なく、軽いモデルならCPUで十分ということでしょうか。

|CPU／GPU |学習時間  |参考価格 |
|---|---|---|
|CPU |20分|85円/時間 |
|GPU(NVIDIA® TESLA® K80 GPU x1)|20分 |560円/時間 |

## レコメンドアルゴリズム
アイテムベース協調フィルタリングのコサイン類似度を使ってレコメンドすることにしました。音楽の持つ喜怒哀楽ベクトルと、ユーザが入力した喜怒哀楽ベクトルの角度から類似度を求めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/852eaf4c-fccc-7e9e-2f35-9123d89df4af.png)
【参考】[コサイン類似度を利用し、集団の類似性を測ってみる](https://qiita.com/tetsutaroendo/items/61942d25ae2a017831f2 "コサイン類似度")
【参考】[アイテムベース協調フィルタリングに今更挑戦してみた](https://qiita.com/michi_wkwk/items/613034b1ec52b6be4720)

## BGMレコメンド
エクセルで作ったプロトタイプです。喜怒哀楽の度合いを入力すると、最もコサイン類似度が高い曲がレコメンドされます。数値の微調整によりレコメンド結果が切り替わり、類似度欄で降順にソートすると類似度の高い順のランキングになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/a0a29ea0-56fc-6783-499d-79b219876542.png "BGMレコメンドプロトタイプのイメージ")

# レコメンドの改良案

## レコメンドUI
プロトタイプでは喜怒哀楽度合いを数値入力にしましたが、顔の表情から喜怒哀楽を読み取る、画像と喜怒哀楽を関連付けて選ばせる入力方法も面白いかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/2c0172c9-dec3-b104-81ce-83d168ed7750.png "画像選択による喜怒哀楽特徴量の入力イメージ")

## 音楽にあった画像のレコメンド
画像データが大量にあれば、同じようなアプローチで画像に喜怒哀楽の特徴量付与できます。画像を選択すれば類似度の高い音楽がレコメンドされ、逆に音楽を選択すれば類似度の高い画像がレコメンドされる双方向の仕組みが可能です。新しいBGMの選曲方法として如何でしょうか。

【メリット】
- 直感的な画像選択によりBGMがレコメンドする。
- 喜怒哀楽の数値指定により微調整が可能。
- BGMが選ぶと関連の強い画像を表示し、視覚的に印象付ける。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/b0af023b-0110-d5b4-d28e-cbfb6d992c70.png "双方向リコメンドイメージ")

【参考】[Neural Network Consoleで笑顔分類器](https://qiita.com/cforestw/items/6db745eced1e9c3d5b82)
※喜怒哀楽ではありませんが、以前、NNCでの笑顔の分類にチャレンジしました。

# イントロでの学習精度とGPU処理速度
順番が前後しますが、アノテーション作業はイントロ数秒での分類が多くありました。イントロ3秒での学習精度を検証、併せてCPUとGPUとの処理速度を比較しました。曲数は同じ訓練用950曲、検証用316曲です。

## イントロの切り出し
24秒の曲の先頭から3秒だけを切り出しました。下記を参考にPythonで処理しました。

【参考】[PythonのWaveモジュールを使ってwavファイルを編集する](https://qiita.com/niisan-tokyo/items/d25dada3fa9903862260)

## 学習結果の評価
24秒の方が精度は高い結果でしたが、イントロ3秒でも思った以上に精度が高く分類されています。5～10秒程度でもよかったのかもしれません。

|分類 |1曲24秒 |1曲3秒 |
|---|---|---|---|---|
|喜 |0.769 |0.727 |
|怒 |0.919 |0.8513 |
|哀 |0.8892 |0.8829 |
|楽 |0.807 |0.7911 |

## CPU、GPUの処理速度比較
GPUが40倍以上早く学習が終わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213256/8ccee19f-e3d1-0630-2240-936852b6e895.png "CPU、GPUでの処理速度比較")

|CPU／GPU |学習時間  |参考価格 |
|---|---|---|
|CPU |50分32秒 |85円/時間 |
|NVIDIA® Tesla® K80 GPU|1分13秒 |210円/時間 |


# まとめ

- BGMを喜怒哀楽の4つでアノテーションし、波形データをCNNで処理するネットワークを作成しました。
- 学習したモデルをAPI化し、200曲に喜怒哀楽の特徴量を付与しました。
- コサイン類似度を使って、入力された喜怒哀楽度合いと類似度の高い曲をレコメンドするプロトタイプを作成しました。
- 画像選択によるBGMのレコメンドと、BGMにあった画像をレコメンドする改良案をまとめました。

## 感想
音声データの解析は初めてで、ゴールにたどり着くのか心配でしたが、チュートリアル動画を見ながらNNCで作業していくとスムーズに進められました。NNCはネットワーク設計、学習、APIでの運用と一元的に作業ができるので、アイデアをすぐに試せたのが良かったと思います。音声の波形データの扱いが十分理解できてませんので、深めていきたいです。