音楽
DeepLearning
Keras
RNN
LSTM

RNNを用いたコード進行自動生成

【追加】生成結果をweb上で再生出来るようにした。
Chord progressor

作曲する時によく悩むコード進行を自動で作ってくれればいいなと思い作ってみた。

Chord progressor

コード進行自動生成について

勉強中の機械学習・深層学習でとりあえず何か作りたいと思い,考えたのがコード進行自動生成だったけどとっくの昔にすでに行われてた。

ディープラーニングで曲のコード進行を生成するウェブサービスを作りました

そのままたくさんのコード進行を学習させるだけじゃあまり自然なコードにならないみたい。

でも自分で試してみたらわりかしうまく行った気がするので,差別化の意味も含め,任意のアーティスト風コード進行生成の追加機能もつけて公開してみます。

コード進行

コード進行とは曲の和音の流れを表したもので,コード進行を作ってしまえば,そこに合うような雰囲気のメロディをつけることで作曲が可能である。曲によって様々な進行が用いられるが,ある程度このコードが来たらこのコードに行くといった法則がある。
例えば,
カノン進行
C(ドミソ)→G(ソシレ)→Am(ラドミ)→Em(ミソラ) 
王道進行
FM7(ファラドミ)→G7(ソシレファ)→Em7(ミソラレ)→Am7(ラドミソ)  
Let it be とかLet it goとか洋楽でもよく使われる進行
C(ドミソ)→G(ソシレ)→Am(ラドミ)→F(ファラド)  
コード進行の法則といっても絶対のルールではなく,C→GってきたらEmに行っても良いし様々なパターンが有る。多くの曲で使われる進行はそれだけ多くの人が良いと思うものと考えられる。

曲のキー

曲にはキーがあり,C調だとカノン進行はC→G→Am→EmだがD調だとD→A→Bm→F#mとなる。コードというのはキーに対しての役割を持っており,C調で考えるとキーの音をルートとしてCはⅠ,GはⅤ,AmはⅥm,EmはⅢmと表記される(ローマ数字はルートからいくつ離れているか)。キーの異なる曲のコード進行をそのまま学習させようとすると,例えばC→Gというのは
C調: Ⅰ→Ⅴ
F調: Ⅴ→Ⅱ
となり、役割の異なる複数のデータを与えることになってしまいうまく学習できない可能性がある。膨大なデータを与えてニューラルネットワークがキーの事まで理解できるようになれば問題ないのかもしれないが,与えるデータの調を偏らないようにする必要もありそうだし計算時間とかデータの量など色々大変になってしまうんじゃないかと予想される。

 そこで曲のキーはすべて揃えるためにC調へ移調した。曲が短調の場合は3度上の長調として扱った。これによって各コードの役割は固定できるはずである。曲の中では部分的に転調する場合があるが,これはそういうコード進行として学習できると思う。また,曲の中で完全に転調する場合があるが,多くの場合曲の最後のサビで半音上がるとかだと思うので,曲の前半部分を主に使用することでほぼ回避できるはず。

ニューラルネットワークの学習

10000曲のコード進行から1〜5の連続するコードを選び入力とし,その次のコードを正解としてRNN(リカレントニューラルネットワーク)に学習させた。ノード数は256で,活性化関数はRelu,入力データ数は200000とした。出力はソフトマックス関数にすることで,次にどのコードに進むかを決める確率を求めることができる。

例えば,Cと入力したときの次のコードの予想(上位10個)は以下のようになった。
Input chords : C
Predicted chord : ['F' 'C' 'G' 'Am' 'Dm' 'Em' 'Dm7' 'B♭' 'E7' 'G7']
Possibility : [ 0.209 0.184 0.152 0.087 0.068 0.035
0.034 0.029 0.022 0.019]
このように次に行くコードはいろいろ考えられるため,各コードへの進行可能性はかなりバラけている。

次に,C G と入力すると
Input chords : C G
Predicted chord : ['Am' 'C' 'F' 'G' 'Am7' 'Dm' 'B♭' 'Em' 'E7' 'Dm7']
Possibility : [ 0.384 0.298 0.125 0.042 0.032 0.016
0.014 0.010 0.010 0.007]
Amに行こうとしてる!これはカノン進行やⅠ→Ⅴ→Ⅵm→Ⅳなどが多くの曲で使われていることをうまく学習できている結果といえそう。

出力結果の確率で選んだコードを次の入力に追加して繰り返せば,コード進行を自動で生成することができる。確率で選んでいくので毎回異なるパターンとなる。
最初にCを入れると
C → G → Am → F → C → G → Am → G
C → G → Am → Em → F → G → Am → D7
C → E7 → Am → F → G7 → C → F → G7
C → C → F → B♭ → F → C → F → C
C → F → G7 → C → C → F → F → C
C → E → F → Em7 → Am7 → F → C → Am7
C → B♭ → F → G → C → Em7 → Am7 → F

最初にAm
Am → F → G → C → Am → F → G → C
Am → F → G → Am → F → G7 → C → F

最初にFM7
FM7 → G → Em7 → Am → Am → G → Em7 → FM7
FM7 → G6 → Dm → G6 → FM7 → G → FM7 → CM7

最初にDm7
Dm7 → G7 → C → F → Bm7-5 → E7 → Am → D7
Dm7 → Am → Dm7 → Am → B♭ → Am → Am → F

なかなか自然なコードが生成されている!ちゃんと毎回変わるので何回もしていると好きなコード進行に出会えるんじゃないだろうか。

アーティストごとの特徴を捉えたコード進行

次にアーティストごとの特徴を学習して,そのアーティスト風なコード進行を生成することが出来ないか試してみた。あるアーティストの曲だけを学習しようとすると曲数が足りず,すべてのコード進行のパターンを網羅できないと考えられる。しかし,最初にたくさんのアーティストの曲からオーソドックスなコード進行を学習しておき,その後で目的のアーティストのデータのみを入力に用いれば,少ないデータ数で学習することができるはず。(これは転移学習っていうのかな?)

アーティストとして松任谷由実,aiko,ミスチルを選び学習させてみた。最初のコードをCとした時の生成結果をそれぞれ10個示す。

松任谷由実 style
C → B7 → Em → Dm7 → G → Dm7 → G → Em
C → E7 → Am → Dm7 → G7sus4 → C → Dm7 → E7
C → Bm7-5 → E7 → A7 → F → G → Em → Am
C → Am → F → Dm7 → G → C → F → G
C → D7 → Dm7-5 → C → C → FM7 → B♭ → Am7
C → D7 → G → C → Edim → Dm → G → C
C → Em → F → C → G7 → C → D → Bm
C → Dm7 → Em7 → F → C → Am → G → F
C → E7 → F → C → Dm7 → G → E7 → Am
C → B7 → Em → Dm7 → G → Dm7 → G → Em

aiko style
C → G → E7 → Am7 → G → F → C → G
C → G♭m7-5 → Am7 → Dm7 → C → E7 → F → Em7
C → F → C → Dm → G → C → FM7 → Dm
C → B♭ → Am → A♭6 → Em → E → Am → G
C → Dm7 → G7 → C → Am7 → F → C → Dm7
C → F → Em7 → Dm7 → G7 → F → E7 → Am7
C → Em → F → G → A♭dim → Am → Dm → Em
C → D → F → G → Dm7 → Em → Fm → G
C → E → D → F → G → Am → C → C7
C → E♭ → F → C → A♭ → B♭ → C → Cm7

Mr.children style
C → G → G → F → C → C → G → Am
C → F → G → E7 → Am → Dm → G → C
C → Em7 → F → G → C → Am → F → G
C → C → C → C → Dm → Dm → F → A♭
C → Gsus4 → C → Dm → Em → Am → Dm → F
C → F → G → Em → Am → Dm → G → C
C → Cadd9 → Csus4 → C → F → G → Em → A
C → Am → Dm → D♭aug → F → Bdim → Gsus4 → G
C → E7 → Am7 → G → Dsus4 → D → Dm7 → G7
C → A♭ → B♭ → C → A♭ → B♭ → C → A♭

どうなんだろ,なんとなく違う傾向になってる,,,のかな?
いろんなコードで試したらそれっぽくなったりするんだろうか評価しづらい,,,

キーの推定

すべてのキーに対応できるように,入力したコードからキーを推定できるようにした。次のコード予測と同じように,1〜5の連続するコードを選び入力,曲のキーを正解としてRNNに学習させた。

Input chords : C
Predicted key : ['C' 'G' 'E' 'F' 'A']
Possibility : [ 0.499 0.238 0.085 0.075 0.031]

Input chords : C G Am
Predicted key : ['C' 'G' 'A' 'E' 'F']
Possibility : [ 0.690 0.210 0.072 0.014 0.003 ]

Input chords : Dm F
Predicted key : ['F' 'C' 'A' 'D' 'D']
Possibility : [ 0.424 0.269 0.183 0.102 0.005]

きちんとキーを推定できているといえる。C調以外のキーに設定するときは,まず入力をC調にしてから計算を行い最後にそのキーに合わせて移調して出力する。

まとめ

わりと自然なコード進行が生成できた!そのまま使えそうなコードが出力されるときもあるし,出力をベースに更に自分で修正して使ってもいいし,作曲のときに使えるかもしれないので,よかったら使ってください。

 コードの長さを反映させたり,8小節できれいに完結するようにするにはどうしたらいいんだろう。コードの長さは半小節を単位として,基本的には2個づつ連続させとくとか?最後のコードをトニックにつながるようにしたりするには,最初と最後が決まってて穴埋めをするようなネットワークが出来ればよさそう。

 あと今回LSTMを使ったが,よく考えたら入力を1〜5個としたのでLSTMではなくて通常のRNNで十分だったはず。ディープラーニングの練習も兼ねたつもりだったけど,考慮する時間ステップの少ないRNNってディープラーニングとはいわないのかな。