はじめに
この記事では、Magentaの開発環境を準備した上で、手元のMIDIファイルを学習し、曲を作成するということを行います。
magentaのBasic RNNのREADMEの通りですので、そちらを読んでいただいてもよろしいかと思います。
用語等、不明な点もあるため、ご了承いただければと思います。
開発環境の準備はこちらの記事もご参考ください。
TensorFlow製音楽生成プロジェクト「Magenta」を開発環境の設定から曲生成までやってみる。
データセットを作る
手持ちにMIDIファイルを学習する前に、まずはTensorFlowで扱えるように、NoteSequencesという形式に変換する必要があります。
下記のスクリプトを実行します。
不正な形式のMIDIファイルを読み込んだ際にエラーを吐くことがあります。
解析できないMIDIファイルはスキップされるので安心して大丈夫なようです。
MIDI_DIRECTORY=<folder containing MIDI files. can have child folders.>
# TFRecord file that will contain NoteSequence protocol buffers.
SEQUENCES_TFRECORD=/tmp/notesequences.tfrecord
bazel run //magenta/scripts:convert_midi_dir_to_note_sequences -- \
--midi_dir=$MIDI_DIRECTORY \
--output_file=$SEQUENCES_TFRECORD \
--recursive
```
`convert_midi_dir_to_note_sequences.py`と言うのを実行しているようですね。
下記のようなメッセージが表示されれば完了です。
```
..............
INFO: Found 1 target...
Target //magenta/scripts:convert_midi_dir_to_note_sequences up-to-date:
bazel-bin/magenta/scripts/convert_midi_dir_to_note_sequences
INFO: Elapsed time: 7.312s, Critical Path: 0.63s
(中略)
INFO:tensorflow:Could not parse 0 MIDI files.
INFO:tensorflow:Wrote 6 NoteSequence protos to '/tmp/notesequences.tfrecord'
```
# 学習する
## メロディーを抽出する
`basic_rnn_create_dataset.py`を実行します。
これは上記でMIDIファイルを元に作成した`NoteSequence data`からメロディーを抽出するスクリプトです。
アウトプットは`SequenceExampleprotos`を含んだ`tfrecord`ファイルとして書き出されます。
`basic_rnn`モデルのTensorFlowの読み込みは、`SequenceExample protos`を直接モデルに読み込むことができます。
この例では、評価データセットを2つ目の`tfrecord`ファイルとして作ります。
ですが、`evaloutput`と`evalratio`フラグを削除することで省くことができます。
下記のようなメッセージが出ればOKです。
```
INFO: Found 1 target...
Target //magenta/models/basic_rnn:basic_rnn_create_dataset up-to-date:
bazel-bin/magenta/models/basic_rnn/basic_rnn_create_dataset
INFO: Elapsed time: 0.573s, Critical Path: 0.01s
INFO: Running command line: bazel-bin/magenta/models/basic_rnn/basic_rnn_create_dataset '--input=/tmp/notesequences.tfrecord' '--output_dir=/tmp/basic_rnn/sequence_examples' '--eval_ratio=0.10'
INFO:tensorflow:
Completed.
INFO:tensorflow:Processed 6 inputs total. Produced 31 outputs.
INFO:tensorflow:DAGPipeline_RandomPartition_training_melodies_count: 29
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_melodies_discarded_too_long: 0
INFO:tensorflow:DAGPipeline_RandomPartition_eval_melodies_count: 2
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_melody_lengths_in_bars:
[0,1): 10
[1,3): 6
[3,6): 17
[6,7): 2
[7,8): 1
[8,10): 4
[10,20): 21
[20,30): 5
[30,40): 6
[50,100): 4
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_melodies_discarded_too_short: 35
INFO:tensorflow:DAGPipeline_Quantizer_sequences_discarded_because_multiple_time_signatures: 5
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_melodies_truncated: 0
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_polyphonic_tracks_discarded: 43
INFO:tensorflow:DAGPipeline_MonophonicMelodyExtractor_melodies_discarded_too_few_pitches: 10
```
完了すると
`/tmp/basic_rnn/sequence_examples/`に
`training_melodies.tfrecord`と`eval_melodies.tfrecord`の2つのファイルができます。
`training_melodies.tfrecord`は訓練用、`eval_melodies.tfrecord`は評価用のようです。
## トレーニングのスクリプトを実行する
Magentaの開発者の方がスクリプトを作ってくださっています。
```
$EXPERIMENT_DIR=/tmp/basic_rnn/logdir
```
作業フォルダを指定します。
```
$HYPERPARAMETER_STRING=`{"rnn_layer_sizes":[50]}’
```
ハイパーパラメータの指定をします。
このように指定することで、LSTMモデルのサイズを指定することができるようです。
LSTMについては下記が参考になると思います(大作)。
[わかるLSTM ~ 最近の動向と共に](http://qiita.com/t_Signull/items/21b82be280b46f467d1b)
> LSTM(Long short-term memory)は、RNN(Recurrent Neural Network)の拡張として1995年に登場した、時系列データ(sequential data)に対するモデル、あるいは構造(architecture)の1種です。
> (中略)
> LSTMのその最も大きな特長は、従来のRNNでは学習できなかった長期依存(long-term dependencies)を学習可能であるところにあります。
```
$NUM_TRAINING_STEPS=20000
```
訓練回数を指定します。Macだととても時間がかかるので、数百とかに減らすといいと思います。
```
$TRAIN_DATA=/tmp/basic_rnn/sequence_examples/training_melodies.tfrecord
```
上記で生成した訓練データのパスを記載します。
```
$EVAL_DATA=/tmp/basic_rnn/sequence_examples/eval_melodies.tfrecord
```
オプションとして、訓練データと並行して検証データも並行してはしらせることができるようです。
設定ができたら、スクリプトを実行します。
```
./run_basic_rnn_train.sh $EXPERIMENT_DIR $HYPERPARAMETER_STRING $NUM_TRAINING_STEPS $TRAIN_DATA [$EVAL_DATA]
```
下記のメッセージが出ます。
INFO: Found 1 target...
Target //magenta/models/basic_rnn:basic_rnn_train up-to-date:
bazel-bin/magenta/models/basic_rnn/basic_rnn_train
INFO: Elapsed time: 0.544s, Critical Path: 0.00s
INFO:tensorflow:hparams = {'rnn_layer_sizes': [50], 'decay_rate': 0.85, 'dropout_keep_prob': 0.5, 'batch_size': 128, 'decay_steps': 1000, 'clip_norm': 5, 'initial_learning_rate': 0.01, 'skip_first_n_losses': 0}
Starting TensorBoard 28 on port 6006
(You can navigate to http://10.200.3.144:6006)
INFO:tensorflow:Train dir: /tmp/melody_rnn/logdir/run1/train
INFO:tensorflow:Starting training loop...
INFO:tensorflow:global_step/sec: 0
(中略)
INFO:tensorflow:Global Step: 100 - Learning Rate: 0.01000 - Loss: 1.680 - Perplexity: 13.678 - Accuracy: 85.811
INFO:tensorflow:Training complete.
# 曲を生成する。
上記の訓練が完了すると、作業ディレクトリ`/tmp/basic_rnn/logdir/run1/train/` の配下に、下記のようなファイルができると思います。
checkpoint model.ckpt-31
events.out.tfevents.1475664203.HTMac.local model.ckpt-31.meta
graph.pbtxt model.ckpt-39
model.ckpt-15 model.ckpt-39.meta
model.ckpt-15.meta model.ckpt-47
model.ckpt-23 model.ckpt-47.meta
model.ckpt-23.meta
checkpointというのはTensorFlowにおけるファイルの保存やロードに用いるもののようです。
Basic_RNNではこのうち、最後のcheckpoint(上記だとmodel.ckpt-47)を用いて曲を生成してくれるようです。
また、曲を生成するには、モデルにはじまりのメロディを与える必要があります。
曲生成はそのメロディを元に、次の音をどんどん予測して行って曲を延長していく、ということをするからです。準備するメロディはモノラルの(同タイミングに複数の音が鳴らない)メロディである必要があります。
任意に作成してもいいですし、サンプルとして
`/magenta/models/shared/primer.mid`も準備されています。
ここではこのサンプルを用います。
PRIMER_PATH=
bazel run //magenta/models/basic_rnn:basic_rnn_generate --
--run_dir=/tmp/basic_rnn/logdir/run1
--hparams='{"rnn_layer_sizes":[50]}'
--output_dir=/tmp/basic_rnn/generated
--num_outputs=10
--num_steps=128
--primer_midi=$PRIMER_PATH
最小の3小節はprimer.midを元に固定されています。
[サンプル1](https://clyp.it/iwkk1xg3)
[サンプル2](https://clyp.it/jebdi2ny)
サカナクションさんを学習させましたが、雰囲気を感じることができました。
# 最後に
DeepLearningの知識、TensorFlowの知識、英語読解力の不足が原因で、ちょっと読み解けてない部分があります。
引き続き勉強します。。。
ありがとうございました。