自動作曲AI Music Transformerの衝撃

# 〜AIが名曲を生み出す〜
この音楽を聴いてみてください。

<p class="codepen" data-height="164" data-theme-id="light" data-default-tab="result" data-user="nayusato" data-slug-hash="ExgZWjz" style="height: 164px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="MusicTransformerDemo">
  <span>See the Pen <a href="https://codepen.io/nayusato/pen/ExgZWjz">
  MusicTransformerDemo</a> by NayuSato (<a href="https://codepen.io/nayusato">@nayusato</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
[埋め込みが見られない場合はここ](https://magenta.tensorflow.org/assets/piano_transformer/clair_de_lune_continuation.mp3)

これはGoogleの自動作曲Music Transformerが生み出した曲の1つです。
入力は、最初の6秒だけ。
クラシックのドビュッシー「月の光」の冒頭6秒だけを与えて、その続きを全て作らせるというタスクを行わせています。
十分聴き入って感動できるような曲に仕上がっています。
ケチをつけられる点がないとは言わないけれど、「人の作った曲です」と言われても識別できないほどの精度になっています。

### 「Music Transformer」
2018年Googleが発表した自動作曲のAI。
自然言語処理のアルゴリズムである`Transformer`を音楽に適用することにより、それ以前とははるかに違う性能の音楽生成が可能となりました。
2019年には、OpenAIの[MuseNet](https://openai.com/blog/musenet/)もGPT-2（自然言語処理のネットワーク）を用いる形で追随しました。

この記事では、Music Transformerのアルゴリズムと、それがどのように既存の課題を解決したかを説明します。

# Music Transformerの解説
### イメージだけつかみたいです！という方のための3行説明

- Music Transformerは、前の音を元に次の音を逐次的に生成していく
- この際、`Attention重み`によって適切に前の音を参照しながら生成する
- そのため、繰り返し構造が生まれやすくなっている
![MTの可視化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/f5ea87d1-3044-0b5e-2996-25a153777be8.png)

### 自然言語処理におけるAttention機構・Transformer
前提として、自然言語処理のTransformerを解説します。
Google翻訳にも使われている技術です。
従来のRNNでは、データを入力した後の出力をもう一度入力層につなぐことで系列を処理します。
しかしこれには、過去の情報が薄まってしまうという欠点があります。
この性質をカバーするため、忘却ゲートをもうけた、`LSTM（Long Short-Term Memory）`が考案されてきましたが、これによって性能は向上したものの、長い系列をうまく学習し生成するには不十分でした[^lstm]。

[^lstm]: LSTMを用いた作曲の例はこれなど。[How to Generate Music using a LSTM Neural Network in Keras](https://towardsdatascience.com/how-to-generate-music-using-a-lstm-neural-network-in-keras-68786834d4c5)

そこで出てきたのが、過去の系列のどこを参照するかのパラメータ`Attention重み`さえも学習してしまおうという考え方です。[^attention]
直接、過去の入力の情報を参照するようにすることで、長い系列であっても過去の情報が失われなくなります。
このAttentionという機構を用いた自然言語処理モデルを`Transformer`と呼びます。

[^attention]: Attentionはあくまで用語であり、心理学・神経科学におけるAttentionが同じ機構であることを意味しません（似た構造で時間情報処理をしていたらとっても面白いけど）。

1単語前を0.1、2単語前を0.1、3単語前を0.3…、のように重みをつけて合算します。
どの単語を参照するかは文脈によって変わってきます。
前の単語の参照の強さまでを学習してしまうことにより、文脈によって柔軟に参照先を変えながら、文章の翻訳や続きの生成ができます。
![Attentionの説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/34d9811f-bda3-c563-2c80-6b72941982a2.png)
<details><summary>図の詳しい説明はここを開く</summary>
・単語をエンコーダーに1つずつ入力する
・変換開始を表す`
`を入力
・現在のデコーダーの状態と、過去のエンコーダーの状態の関数から、スコアを算出（関連度を表す）
・スコアを`softmax`関数で和を1にする。これが`Attention重み`になる
・`Attention重み`で重みをつけて、過去のエンコーダーの状態の重み付き和を取る
・文脈ベクトルと現在の隠れ状態を結合して、予測分布を生成
・この予測分布を`softmax`に通して、単語の出力を得る（例："Je"）
・次の入力は、前の単語の出力（"Je"）の埋め込み表現と、文脈ベクトルとを結合したものをデコーダーに入れる
・デコーダーがセンテンス末を表す`
`を出力したら終わり
詳しくは、[Neural machine translation with attention](https://www.tensorflow.org/tutorials/text/nmt_with_attention)
</details>

**分かりやすい例： 文脈が異なった時の指示語のAttention重み**
Attention機構では、どのような語が前にエンコードされるかによって隠れ状態が変わってきます。そのため、計算されるAttention重みも文脈の影響を受けて変わります。
単語"it"の意味と文脈は単語単独では決まらず、その前後の入力によって決定されます。
![文脈による違い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/afc4abf0-cff9-a952-57bb-dad364f89eec.png)
(図は[Google AI Blog](https://ai.googleblog.com/2017/08/transformer-novel-neural-network.html)を元に作成)

Transformerの事前学習においては、

- マスクされた1単語を予測させる
- 与えられた2つの文が隣接する2文かどうかを判断させる

などが使われます。
**Attention自体には教師データがない**ですが、出力結果の誤差を少なくするように学習が進むことで、Transformerは文脈を獲得します。

### 大規模なデータの用意
Transformerの学習のためには、大規模かつ質の良いデータが必要となります。
さすがはGoogle、**YouTube**を使いました。
YouTubeの利用ライセンスのあるピアノ音源の動画を用いて、数十万もの音声データを用意。
このデータは音声データですが、Googleが別途開発した、音声データ→楽譜形式（正確にはMIDIのような形式）に変換する技術[^onsets]を活用して、データを変換し、
1万時間もの質の良い学習データを作り出しました[^data]。

[^onsets]: [Onsets and Frames: Dual-Objective Piano Transcription](https://magenta.tensorflow.org/onsets-frames)

[^data]: そう簡単には他社や研究機関が追随できるデータ量ではない。サービスを行いながら研究活動をする企業が研究も強いのだなぁと思う。

### 音楽情報の簡略化
Transformerで学習させるためには、1単語1単語に対応するベクトル (one-hot vector) を用意し、それを入力として1単語ずつ逐次的に出力を行う必要があります。
音楽では同時に音が鳴ったり、テンポが一定でなかったりするので、これをそのまま音楽に適用することはできません。

Music Transformerでは新たな楽譜形式を使っています。
（MIDIという従来の楽譜データ形式が元になっている）

- 88段階の音程のNOTE_ON：音の始まりを表す  
（最低音のラ～最高音のドの88段階）
- 88段階の音程のNOTE_OFF：音の終わりを表す
- 10 ms刻みのTIME_SHIFT：時間軸を進めることを表す  
（10, 20, 30, ... , 1000 ms）
- 32段階のSET_VELOCITY：次の音の強さを表す  
（4, 8, 12, ... , 128)
[^eos]

[^eos]: 加えて、paddingとeos（終了符）が存在する

これを用いると、次の例のように「ドーミーソー（休）ファ」を離散のトークンの列として表すことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/75e91829-20be-8b11-e720-c46c74551f6a.png)
（Huang et al., 2018より引用）

これで、メロディ・リズム・和音を全てベクトルの列として扱う準備ができました。
実際には、このトークンを`one-hot vector`[^onehot]として入力することで学習・生成が行われます。
学習の際は、音楽データの系列から、続きのトークンを予測させることによって、教師あり学習を行います。

[^onehot]: n次元ベクトルの中の1箇所だけが1で、他が全て0となるベクトル。例えば、事前に{ド、レ、ミ}と表すように決めておけば、「ド」={1,0,0}、「レ」={0,1,0}と表すことができる。

### Music Transformerの生成方法
Music Transformerは逐次的に1トークンずつを生成します。
前に入力されたトークンによって決まる隠れ状態によって、`Attention重み`が決定します。
`Attention重み`を可視化したのが、この図。弧が`Attention重み`を表しています。
前の音に似た形の音が入力されれば、前の音を強く参照するため、繰り返しが生まれてきやすくなります。
![MTの可視化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/f5ea87d1-3044-0b5e-2996-25a153777be8.png)

例えば、「ドレミファ」という音が事前に入力された後に、また「ドレ」という音が入力されると、
`Attention重み`は時間を隔てた「ドレミファ」に強く働くようになります。
そのため、「ドレミファ」という音がまた繰り返されやすくなります。

実際には、次の音の予測は分布として表されます。この場合だと「ドレ」の次には「ミ」が最も来やすいが、「ド」の可能性もある、といった形です。
最後に、出力された分布を`softmax`関数に通し、確率的に1つの音を決定します。
確率が高い音は選ばれやすいですが、確率の低い音もたまに選ぶため、生成するたびに多様な音楽が出力されます。

### Music Transformerを使ってみよう
Google公式のColab：
https://colab.research.google.com/notebooks/magenta/piano_transformer/piano_transformer.ipynb

実際に生成してみた曲がこれ。
<p class="codepen" data-height="158" data-theme-id="light" data-default-tab="result" data-user="nayusato" data-slug-hash="VwKPVdJ" style="height: 158px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="GeneratedMusic">
  <span>See the Pen <a href="https://codepen.io/nayusato/pen/VwKPVdJ">
  GeneratedMusic</a> by NayuSato (<a href="https://codepen.io/nayusato">@nayusato</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

[埋め込みが見られない場合はここ](https://drive.google.com/file/d/1imfAN_kv7tWw6sR77lRaaSNqopgRhGSN/view?usp=sharing)

なんちゅう悲しい曲になってしまったんだ……月の光が見えない深い夜になってしまいました。
せっかくなので音楽理論的に分析してみました。

- 音楽理論的には、冒頭のD♭調からD♭7をドミナントのC#7として捉えて、暗いF#m調に転調している
- 途中で冒頭のメロディに戻ってきている
- 後半はもう一度転調した後、同じモチーフを変形させて何回も繰り返している

…みたいに深読みできるくらいにはちゃんとした曲に仕上がっています。
![生成曲.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280275/23907bee-33a7-c18f-365f-1f56284a7979.png)


# Mucic Transformerが解決した2つの課題
上記の説明にもある**繰り返し**を自然に作れるというのはすごい技術革新だったのです。
Music Transformer以前にも自動作曲の技術は多くありましたが、主に2つの課題がありました。

### 課題1：繰り返しが作れない
音楽には時間的構造があります。
米津玄師の「Lemon」を例に取ると、
　　「♪あの日の悲しみさえ」：主題の提示
　　「♪あの日の苦しみさえ」：同じ主題の繰り返し
こういう隣接した繰り返しもあれば、
　　「♪どこかであなたが今」：2番でもう一度繰り返し
のように、1番と2番のように離れたところでの繰り返しもあります。
このような**様々な時間スケールにおける繰り返し**が存在しています。
クラシックにおいても、
　提示部（主題の提示）・展開部（違うことする）・再現部（最初の主題に戻ってくる）
となっていて、長い時間スケールにおける繰り返しが存在しています。

時間的に、前のものに依存しながら生成するアルゴリズムとしては、`RNN (Recurrent Neural Network)`がありますが、繰り返しをうまく生めていない点が課題でした。
（RNN：出力層を入力層に繋ぐことによって、時系列データを生成する手法）

RNNを用いた手法としては、Googleの[Performance RNN](https://magenta.tensorflow.org/performance-rnn)（2017年）があります。
それっぽい雰囲気の曲は作れるものの、RNNだと生成を続けるほどに時間的に古い情報が薄まっていくので、長期的な時間的構造を持たすには向いていません。
結果、繰り返しがなく、とりとめもない曲が生み出されてしまいます。

繰り返しのない音列は音楽とは言いがたい。
人は、音楽を聴きながら「次の音は何かな？」と予測し、その予測が当たったり外れたりすることによって感情が動かされていると考えられています。[^neuro]
この繰り返しをうまく作れないと、聴きやすい音楽にはなりません。

[^neuro]: 神経科学においては近年、音楽において快感情を感じるのは、予測が確実に立つ中での大きな予測のズレ（Surprise）の瞬間であることが示唆されている（[Cheung et al., 2019](https://www.sciencedirect.com/science/article/pii/S0960982219312588)）。繰り返しがない場合、予測が立たず、それゆえズレも生まれず、「なにこの曲…」となってしまう。程よく繰り返して、程よくはずす程度の、繰り返しと変化が音楽には必要である。

この観点で最初の音源をもう一度聴いてもらうと、39秒のところで冒頭のメロディに戻ってきています。
**勝手に繰り返しが作れています。**（しかもちょっとアレンジが入る）
情報が薄まってしまう従来手法ではこれはなし得なかったことです。

### 課題2：文脈の影響をうまく表現できない
音楽には文脈性があります。
前に来たものによって、調が決まり、スケールが決まり、またリズムとメロディと和音も相互に絡み合っています。

文脈性を遷移確率として扱う手法としては、`遷移確率`を用いた方法があります。
ドの次にレに行く確率は0.4、ドの次にド#に行く確率は0.1などのように、音から音への遷移を確率的に扱い、それに沿って音をサンプリングし生成していく手法。
学習データから遷移確率（≒出現頻度）を算出して、それを基に生成すれば、学習データと似た構造の音楽を作ることができます。
例えば、「ドの次にドレミファソラシの音は来やすいが、ド#などの半音は来づらい」などのような音楽構造を数式的に定義することができます。
ただ、これには欠点が2つあります。

- **長い時系列になるほど扱いにくい**  
例えば、ド→レ→ミ→ファ→ソの遷移が起きやすいことを表そうとすると、4次の遷移確率まで定義する必要がある。実際上無限の次数を定義することは難しく、遷移確率の学習をするのも難しい。
- **メロディ・リズム・和音を統一的に扱うのは難しく、その相互作用を表せない**  
この3要素は互いに絡み合っていて、和音が決まることでメロディに制約がかかったり、メロディによって次に起こりそうなリズムが決まったりする。これを扱うためには、メロディ・和音・リズムのそれぞれの遷移確率を定義した上で、その相互作用の定式化までせねばならず現実的ではない。

この観点で冒頭の音源を聴いてみると、冒頭から途中までD♭調の和音とスケールで、リズムも4拍子になっていて、1つの文脈が引き継がれています。
これらは指定しておらず**たった6秒の冒頭を与えただけなのに**。

これらの課題を**自然言語処理アルゴリズム**と**大規模なデータ**とで打ち破ったのがMusic Transformerでした。
ぜひMusic Transformerを触って作曲してみてください。

# 参考文献

- Music TransformerのGoogleの元記事  
[Music Transformer: Generating Music with Long-Term Structure](https://magenta.tensorflow.org/music-transformer)
- Googleの記事の第2弾  
[Generating Piano Music with Transformer](https://magenta.tensorflow.org/piano-transformer)
- 論文  
[Huang et al. (2018) Music Transformer: Generating Music with Long-term Structure](https://arxiv.org/abs/1809.04281)
- Pop音楽に適用した例  
[Pop Music Transformer: Beat-based Modeling and Generation of Expressive Pop Piano Compositions](
https://arxiv.org/abs/2002.00212)
- 中山光樹(2020) 「機械学習・深層学習による自然言語処理入門」

---
この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ Twitter や facebook、はてなブックマークにてコメントをお願いします！
また [DeNA 公式 Twitter アカウント @DeNAxTech](https://twitter.com/DeNAxTech) では、 Blog記事だけでなく色々な勉強会での登壇資料も発信してます。ぜひフォローして下さい！
<a href="https://twitter.com/DeNAxTech?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-size="large" data-lang="ja" data-show-count="false">Follow @DeNAxTech</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>