Amazon Web Services ブログ

AWS DeepComposer での独自のデータを使った音楽ジャンルモデルの作成

AWS DeepComposer は、生成 AI を教え、敵対的生成ネットワーク (GAN) を使って提供されたメロディを完全にオリジナルな曲に変換する AWS の教育サービスです。AWS DeepComposer を使用することにより、事前訓練済みの音楽ジャンルモデル (ジャズ、ロック、ポップ、シンフォニー、ジョナサン・コールトンなど) のひとつを使用する、または独自のモデルをトレーニングできます。音楽データファイルは、カスタム音楽ジャンルモデルをトレーニングする一環として NumPy オブジェクトに保存します。この記事は、GitHub にある Lab 2 – Train a custom GAN model のトレーニング手順に沿って、MIDI ファイルを AWS DeepComposer に適切なトレーニング形式に変換する方法について説明します。

このユースケースでは、レゲエ音楽ジャンルモデルをトレーニングするために独自の MIDI ファイルを使用します。源をジャマイカ島に発するレゲエ音楽は、通常、ベースギター、ドラム、および打楽器を使用しますが、この記事の手順は汎用性が高いため、どの音楽ジャンルにでも使用できます。

トレーニングデータを生成するためのデータ処理

トレーニングデータの開始状態となるのが MIDI (.mid) ファイルです。ソフトウェアはファイルを生成 (および読み込み) し、ファイルには曲譜と再生サウンドに関するデータが含まれています。データ処理の一環として、MIDI ファイルを NumPy アレイに変換し、それらを単一の .npy ファイルでディスクに永続化する必要があります。以下の図は、この変換プロセスを示すものです。

.csv ファイルは、機械学習でのデータの保存用に幅広く使用されていますが、.npy ファイルはトレーニングプロセスにおけるより高速な読み込み用に高度に最適化されています。.npy ファイルの最終シェイプは (x、32、128、4) になります。これは、(number of samples, number of time steps per sample, pitch range, instruments) を表しています。

MIDI ファイルを適切な形式に変換するには、以下の手順を実行します。

  1. MIDI ファイルを読み込んで Multitrack オブジェクトを生成する。
  2. 使用する 4 個のインストゥルメントトラックを決定する。
  3. 各トラックの pianoroll マトリクスを取得し、適切な形式に変換する。
  4. 所定のインストゥルメントの pianoroll オブジェクトを連結させて、それらを .npy ファイルに保存する。

Multitrack オブジェクトを生成するための MIDI ファイルの読み込み

データ処理の最初のステップは、各 MIDI ファイルを解析して Multitrack オブジェクトを生成することです。以下の図は、Multitrack オブジェクトを示しています。

このプロセスをサポートするライブラリが Pypianoroll で、これは Python コード内から MIDI ファイルの読み込みと書き込みを行う機能を提供します。以下のコードを参照してください。

#init with beat resolution of 4 

music_tracks = pypianoroll.Multitrack(beat_resolution=4)
#Load MIDI file using parse_midi
#returns Multitrack object containing Track objects

music_tracks.parse_midi(your_midi_file_directory + your_midi_filename)

music_tracks は、MIDI ファイルから読み込まれた Track オブジェクトのリストが格納される Mulitrack オブジェクトです。各 Mulitrack オブジェクトには、以下のコードにあるように、テンポ、ダウンビート、ビート解像度、および名前が含まれます。

tracks: [FRETLSSS, ORGAN 2, CLAVINET, MUTED GTR, CLEAN GTR, VIBRAPHONE, DRUMS],
tempo: [120. 120. 120. ...120. 120. 120.],
downbeat: [ True False False False False False False False False . . .
 False False False False False False False False False False False False],
beat_resolution: 4,
name: “reggae1”

使用する 4 個のインストゥルメントトラックの決定

解析した Multitrack オブジェクトにちょうど 4 個のインストゥルメントが含まれる場合は、この手順を省略できます。

前述の解析済み Multitrack オブジェクトには、合計で 7 個のインストゥルメントトラック (フレットレス (エレキベース)、クラビネット、ミュートギター、クリーンギター、ビブラホン、およびドラム) があります。モデルが学ばなければならないインストゥルメントが多いほど、トレーニングの時間が長くなり、コストも高くなります。選択した GAN が 4 個のインストゥルメントしかサポートしないのはこのためです。MIDI ファイルのトラックに 5 個以上のインストゥルメントが含まれる場合は、選択したジャンルで最も一般的な 4 個のインストゥルメントを使ってモデルをトレーニングしてください。反対に、トラックごとに少なくとも 4 個のインストゥルメントがない場合は、MIDI ファイルを補強する必要があります。インストゥルメントの数が間違っていると、NumPy のシェイプエラーが引き起こされます。

所定のトラック上にある各インストゥルメントには、プログラム番号があります。プログラム番号は General MIDI の仕様によって決定されるもので、インストゥルメントに対する固有の識別子のようなものです。以下のコード例は、関連するプログラム番号を使ってピアノ、オルガン、ベース、およびギターの各インストゥルメントを抽出します。

instrument1_program_numbers = [1,2,3,4,5,6,7,8] #Piano
instrument2_program_numbers = [17,18,19,20,21,22,23,24] #Organ
instrument3_program_numbers = [33,34,35,36,37,38,39,40] #Bass
instrument4_program_numbers = [25,26,27,28,29,30,31,32] #Guitar
if track.program in instrument1_program_numbers: 
     collection['Piano'].append(track)
elif track.program in instrument2_program_numbers:
     collection['Organ'].append(track)
elif track.program in instrument3_program_numbers:
     collection['Bass'].append(track)
elif track.program in instrument4_program_numbers:
     collection['Guitar'].append(track)

各トラックの pianoroll マトリクスの取得と適切な形式への変換

Multitrack オブジェクトには、インストゥルメントごとに単一の Track オブジェクトがあります。各 Track オブジェクトには、pianoroll マトリクス、プログラム番号、トラックがドラムかどうかを示すブール、および名前が含まれています。

以下のコード例は単一の Track を示しています。

pianoroll:
[[0 0 0 ...0 0 0]
 [0 0 0 ...0 0 0]
 [0 0 0 ...0 0 0]
 ...
 [0 0 0 ...0 0 0]
 [0 0 0 ...0 0 0]
 [0 0 0 ...0 0 0]],
program: 7,
is_drum: False,
name: CLAVINET

トレーニングのため、単一の pianoroll オブジェクトには、曲のスニペットと 128 個のピッチを表す 32 個の個別のタイムステップが存在する必要があります。選択したインストゥルメントトラックのための pianoroll オブジェクトの開始シェイプは (512、128) で、これを適切な形式に変換する必要があります。 各 pianoroll オブジェクトは、ピッチが 128 個の 2 つの小節 (32 タイムステップ) に変換されます。以下のコードを入力すると、単一の pianoroll オブジェクトの最終シェイプが (16、32、128) になります。

#loop through chosen tracks
for index, track in enumerate(chosen_tracks):  
     try:
          #reshape pianoroll to 2 bar (i.e. 32 time step) chunks  
          track.pianoroll = track.pianoroll.reshape( -1, 32, 128)
            
          #store reshaped pianoroll per instrument
          reshaped_piano_roll_dict = store_track(track, reshaped_piano_roll_dict)     
     except Exception as e: 
         print("ERROR!!!!!----> Skipping track # ", index, " with error ", e)

簡潔にするために、以下のコード例はピアノトラック用に生成されるサンプルのみになっています。

{'Piano': [Track(pianoroll=array([[[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8), program=7, is_drum=False, name=CLAVINET)]

所定のインストゥルメント用の pianoroll オブジェクトの連結と .npy ファイルへの保存

次の手順では、すべてのトラックをインストゥルメントごとに連結して、それらを .npy トレーニングファイルファイルに保存します。このプロセスは、pianoroll オブジェクトを重ね合わせるプロセスとして考えることができます。このプロセスは、選択した 4 個のインストゥルメントそれぞれに繰り返す必要があります。以下のコードを参照してください。

def get_merged(music_tracks, filename):

...

#will hold all merged instrument tracks 
merge_piano_roll_list = []
    
for instrument in reshaped_piano_roll_dict: 
     try:
          merged_pianorolls = np.empty(shape=(0,32,128))

          #concatenate/stack all tracks for a single instrument
          if len(reshaped_piano_roll_dict[instrument]) > 0:
               if reshaped_piano_roll_dict[instrument]:     
                    merged_pianorolls = np.stack([track.pianoroll for track in reshaped_piano_roll_dict[instrument]], -1)
                    
               merged_pianorolls = merged_pianorolls[:, :, :, 0] 
               merged_piano_rolls = np.any(merged_pianorolls, axis=0)
               merge_piano_roll_list.append(merged_piano_rolls)
     except Exception as e: 
          print("ERROR!!!!!----> Cannot concatenate/merge track for instrument", instrument, " with error ", e)
            
        
merge_piano_roll_list = np.stack([track for track in merge_piano_roll_list], -1)
return merge_piano_roll_list.reshape(-1,32,128,4)

ここで、統合された pianoroll を .npy ファイルに保存します。以下のコードを参照してください。

#holds final reshaped tracks that will be saved to training .npy file
track_list = np.empty(shape=(0,32,128,4))

. . .

#merge pianoroll objects by instrument 
merged_tracks_to_add_to_training_file = get_merged(music_tracks, filename)

#concatenate merged pianoroll objects to final training data track list
track_list = np.concatenate((merged_tracks_to_add_to_training_file, track_list))

# binarize data
track_list[track_list == 0] = -1
track_list[track_list >= 0] = 1

#save the training data to reggae-train.npy
save(train_dir + '/reggae-train.npy', np.array(track_list))

結果

コードが、your_midi_file_directory に保存された MIDI ファイルのセットに基づいて reggae-train.npy を生成します。Jupyter ノートブックと完全なコードは、GitHub リポジトリで入手可能です。

トレーニングデータファイルができたところで、AWS DeepComposer samples ノートブックにある Lab 2 – Train a custom GAN model に従ってカスタム音楽ジャンルモデルをトレーニングしましょう。

この記事では、SoundCloud に AI 生成の 2 つのレゲエ風トラック、Summer BreezeMellow Vibe を提供します。

Summer Breeze

Mellow Vibe

ヒントとコツ

データについて理解し、最高音質の音楽を生成するためは、以下のヒントとコツを役立ててください。

GarageBand での MIDI ファイルの表示とリスニング

Mac をお持ちの場合は、GarageBand を使用して MIDI ファイルを聴き、伴奏インストゥルメントを表示することができます。Mac をお持ちでない場合は、MIDI ファイルをサポートするその他すべてのデジタルオーディオワークステーション (DAW) を使用できます。AI 生成音楽は、GarageBand を使用して聴くと音質が大幅に良くなります。プロレベルの USB スピーカーを接続してサウンドを増幅することも可能です。

プログラム番号を使用した伴奏インストゥルメントの変更

Lab 2 – Train a custom GAN model からの推論コードを実行しているときは、すべての AI 生成トラックが GarageBand で「Steinway Grand Piano」として表示されるのが分かると思います。AWS DeepComposer コンソールを使い慣れている場合は、伴奏インストゥルメントを変更することができます。カスタムモデルのトレーニング時に伴奏インストゥルメントを変更するには、midi_utils にある save_pianoroll_as_midi 関数を呼び出すときにプログラムパラメータを使用します。以下のコードを参照してください。

#use programs to provide the program numbers for the instruments I care about
#17 = Drawbar Organ, 28 = Electric Guitar, 27 = Electric Guitar, 11 = Music Box
midi_utils.save_pianoroll_as_midi(fake_sample_x[:4], programs=[17, 28, 27, 11], destination_path=destination_path)

GarageBand を使用した伴奏の追加

AI 生成の曲 (伴奏付き) がある場合は、GarageBand (または同様のツール) を使って伴奏を追加できます。トラックのテンポ (つまり速度) を調整したり、特定のインストゥルメントをミュートしたりすることもできます。また、伴奏インストゥルメントを好きなだけ追加して、ユニークなサウンドを創り出すこともできます。

AWS DeepComposer コンソールでの推論メロディの作成

推論を実行するときには、MIDI 形式のカスタムメロディが必要です。伴奏インストゥルメントを追加してユニークな曲を生成するには、カスタムメロディを使用します。カスタムモデルをトレーニングするときにメロディを作成する最も簡単な方法は、AWS DeepComposer コンソールの使用です。仮想キーボード、または AWS DeepComposer キーボードを使ってメロディを録音し、[ダウンロード] を選択して MIDI ファイルとしてダウンロードすることができます。

matplotlib を使用した pianoroll のプロット

pianoroll オブジェクトは、plot 関数を Track で使用してプロットできます。これによって、pianoroll オブジェクトの視覚的表現が提供されます。以下のコードを参照してください。

import matplotlib.pyplot as plt

...

fig, ax = track.plot()
plt.show()

以下のプロットは、pianoroll オブジェクトがどのように見えるかを示したものです。

データのバイナリ化

このコードには、データをバイナリ化するセクションがあります。バイナリ入力が関与するときは、モデルが 0 と 1 ではなく、-1 と 1 で動作するので、この更新は大切です。track_list には最終トレーニングデータが含まれており、これは reggae-train.npy に永続化する前に -1 または 1 に設定する必要があります。以下のコードを参照してください。

# binarize data
track_list[track_list == 0] = -1
track_list[track_list >= 0] = 1

まとめ

AWS DeepComposer は単なるキーボードではありません。生成 AI と GAN の複雑性を学ぶための楽しく魅力的な方法です。新しい曲のインスピレーションとなり得るシンプルなメロディの演奏を学ぶことができ、独自のカスタム音楽ジャンルモデルをトレーニングする機能では、極めてユニークなサウンドを創り出すことができます。2 つのジャンルを融合させて新しいジャンルを生み出すことさえも可能です!

A Cloud Guru で近日公開される私の無料ウェブシリーズ「AWS Deep Composer: Train it Again Maestro」をぜひご覧ください。6 つのエピソードから成るこのウェブシリーズでは、機械学習、音楽用語、そして生成 AI と AWS DeepComposer を使って曲を生成する方法について学ぶことができます。シリーズは、「Battle of the DeepComposers」対決で締めくくられます。このバトルでは、私の生成 AI 音楽と別のインストラクターによる音楽を対決させ、皆さんからお気に入りの音楽に投票してもらいます。お楽しみに!

お気に入りのアーティストからインスピレーションを受けた私の AI 生成音楽を聞くには、me on SoundCloud をフォロー、または LinkedIn でつながることができます。


著者について

Kesha Williams は、25 年の IT 経験を持つ AWS Machine Learning Hero、Alexa Champion、受賞ソフトウェアエンジニア、そして A Cloud Guru のトレーニングアーキテクトです。