ディープラーニングを活用した作曲ツールを作った

[個人開発 #2 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/private-developmen2) の13日目の記事です。

作曲におけるコード（和音）進行生成のためのツール [Chord Worker](https://chordworker.diatonic.codes) を2018年12月13日に公開しました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">音楽アプリ Chord Worker のディープラーニング版を公開しました。ニューラルネットワークがコード進行をサジェストしてくれます。MIDI 出力も付けたので DAW でも使えるはず…！<a href="https://t.co/a7TGyVOFUf">https://t.co/a7TGyVOFUf</a> <a href="https://twitter.com/hashtag/chordworker?src=hash&amp;ref_src=twsrc%5Etfw">#chordworker</a> <a href="https://t.co/bDNc6Vd2VL">pic.twitter.com/bDNc6Vd2VL</a></p>&mdash; tanikawa (@diatonic_codes) <a href="https://twitter.com/diatonic_codes/status/1073229903917502465?ref_src=twsrc%5Etfw">2018年12月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<img width="1089" alt="Chord Worker" src="https://qiita-image-store.s3.amazonaws.com/0/19511/c227391b-337b-a268-8c8a-2aba21dd2103.png">

## アプリ概要

主な機能・特徴は次の通りです。

* パッド（ボタン）を押すだけでコードを演奏することができます
* ニューラルネットがコード進行をサジェストしてくれます
* MIDI 出力に対応しているので、DAW と連携できます（今後 MIDI 入力にも対応する予定です）


詳細な仕組みはまとめる時間がなかったので省略しますが、気になる方は以前に書いた記事を読むとなんとなく把握できるかと思います。

* [Web MIDI API による Web アプリと DAW の連携](https://qiita.com/tanikawa/items/1a820f662791077e5df7)
* [3時間で自動作曲プログラムを DAW で鳴らす](https://qiita.com/tanikawa/items/3ed44698f3472e6168dc)
* [ディープラーニングによるコード進行の予測](https://qiita.com/tanikawa/items/8f1a5b3a33f24ed0a984)


## ニューラルネットの推論

このアプリではコード進行をリアルタイムにサジェストする必要があるため、サーバ側で推論を行うのは、ネットワークのラグなどの理由から現実的ではありません。そこで、Web ブラウザ側でニューラルネットの推論ができるライブラリを探していたところ、ちょうど Microsoft から [ONNX.js](https://github.com/Microsoft/onnxjs) というライブラリが公開されたので、これを使うことにしました。

### ONNX と ONNX.js について

ONNX (Open Neural Network Exchange) は、ニューラルネットのモデルを表現するフォーマットです。多くの有名なディープラーニングフレームワークが、この ONNX フォーマットへの変換をサポートしています。ONNX.js は、ONNX フォーマットのモデルを JavaScript で動作させるためのライブラリになります。


## ONNX.js を使う

モデルの学習には Chainer を使いました。Chainer の場合、[ONNX-Chainer](https://github.com/chainer/onnx-chainer) を使えば、学習済みモデルを ONNX に変換できます。

ただ、過去の記事「[ディープラーニングによるコード進行の予測](https://qiita.com/tanikawa/items/8f1a5b3a33f24ed0a984)」にてコード進行の予測モデルを組んだ際には、`EmbedID -> LSTM -> Linear` という構成を採用したのですが、ONNX.js では EmdebID と LSTM をサポートしておらず、そのままではモデルを移植できません。そこで、本アプリでは次のような代替を考えました。

### EmbedID の代替

word2vec を使ってコード進行を学習し、コードの分散表現を獲得しました。学習方法は、通常の単語の分散表現を学習する手順と同様で、コード進行を半角区切りでテキスト化しておき、gensim などのツールで学習するだけです。

Web ブラウザでは、学習された各コードの分散表現を JavaScript の Object の形で保持しておき、これを EmbedID の代わりに使います。

データの例:

```js
// どの調にも対応できるように、コード名は度数表記で格納
const chord2vec = {
  'ⅠM7': [-0.3557768762111664, -0.0004484227974899113, ..., 0.31235525012016296],
  'Ⅰm7': [-0.0884508565068245, -0.017984995618462563, ..., -0.07706872373819351],
  ...
};
```


### LSTM の代替

LSTM の良いところは可変長を扱える点にありますが、今回のアプリで長い系列を扱うメリットをあまり感じなかったというのと、予測精度をシビアに見るつもりもないので、固定で8ステップ分のコード（の分散表現）を連結 (concat) して、Linear 層に渡す形式にしました。

入力が8ステップに満たない場合は、`<PAD>` で埋めます。

8ステップというのは個人的な主観で決めたので、もっと良いステップ数があるかもしれません。


## モデル構成まとめ

最終的にモデルの構成は次の図のような感じになりました。

![chordworker.png](https://qiita-image-store.s3.amazonaws.com/0/19511/996328c8-b768-c0fc-1df2-d70a23696abc.png)


ユーザビリティを考慮すると、モデルのダウンロード時間と推論処理の時間をできるだけ抑える必要があるので、小規模なモデルになっています。上記の構成で、モデルのファイルサイズは 2.2 MB、推論にかかる時間は MacBook Air 2015 の 11インチモデルの CPU でも 20〜40ms 程度だったので、とりあえず OK と判断しました。


## おわりに

ONNX.js が出てきて、Web ブラウザでディープラーニングのモデルを活用する敷居が低くなった印象ですが、まだまだ使えるオペレータが限られているので、今後のアップデートに期待したいところです。

Advent Calendar に間に合わせるために公開したので、いろいろと機能がひどいです[^1]が、使ってみて何かフィードバックいただけると幸いです。

[Chord Worker](https://chordworker.diatonic.codes)

[^1]: Windows だとコードを鳴らすと音割れするかもしれません。早急にボリューム機能を付けます。