音楽ど素人が機械学習で楽譜認識するAndroidアプリを作る話　音符検出モデルの作成編

#はじめに
中学から吹奏楽部に入った息子が楽譜に音名を書くのがだるいと言いだしたんで、そんなもん今どきスマホとパシャッとすりゃAIでぱっと出てくるアプリがあるだろ？って言ったら意外となかったんで自分で作った
今回は機械学習(MobileNet SSD)による音符検出モデルの作成編です
**五線譜の検出編**
https://qiita.com/Anadreline/items/4cf6e88c743a65b7da2c

#作成アプリ
**Music Score Reader**
https://play.google.com/store/apps/details?id=msreader.android.anadreline.com.musicscorereader

#開発者の初期スペック
- 五線譜の**どこがドなのかがわからない**
- **♯と♭って結局どっちかだけでよくない！？**と思っている
- 息子にトランペットの**ドはドじゃないからね**って言われてファッ！？ってなる
- 12音に五線譜表記って**仕様がおかしくね**って思っている

#検証環境
この記事の内容は、以下の環境で検証しました。
    Python 3.5.4
    TensorFlow 1.12.0

#検出モデル作成プロセス
前提条件としてスマートフォンアプリとして作成するのが目的なので、検出に使えるアルゴリズムは必然的に限定されます
選択肢としてはTiny YOLO、SSD、MobileNet SSDあたりになるけど、開発当初は他プロジェクトでSSD300を使った経験があったので試してみたけど、うまく動かず断念
一番情報が多いMobileNet SSDでやることにした
学習環境の構築は以下を参考に
**Tensorflowのobject detection APIのチュートリアルを試す（windows）**
https://qiita.com/kappanda/items/697ba3c6625774d3414c

必要なものはこのあたりで全てそろいます
https://github.com/tensorflow/models/tree/master/research/object_detection

学習モデル作成手順はこちらを参考にしました
**Tensorflow ObjectDetection APIでミレミアム・ファルコン検出**
https://qiita.com/YudaiSadakuni/items/530ee4150cb3ec020010

##ラベルデータ作成
お手本データはこちら
https://github.com/tensorflow/models/tree/master/research/object_detection/data
今回の目的は音名を表示することなので、検出対象の記号は以下11種に絞りました
黒丸音符、白丸音符、♯、♭、♮、ト音記号、ヘ音記号、小節区切

```label_map.pbtxt
item {
  id: 1
  name: 'note1'
}
item {
  id: 2
  name: 'note2'
}
item {
  id: 3
  name: 'sharp'
}
item {
  id: 4
  name: 'sharp_d'
}
item {
  id: 5
  name: 'flat'
}
item {
  id: 6
  name: 'gclef'
}
item {
  id: 7
  name: 'fclef'
}
item {
  id: 8
  name: 'natural'
}
item {
  id: 9
  name: 'bar'
}
item {
  id: 10
  name: 'bar_d'
}
item {
  id: 11
  name: 'bar_e'
}
```

音符の種類や休符まで認識できると楽譜認識後の自動演奏まで視野に入るんですが、そうなると格段に認識難度が上がるため断念

##アノテーションデータの作成
アノテーションデータは適当に楽譜をスマホで撮った画像から切り出したものを使用して作成
当初普通の楽譜から作成したもんで、音符の種類と記号の数にかなりの偏りができてしまった

<blockquote class="twitter-tweet" lang="ja"><p>アノテーションデータの作成</p>&mdash; Anadreline(@Anadreline) <a href="https://twitter.com/Anadreline/status/1109379559806259201">2019年3月23日</a></blockquote>

ほとんどが1画像1データではなく、複数入っているものになりました

##TFRecordファイルの作成
https://github.com/tensorflow/models/tree/master/research/object_detection/dataset_tools
用意した画像をimagesフォルダにアノテーションデータをxmlsフォルダにに用意してcreate_tf_record.pyにてtrain.recordとval.recordを作成

##Configファイルの作成
ベースとなるモデルを以下からダウンロード
https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md
今回はssd_mobilenet_v1_cocoを使用した
https://github.com/tensorflow/models/tree/master/research/object_detection/samples/configs
にあるconfigファイルを自作データ用に修正

- num_classes: をデータ種類数に合わせた値に変更
- num_steps: は最大学習回数
- fine_tune_checkpoint: checkpointファイルのパス
- input_path: レコードファイルのパス
- label_map_path: ラベルファイルのパス

##学習
https://github.com/tensorflow/models/blob/master/research/object_detection/model_main.py
model_main.pyにconfigファイルを指定して学習開始

frozen inference graphに変換
https://github.com/tensorflow/models/blob/master/research/object_detection/export_inference_graph.py
export_inference_graph.pyでチェックポイントファイルを学習モデルに変換します
できたpbファイルで学習モデルの完成です
本当はTensorFlow Liteのモデルを作ればよかったんだけど、最初作ったのがTensorFlow Mobileのモデルで最後までこれでいってしまいました

#学習モデルの検証
##学習データ数による認識率の変化
![analyze2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36793/f1bec528-0fb1-822e-b694-f69859ead97c.png)
当然の結果かもしれないが、学習データを増やすほどに認識率は上がった
ただし100％の認識率には達せず、データを変えるたびに今まで認識していたものが認識できなくなったり、できるようになったりした
##学習回数による認識率の変化
![analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36793/b8510d82-5777-2b01-27d9-f82db3643837.png)
10万回まで学習を行ったが、ある程度から過学習なのか誤認識が増える傾向がみられた
##最終モデル
![analyze16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36793/3fd17088-2991-72e2-0edf-ff72ddb6ca85.png)
最終的には画像数651枚、学習回数75000回程度で認識率95.23%と一番いい結果が得られた