magenta_sessionのバージョンを上げてGPU対応したくてやった話

## tensoflowに興味があったし音楽の自動生成が面白そうだった

Pythonを知らなければtensorflowは技術記事で見かける機械学習のライブラリってイメージでした。触ったことがなく[magenta](https://github.com/magenta/magenta)というを知って触ってみようと思いチュートリアルのようなものを探すと以下の記事が見つかりました。

[人工知能時代の音楽制作への招待 - Google Magenta 解説&体験ハンズオン (自習編) -
](https://qiita.com/icoxfog417/items/f198f2e030d861d7bbf4)

ちょうどいいじゃん！と思って触るとcpuでのみの学習しか対応しておらず「機械学習はGPUの方が速度でるんでしょ？」という素人考えでDockerの勉強も兼ねて対応させることにしました。

forkしてGPUに対応させたリポジトリです。
[MizoTake/magenta_session](https://github.com/MizoTake/magenta_session)

##WSL上でDockerを使ってGPUを動かす環境を整える

自分はWindowsのPCにしかGPUを挿してなかったのでWSL2を使用してubuntuからnvidia-dockerを使用する手段を選びました。(Dockerのバージョンによってはnvidia-dockerをインストールしなくても大丈夫なそうですが自分の手元でうまくGPUを認識しなかったので使用しました)

[magentaセットアップをWSLでしたら躓いてDockerの良さを再認識したメモ](https://maketake.hatenablog.com/entry/2020/08/11/100353) にぶち当たったエラーなどをメモ書き程度に書いています。これを今回はまとめて書く話になります。

WSL2は現在WindowsのOSをInsider Previewにしないと動きません。そのためリスクを負うことを理解して進めてください(Windowsを使わない場合は関係ないのでサクサクとdockerで準備ができていくと思います)

WSL2の準備は
[待ってました CUDA on WSL2](https://qiita.com/ksasaki/items/ee864abd74f95fea1efa)を順番にきちんとやればうまく動くと思います。cuda周りはDocker使わずやろうと思いましたが結構めんどくさかったのでDockerで動かすことを推奨します。

これは手元の環境によるかもしれませんがWSL2対応のlinuxをインストールしようとMicroSoft Storeからインストールしようとすると自分はうまくいきませんでした。そこで調べると[Manually download Windows Subsystem for Linux distro packages
](https://docs.microsoft.com/en-us/windows/WSL/install-manual)から落とせば、ストアを経由せずにダウンロードできました。ダウンロードした後も`.appx`をダブルクリックするとダイアログが出て簡単にインストールすることができます。

DockerはWSL上で動かさないとGPUを使えないためWindowsのDockerは落としておく必要がありました。

Dockerのイメージは[TensorFlow Overview](https://docs.nvidia.com/deeplearning/frameworks/tensorflow-release-notes/overview.html#overview)ここから持ってくるとcudaやtensorflowが包括されているので便利でした。

イメージをビルドして動かしたらPythonも最初から入ってるので[TensorFlowからGPUが認識できているかを2行コードで確認する](https://thr3a.hatenablog.com/entry/20180113/1515820265)を使ってGPUが認識されているか確認します。文字がでてきたら大丈夫です。

##magenta_sessionを最新のmagentaとtensorflow2に対応させる

magenta_sessionのソースコードは2~3年前と古く最新のmagentaやtensorflow2には対応していません、そのため当初は

1. magenta_sessionのライブラリバージョンを基準にDockerを構成する
1. magenta_sessionのライブラリバージョンを上げると共にmagenta_sessionの中身も更新する

の2択で迷っていました。結果2つ目で動かすことにするのですが何故1つ目にしなかったのかというと1つ目が動かなかったからです。tensoflow1のtensorflow-gpuなどもnvidiaのサイトのイメージにありますがGPUをうまく認識しなかったので断念しました。

- magenta==0.3.2 → magenta==2.1.0
- tensorflow==1.10.0 → tensorflow==2.2.0

が主なライブラリのバージョンアップです。tensorflowは後方互換があったのでそれを使うようにしていましたがmagentaはそれなりに変わっていたためちょっとだけ変更を追うのが大変でした。

### tensorflowのバージョンアップ対応

tensorflowの対応は簡単で前述しましたが後方互換のおかげでプロジェクト内の文字列置換で基本済みました
[Automatically upgrade code to TensorFlow 2](https://www.tensorflow.org/guide/upgrade)を見ると自動的に処理をしてくれるものがあるみたいなのですが自分が気付いたときには対応した後で、行った対応は

- `import tensorflow as tf` → `import tensorflow.compat.v1 as tf`

だけだった気がします。magenta自体のtensorflow2対応を参考にしました。すんなり動いたので良かったです。

### magentaのバージョンアップ対応

magentaの構造がちょいちょい変わっていたので参照する場所を更新すれば基本大丈夫でした

- [convert_to_melody_dataset.py](https://github.com/MizoTake/magenta_session/commit/6b2d5ba51c91acd307455f21fab2153c53267360)

```py:13行目
    pipeline_instance = md.get_pipeline(config, md.FLAGS.eval_ratio)
```

を

```py:13行目
    pipeline_instance = md.melody_rnn_pipeline.get_pipeline(config, eval_ratio=md.FLAGS.eval_ratio)
```
にすることでまずはエラーが解消されるのですがこれは
[melody_rnn_create_dataset.py](https://github.com/magenta/magenta/blob/master/magenta/models/melody_rnn/melody_rnn_create_dataset.py)と[melody_rnn_pipeline.py](https://github.com/magenta/magenta/blob/master/magenta/models/melody_rnn/melody_rnn_pipeline.py)の中身をみるとpipelineの参照の方法や`get_pipeline`メソッドの引数が変わったことが確認できたのでバージョンに合った指定にします。

- [train_model.py](https://github.com/MizoTake/magenta_session/commit/6b2d5ba51c91acd307455f21fab2153c53267360)

```py:28行目
        graph = events_rnn_graph.build_graph("train", config, train_file)
```

```py:47行目
        graph = events_rnn_graph.build_graph("eval", config, eval_file)
```

の2つが古いメソッドでもうこの名前のメソッド名はありませんでした。そのためmagenta現行のメソッド名で呼び直します

```py:28行目
        graph = events_rnn_graph.get_build_graph_fn("train", config, train_file)
```

```py:47行目
        graph = events_rnn_graph.get_build_graph_fn("eval", config, eval_file)
```

とします、これは[events_rnn_graph.py](https://github.com/magenta/magenta/blob/master/magenta/models/shared/events_rnn_graph.py#L68)メソッド名が変わっただけのようで引数がそのままなので見つけやすかったです。

- [generate_midi.py](https://github.com/MizoTake/magenta_session/blob/6b2d5ba51c91acd307455f21fab2153c53267360/scripts/models/train_model.py)

```py:43行目
        bundle=magenta.music.read_bundle_file(model_path))
```

↓

```py:43行目
        bundle=magenta.models.shared.sequence_generator_bundle.read_bundle_file(model_path))
```

今回はこれが一番苦労しました。現状(magenta==2.1.0)の[magenta/music](https://github.com/magenta/magenta/blob/master/magenta/music/__init__.py)を見ると`__init__.py`しかありません。そうmusicディレクトリには処理が一つもなくなっていました。(実際はmagentaのReleaseノートを見ると[releases/tag/2.1.0](https://github.com/magenta/magenta/releases/tag/2.1.0)にmusicの処理は[note_seq](https://github.com/magenta/note-seq)に移動させたそうですが探しても目当てのものはありませんでした。)

そこで`__init__.py`のコミット履歴をたどることにしました。tensorflow2の対応あたりを探すと見つかりました。[Move generator_pb2 and sequence_generator out of music](https://github.com/magenta/magenta/commit/2fc431fb1b003d70ff220e5d0d9704e331614dbb)ここで目当ての`read_bundle_file`は消されたことが分かり`sequence_generator_bundle`を探すとディレクトリが移動させられたことがわかりました。これで現行の場所がわかったので確認します。[sequence_generator_bundle.py](https://github.com/magenta/magenta/blob/master/magenta/models/shared/sequence_generator_bundle.py#L27)で見つかったので参照することで解決しました。

これで[人工知能時代の音楽制作への招待 - Google Magenta 解説&体験ハンズオン (自習編) -
](https://qiita.com/icoxfog417/items/f198f2e030d861d7bbf4)にあった生成までのコマンドが動きました。今回はsession部分には触れていないのでここまでの対応となります。(とにかく生成がしたかった)

##まとめ

今回はこれまででとりあえずmagenta_sessionがGPUを使って動くことが確認できました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">使用率が上がると楽しい(?) <a href="https://t.co/udJSw8lBEb">pic.twitter.com/udJSw8lBEb</a></p>&mdash; あるど (@OrangeGKeeper) <a href="https://twitter.com/OrangeGKeeper/status/1294148621298851847?ref_src=twsrc%5Etfw">August 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

結構ギリギリまでGPUが使われていることがわかります。もしこれで何か間違っていてGPUが使われていない学習が行われていたら卒倒しますね(白目)