歌詞からコード進行を生成する

# はじめに
曲の雰囲気を決める大きな要素としてコード進行があり、基本的には明るい歌詞の曲には明るい雰囲気のコード進行、切ない歌詞の曲には切ない雰囲気のコード進行が使われることが多い。(もちろんそうじゃない曲もある)

ニューラルネットワークの自然言語処理モデルでは、割と高精度な機械翻訳が実現されてきており、入力した文章の単語の繋がりから意味のようなもの抽出して状態変数に変換し、同じような意味を持つ他の言語に翻訳している。

ここで他の言語をコード進行に置き換えてやれば、入力した歌詞からその歌詞の雰囲気にあったコード進行を生成できそう。

そこでJPOPの約1万曲のコード進行付きの歌詞を学習させ，自作の歌詞を入力するとその歌詞にあったコード進行を生成するモデルを作ってみた。

ここで公開してみました。
http://lyrics2chords.a2kiti.com/
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201397/91dc71c3-707b-80ee-bf84-349960f90203.png)


# コードについて
https://past-orange.com/po_sp/?p=940
このサイトが例え付きでコードについて説明してくれており面白かった。
同じ「愛してる」って言葉でも鳴っているコードが違うとその言葉の背景的なものも違って聞こえる。単語ではなく文章であればある程度の背景が含まれるはずで、うまく学習すればその文章の雰囲気にあったコードが出てくるはず。

# 学習データ
サビ、Aメロ、Bメロなどのブロック毎に分け、macabにより分かち書きした。分かち書きした単語
配列を入力、そのブロックのコード進行を出力にした。以前RNNでコード進行から次のコードを予測するモデルを作ったときに、曲のキーがバラバラでなく統一したほうがうまく行ったので、今回も全てC/Am調に変換した。ただ、曲の途中でキーが変わってる場合も多いがそれに関しては考慮できていない。なので最期のサビの半音上げパターンなどによりD♭調とかが少々混ざってる気がする。
ブロックごとに分けたことで学習データの数はおよそ10万になった。単語の種類は約50000個、出力コードの種類は約200個。

# 生成モデル
機械翻訳に使えるモデルの中でもシンプルなseq2seqを用いた。この記事を参考にChainerで実装し、エンコーダーでは入力がembedding層からLSTM層に行き、デコーダーではLSTM層からembedding層を通り出力される。予測を行うときは、最もスコアが高いコードをそのまま出すのではなく、スコアをもとに確率で出力するようにした。こうすることで、同じ入力でも毎回少し違ったコード進行が生成されるようになる。

# 結果
例えばこんな歌詞を入力してみると
「My close friend, you don't cry　逢えない夜に凍えたら、そっと瞳閉じて…」
Am→D7→G→Fm→C→Am→D7→Fm→C
Am→G6→G♭dim→F→C→E→Am→G6→FM7
Am→D7→G→C→F→C→Am→D7→G

「泣けるだけ泣けば良い だから堪えないで 涸れるまで泣けば良い だからそのドレスは破り捨てて」
Am→G→F→G→Am→G→F→G
Am→F→Em7→F→C
Am→G→F→Am→G→F→G→E7

「Bring me higher love, give me all your love この胸に Bring me higher love, give me all your love 壊れるほどに刻みこんで」
C→Am→F→C→F→C→D7→G→C→Am→F→C→F→G→C→C
C→Am→F→G→C→Am→F→G→C→Am→F→G→C→Am→F→G→G
C→Am→F→G→Am→C→Am→F→G→Am→Am→F→G→C→C→C→C

このようなコード進行が生成される。毎回少し違うコードが出力されるので3つ載せてみた。すべてC調かAm調で出力している。
この2つは学習データにはない歌詞である。
たぶんたまたまだけど，2曲めの1つ目の出力は実際の曲通りでびっくりした。
だいたい曲になりそうなコード進行が生成されている。
とはいえ，すこし言葉を変えるとだいぶ変わる，，，

何も入力しない場合イントロの学習結果が出力される。
Am→G→F→ConE→Dm→Em→F→G♭dim→Gsus4→G
F→G→Em→Am→G9→Am7
Am→F→C→G→Am→F→C→G



評価が難しいけど，
https://past-orange.com/po_sp/?p=976
にあるコード進行の「愛している」の表現を入力してみて，それっぽいコード進行が出てくるか見てみる。

長調系
Dm→G→Cの表現「伝わるだろうか？でも言おう！愛してる！」
G→F→C→G→F→C
G→F→C→G→F→C
G→F→C→G→F→C

Dm→G→CM7の表現「伝わるだろうか？でも言おう！愛してる．．．これで良かったのだろうか」
C→G→Am→Em→F→C→D→G→C→E→Am→Em→F→G→C
Am→F→G→C→Am→F→G→C→Am→F→G→C→F→G→F→C
C→G→Am→Em→F→C→D→G→C→E→Am→Em→F→G→C

A♭→B♭→Cの表現「愛してる！愛してる！！A・I・SHI・TE・RU！！！！我と共にあれ！！！！！！」
F→C→D7→G7→C→F→G7→C→C→G7→G7→C→G7→G7→G7
F→C→Am→F→C→Am→F→C→F→G→F→G7
F→C→Dm→B♭→Am→F→C→G→B♭→C→GonB→Am→A♭→G→G

短調系
Dm→Em→Amの表現「あぁ、愛したとも。愛してしまったのさ。叶わぬ恋さ」
Am→F→C→G→Am→F→G7
Am→F→C→G→Am→F→C
Am→F→C→Em→Dm→Bm7-5→E7

Dm→E7→Amの表現「あぁ、愛したとも。とってもとっても！！愛した俺儚い切ない悲劇の主人公」
C→G7→C→F→C→Dm7→G7→C→F→G7→C
C→Fm→C→G→Fm→Gsus4→G
CM7→Em7→Am7→F→Am7→G→Em7→CM7

D7→E7→Amの表現「言うぞ、言うぞ！！愛し．．．やっぱりダメだ。人妻じゃないか」
F→E7→Am→F→E7→D7→G→G
F→E7→Am→Dm→G→C→C
F→E7→Am→F→G

うーんなんとも言い難いけど，長調と短調はつかい分けられてそうな感じもする。

# 考察
ちゃんと曲になりそうなコード進行が生成され、歌詞によってそれなりに異なるものになっていることが確認できた。コード進行はあくまで音楽の要素の一つであり、同じコード進行でもメロディ、リズムによるため結局評価が難しい。

追加でなにか出来そうなこととして以下が挙げられる。


## 学習済みword2vecの利用
エンコーダーのembedding層は単語を単語ベクトルに変換するものと言えるが、1から学習するのではなく、すでにきちんと学習されたものを使ったほうが適切な気がする。
そこで下記のリンクでに公開されている学習済みの重みを使ってみたが、この学習で含まれる単語に今回の歌詞データ中の単語があまり含まれておらず、歌詞の半分くらいしか使えなかったので断念。
https://github.com/Kyubyong/wordvectors

## 他のモデルの利用
最近の自然言語処理ではtransformerがよく使われているようである。これを使ってみても良いが、良くなったのかどうかの評価が難しいので悩みどころ。
Attentionを使えばどの言葉に良く反応しているのか可視化できそうなのでいいかも。
今回生成物にランダム性を持たせるため、出力時にスコアをもとにした確率を使ったが、デコーダーの入力である内部表現に揺らぎを与える方法も考えられる。seq2seqをVAEにしたモデルを使えば、潜在変数をいじって出力を操作出来るはずなので、2つの歌詞を入力し、その中間となるコード進行を出力するなど、なにか面白いことができそう。

## 画像からコード進行を生成
画像からキャプションを生成するモデルもある。
よって画像にあったコード進行の生成もできるかも。
以前画像からmidiの生成をしてみたが（非機械学習）、その時はコード進行を適当に設定していた。
http://image2midi.a2kiti.com/
これに画像からそれにあったコード進行を作って当てはめてみたら面白そうなので次やってみたい。

## メロディや伴奏の生成
一番やりたいのはコードだけでなくメロディや伴奏を生成して、歌詞を入れたら曲になるようにしたい。でもそんな学習データがないので、実際にやるのは難しい…
ネットに落ちてるギタープロのスコアを解析できるライブラリがあるけど、あのデータでコード進行まで含まれてるのってあんまりないんですよね…
前にソニーがAIに作曲させたみたいな記事が出てたけど、ソニーは13000曲のデータベースを持ってるらしい。

いいなあー。