magenta/TensorFlowを使ってみた

# magenta/TensorFlowを用いてメロディーの自動生成

## 背景
今回Pythonを用いてMIDIデータを操作出来るようなりたいということで，様々なサイトを参照しているうちにMagentaというツールにたどり着きました．

>#Magentaとは
この前、GoogleのMagentaという新プロジェクトがGithubにてオープンになりました。
https://github.com/tensorflow/magenta

>Magentaというのは、ニューラルネットワークを使って、美術や音楽を生成するプロジェクトです。

>機械学習のクリエイティビティを進化させるのと、アーティストと機械学習のコミュニティとなることを目的としています。

>#作曲をするリカレントニューラルネットワーク
Magentaの第１弾として、作曲をするリカレントニューラルネットワーク(RNN)のモデルが公開されました。
LSTM(Long Short-Term Memory)という手法を取り入れたものです。
magenta公式サイト(http://magenta.tensorflow.org/ )によれば、
>> It’s purposefully a simple model, so don’t expect stellar music results. We’ll post more complex models soon.
>>これは意図的にシンプルにしたモデルで、傑出した音楽ができることは期待できません。しかし、これからより複雑なモデルを公開していきます。

Magentaは2016年にリリースました．
RNNやLSTMについてまず勉強が必要ですが，とりあえず使ってみようということでこのツールを活用していきたいと思う．

## 環境
- MacBookPro (macOS Catalina (10.15.4))
- Docker for Mac

## 参考文献
- [PyDataOkinawa/meetup017](https://github.com/PyDataOkinawa/meetup017)

- [MIDIファイルから特定の楽器の音のみを取り出し別ファイルにする
](https://qiita.com/tackey/items/860f408e43397f55b160)

## 特定パートを抜き取る
YAMAHAオンラインショップから購入したMIDIデータ(日向坂46の表題曲，4曲)を確認した．

<img width="1920" alt="スクリーンショット 2020-04-17 22.53.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512948/5b603377-d40a-4f95-21d9-5f7a09d0f661.png">


このように様々なトラックに分かれていた．(ドラムパートや伴奏など)
後述するが，何もせずこのままのデータを用いて学習を行った．結果を確認したが，やはり用いるデータのジャンルが多いとよくない．そのためメロディーだけに絞る必要がある．

ということでPythonのパッケージ`pretty-midi`を用いてメロディーパートだけ抜き取ってみよう．

```terminal:terminal
pip install pretty_midi
```

参考までにリソースの配置は以下の通り．

<img width="997" alt="スクリーンショット 2020-04-17 22.56.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512948/def7b061-8ba4-b3e9-4949-45803d5fd9c5.png">


```Python:cut_out.py

import pretty_midi
import os

os.chdir("~/WorkSpace/MIDI_data/cut_out")

def func():
  midi_name = ["00", "01", "02", "03"]

  for m_name in midi_name:
    midi_data = pretty_midi.PrettyMIDI("resource" + m_name + '.mid')

    # 選択楽器番号を選択して保存
    midi_track = midi_data.instruments
    # print("midi_track = {0}" .format(midi_track))
    for m_track in midi_track:
        print("midi_track = {0}" .format(m_track))

    print("select track-nunber => ")
    i = int(input())

    # 選択楽器を取り出し、インスタンスにする
    for instrument in midi_track:
        if instrument.program == i:
            ins = instrument

    # 新規作成用のPrettyMIDIオブジェクトを作る
    rev_en_chord = pretty_midi.PrettyMIDI()

    # PrettyMIDIオブジェクトに追加
    rev_en_chord.instruments.append(ins)

    # 保存する
    rev_en_chord.write('./result/ins_' + m_name + '.mid')

  return

func()
```

各MIDIファイルを参照し，楽器番号を指定してそのトラックだけを保存するコードである．

[MIDIノートナンバーの各種対応表。GM、GS、XGでのリズム楽器名。プログラムナンバーと楽器名と発音域。](https://digi-pal.link/midi-note-number/)

楽器コードは上記サイトを参照．だいたいの人はプログラミングからMIDIデータを触るとき，楽器コードからいじるようである．

## いよいよLearning

Dockerを起動し，`magenta/tensorflow`イメージをpullする．
TensorBoardも使用するため，Port番号を指定する．

```terminal:Terminal
docker run -it -p 6006:6006 -v /tmp/magenta:/magenta-data tensorflow/magenta
```

基本的には下記サイトの手順道理に進めれたのでここに明記はしない．

[PyDataOkinawa/meetup017](https://github.com/PyDataOkinawa/meetup017)

しかしイメージの中でシェルスクリプトをたたく必要があったのだが，エラーが出て止まってしまう．
いままでシェルスクリプトを触ったことがなかったので解読に時間がかかった．環境違いなのか，指定されるプログラミングファイルの名称が違ったり，パラメータの設定値の具合が悪くエラーになったりしていた．(シェルスクリプトに勉強になりました．)

参考までに私の環境においては以下の変更を行うことで学習が可能であった．

```shell:build_dataset.sh

convert_midi_dir_to_note_sequences \
    --midi_dir=$MIDI_DIR \
    --output_file=$SEQUENCES_TFRECORD \
    --recursive

###### 以下に変更 ######

convert_dir_to_note_sequences \
    --midi_dir=$MIDI_DIR \
    --output_file=$SEQUENCES_TFRECORD \
    --recursive
```



学習中…
TensorBoardも初めて見ました．何が書いてあるのかさっぱりなのでもっと勉強しなければなりません．
<img width="1920" alt="スクリーンショット 2020-04-16 17.29.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512948/a718defc-d583-c0c4-73aa-3a579bf58229.png">

![スクリーンショット 2020-04-15 18.37.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512948/5c35c2e7-4032-96b4-b538-d54ba73ea65f.png)

とりあえずMacBookで回してみたが，やはりキツそう…
来週にはDeepInfinityで回せるようにならなくては…

ステップ数を1200に設定していたので，MacBookProだと学習に1時間30分かかった．
用いたモデルは`Basic RNN`
<img width="578" alt="スクリーンショット 2020-04-16 18.50.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512948/586a22bc-143f-19e3-c648-4dfdc17d936b.png">

正確性を表す(Accuracy)は0.8まで上昇していた．

## 生成

このトレーニングデータを用いてMIDIファイルを生成した．
ステップ数は500を指定した．また，生成ファイルは5つにした．

生成されたMIDIデータを`timidity`を用いて`wav`へと変換した物をGoolge Driveにアップロードした．

[Google Drive](https://drive.google.com/drive/folders/1R2SpHmvkjver7Zsy-4wYlSY4Axsk-jxb?usp=sharing)

ここで時間が来てしまったのですが，曲を聴く限り若干ながら原曲を彷彿とさせるメロディラインが生成されたと感じる．