自成一派,这个做曲大师确实名副其实!

image

AWS DeepComposer 是一项教育型的 AWS 服务,能够训练出生成式人工智能,并利用 GAN(Generative Adversarial Network)转换输入的旋律,创做出完整的原创乐曲。git

以前咱们曾有篇文章详细介绍过该服务,感兴趣的童鞋能够在这里查看:当音乐赶上人工智能 -- 歌手们都在「云竞演」,做曲家就不想试试「云谱曲」?github

简单来讲,借助 AWS DeepComposer,咱们可使用预先训练好的音乐流派模型(如爵士、摇滚、流行、交响乐等)将咱们提供的旋律转换为相应流派的曲子。那么当你玩转这个服务后,有没有想过本身也「开宗立派」,经过必定的参数训练出本身的流派选项?segmentfault

固然能够!咱们只须要将音乐数据文件存储在 NumPy 对象中,随后结合 GitHub 上的 Lab 2—— 训练一套自定义 GAN 模型中的训练步骤进行操做便可。下文将介绍如何将 MIDI 文件转换为适用于 AWS Deepomposer 的格式,而训练出本身的流派模型。数组

在下文中,咱们可使用本身的 MIDI 文件训练出雷鬼音乐流派模型。雷鬼音乐诞生于牙买加岛,经常使用乐器包括低音吉他、鼓以及各种打击乐器。不过本文介绍的方法也是通用的,你们彻底能够借此训练任何其余音乐流派。app

数据处理:生成训练数据

MIDI(.mid)文件是训练数据的最初始状态。MIDI 文件由软件生成(并读取),文件中包括关于音符及声音回放的数据。在数据处理过程当中,咱们须要将 MIDI 文件转换为 NumPy 数组,并将其持久化保存成磁盘上的一个单独的.npy 文件。下图展现了数据的转换过程:
imagecomposer

尽管机器学习广泛使用.csv文件存储数据,但.npy文件是为加速训练过程当中的读取速度高度优化的。.npy文件的最终形态应为(x, 32, 128, 4),其含义分别为(样本数量,每一个样本的时间步数, 音高范围, 乐器)。less

若将 MIDI 文件转换为适当的格式,咱们须要完成如下步骤:机器学习

  1. 读取 MIDI 文件以生成一个 Multitrack 对象。
  2. 肯定要使用的四条乐器音轨。
  3. 检索各音轨中的 Pianoroll 矩阵,并将其调整为正确的格式。
  4. 将 Pianoroll 对象与给定的乐器相匹配,并将其存储在.npy文件中。

读取 MIDI 文件以生成一个 Multitrack 对象

数据处理的第一步,是解析各 MIDI 文件并生成一个 Multitrack 对象。下图即为 Multitrack 对象的基本结构。
image
这个过程用须要用到 Pypianoroll 库,它以 Python 代码实现读取及写入 MIDI 文件的功能。具体参见如下代码:ide

#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 是一个 Mulitrack 对象,包含一个从 MIDI 文件中读取到的 Track 对象列表。每一个 Mulitrack 对象都包含速度(Tempo)、节拍(Downbeat)、节拍分辨率(Beat resolution)以及名称(Name),具体如如下代码所示:函数

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”

肯定要使用的四条乐器音轨

若是要解析的 Mulitrack 对象中刚好包含四种乐器,则能够直接跳过此步骤。

咱们以前解析的 Mulitrack 对象共包含7条乐器音轨(Fretless 电贝司、风琴、竖笛、静音电吉他、清音电吉他、颤音琴和鼓)。模型须要学习的乐器种类越多,训练时间就越长,成本天然也越高。有鉴于此,这里咱们选择的 GAN 只支持最多4种乐器。若是 MIDI 文件中的音轨包含4种以上乐器,请直接从所选择的音乐流派中选择最重要的4种乐器进行模型训练。相应的,若是乐器数量不足4种,则须要扩充 MIDI 文件。乐器数量错误会致使 NumPy 的形制出现错误。

给定音轨上的每一种乐器都拥有本身的编号。编号由通用 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 对象应具备32个离散的时间步长,表明一首歌曲的片断与128个音高。所选乐器音轨的 Pianoroll 对象的起始形态为(512,128),咱们须要将其调整为正确的格式。每一个 Pianoroll 对象将从新调整为2个小节(32个时间步长)、音高为128。输入如下代码后,单一 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 notebook 与完整代码可经过GitHub repo获取。

如今,咱们已经拥有了训练数据文件,接下来就能够根据 AWS DeepComposer 示例 notebook 中 Lab 2—— 训练自定义 GAN 模型提出的步骤训练自定义音乐流派模型。

本文在 SoundCloud 上提供两个由 AI 生成的雷鬼风格音轨:Summer BreezeMellow Vibe

技巧与秘诀

咱们可使用如下技巧与秘诀理解你的数据内容,并生成更悦耳的 AI 乐曲。

在 GarageBand 中查看及收听 MIDI 文件

若是你使用 Mac 设备,可使用 GarageBand 收听 MIDI 文件并查看其中使用的乐器。若是没有 Mac 设备,则可以使用任何其余支持 MIDI 文件的Digital Audio Workstation(DAW)。在经过 GarageBand 收听 AI 生成的乐曲时,音质要明显更好,甚至能够链接专业级扬声器以得到极好的听觉效果。

使用乐器编号更改伴奏的乐器

在运行Lab 2—— 训练自定义 GAN 模型提供的推理代码时,你们可能会注意到,全部由 AI 生成的音轨都会在 GarageBand 中显示为“Steinway Grand Piano”。若是熟悉 AWS DeepComposer 控制台,则可随时调整乐器种类。要在训练自定义模型时更改伴奏的乐器种类,请在调用midi_utils中的save_pianoroll_as_midi函数时使用programs参数,具体请见如下代码:

#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 键盘记录下旋律,然后选择“Download”将其下载为 MIDI 文件。
image

使用 Matplotlib 绘制 Pianoroll

你们可使用 Track 上的 Plot 函数绘制 Pianoroll 对象,这样就能直观查看 Pianoroll 对象了。具体请参见如下代码:

import matplotlib.pyplot as plt
...
fig, ax = track.plot()
plt.show()

下图所示,为 Pianoroll 对象的基本观感。
image

数据二值化

代码包含了一段对数据进行二进制化的部分。这项更新很是重要,由于在处理二进制化输入时,该模型实际处理的是-1与1(而非0与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 的复杂性。咱们能够在它的帮助下学习演奏简单的旋律,甚至可能激发出创做全新乐曲的灵感、训练出本身的自定义音乐流派模型、最终创造出史无前例的声音。咱们也能够将两种流派融合起来以创造出新的音乐类型!

image