Python 与 TensorFlow2 生成式 AI(四)(3)

简介: Python 与 TensorFlow2 生成式 AI(四)

Python 与 TensorFlow2 生成式 AI(四)(2)https://developer.aliyun.com/article/1512053

用于音乐生成的 LSTM 模型

如前所述,我们的第一个音乐生成模型将是第九章文本生成方法的崛起中基于 LSTM 的文本生成模型的扩展版本。然而,在我们可以将该模型用于这项任务之前,有一些注意事项需要处理和必要的变更需要进行。

不像文本生成(使用 Char-RNN)只有少数输入符号(小写和大写字母、数字),音乐生成的符号数量相当大(~500)。在这个符号列表中,还需要加入一些额外的符号,用于时间/持续时间相关的信息。有了这个更大的输入符号列表,模型需要更多的训练数据和学习能力(学习能力以 LSTM 单元数量、嵌入大小等方面来衡量)。

我们需要处理的下一个明显变化是模型能够在每个时间步骤上接受两个输入的能力。换句话说,模型应能够在每个时间步骤上接受音符和持续时间信息,并生成带有相应持续时间的输出音符。为此,我们利用功能性的tensorflow.keras API,构建一个多输入多输出的架构。

正如在第九章文本生成方法的崛起中详细讨论的那样,堆叠的 LSTM 在能够学习更复杂特征方面具有明显优势,这超过了单个 LSTM 层网络的能力。除此之外,我们还讨论了注意机制以及它们如何帮助缓解 RNN 所固有的问题,比如难以处理长距离依赖关系。由于音乐由在节奏和连贯性方面可感知的局部和全局结构组成,注意机制肯定可以起作用。下面的代码片段按照所讨论的方式准备了一个多输入堆叠的 LSTM 网络:

def create_network(n_notes, n_durations, embed_size = 100,                                          rnn_units = 256):
    """ create the structure of the neural network """
    notes_in = Input(shape = (None,))
    durations_in = Input(shape = (None,))
    x1 = Embedding(n_notes, embed_size)(notes_in)
    x2 = Embedding(n_durations, embed_size)(durations_in) 
    x = Concatenate()([x1,x2])
    x = LSTM(rnn_units, return_sequences=True)(x)
    x = LSTM(rnn_units, return_sequences=True)(x)
    # attention
    e = Dense(1, activation='tanh')(x)
    e = Reshape([-1])(e)
    alpha = Activation('softmax')(e)
    alpha_repeated = Permute([2, 1])(RepeatVector(rnn_units)(alpha))
    c = Multiply()([x, alpha_repeated])
    c = Lambda(lambda xin: K.sum(xin, axis=1), output_shape=(rnn_units,))(c)
    notes_out = Dense(n_notes, activation = 'softmax', name = 'pitch')(c)
    durations_out = Dense(n_durations, activation = 'softmax', name = 'duration')(c)
    model = Model([notes_in, durations_in], [notes_out, durations_out])
    model.compile(loss=['sparse_categorical_crossentropy', 
                        'sparse_categorical_crossentropy'], optimizer=RMSprop(lr = 0.001))
    return model 
network (one input each for notes and durations respectively). Each of the inputs is transformed into vectors using respective embedding layers. We then concatenate both inputs and pass them through a couple of LSTM layers followed by a simple attention mechanism. After this point, the model again diverges into two outputs (one for the next note and the other for the duration of that note). Readers are encouraged to use keras utilities to visualize the network on their own.

训练这个模型就像在 keras 模型对象上调用 fit() 函数一样简单。我们将模型训练约 100 个周期。图 11.4 描述了模型在不同周期下的学习进展:


图 11.4:模型输出随着训练在不同周期下的进展

如图所示,模型能够学习一些重复模式并生成音乐。在这里,我们使用基于温度的抽样作为我们的解码策略。正如在 第九章文本生成方法的兴起 中讨论的,读者可以尝试诸如贪婪解码、纯抽样解码等技术,以了解输出音乐质量如何变化。

这是使用深度学习模型进行音乐生成的一个非常简单的实现。我们将之前两章学到的概念与之进行了类比,那两章是关于文本生成的。接下来,让我们使用对抗网络进行一些音乐生成。

使用 GAN 进行音乐生成

在前一节中,我们尝试使用一个非常简单的基于 LSTM 的模型进行音乐生成。现在,让我们提高一点标准,看看如何使用 GAN 生成音乐。在本节中,我们将利用我们在前几章学到的与 GAN 相关的概念,并将它们应用于生成音乐。

我们已经看到音乐是连续且序列化的。LSTM 或 RNN 等模型非常擅长处理这样的数据集。多年来,已经提出了各种类型的 GAN,以有效地训练深度生成网络。

Mogren 等人于 2016 年提出了 连续循环神经网络与对抗训练:C-RNN-GAN⁴,结合了 LSTM 和基于 GAN 的生成网络的能力,作为音乐生成的方法。这是一个直接但有效的音乐生成实现。与前一节一样,我们将保持简单,并且只关注单声道音乐生成,尽管原始论文提到了使用音调长度、频率、强度和音符之间的时间等特征。论文还提到了一种称为 特征映射 的技术来生成复调音乐(使用 C-RNN-GAN-3 变体)。我们将只关注理解基本架构和预处理步骤,而不试图按原样实现论文。让我们开始定义音乐生成 GAN 的各个组件。

生成器网络

tensorflow.keras to prepare our generator model:
def build_generator(latent_dim,seq_shape):
  model = Sequential()
  model.add(Dense(256, input_dim=latent_dim))
  model.add(LeakyReLU(alpha=0.2))
  model.add(BatchNormalization(momentum=0.8))
  model.add(Dense(512))
  model.add(LeakyReLU(alpha=0.2))
  model.add(BatchNormalization(momentum=0.8))
  model.add(Dense(1024))
  model.add(LeakyReLU(alpha=0.2))
  model.add(BatchNormalization(momentum=0.8))
  model.add(Dense(np.prod(seq_shape), activation='tanh'))
  model.add(Reshape(seq_shape))
  model.summary()
  noise = Input(shape=(latent_dim,))
  seq = model(noise)
  return Model(noise, seq) 

生成器模型是一个相当简单的实现,突显了基于 GAN 的生成模型的有效性。接下来,让我们准备判别器模型。

判别器网络

在 GAN 设置中,判别器的任务是区分真实和生成的(或虚假的)样本。在这种情况下,由于要检查的样本是一首音乐作品,所以模型需要有处理序列输入的能力。

为了处理顺序输入样本,我们使用一个简单的堆叠 RNN 网络。第一个递归层是一个具有 512 个单元的 LSTM 层,后面是一个双向 LSTM 层。第二层的双向性通过查看特定和弦或音符之前和之后的内容来帮助判别器更好地学习上下文。递归层后面是一堆密集层和一个用于二元分类任务的最终 sigmoid 层。判别器网络如下代码片段所示:

def build_discriminator(seq_shape):
  model = Sequential()
  model.add(LSTM(512, input_shape=seq_shape, return_sequences=True))
  model.add(Bidirectional(LSTM(512)))
  model.add(Dense(512))
  model.add(LeakyReLU(alpha=0.2))
  model.add(Dense(256))
  model.add(LeakyReLU(alpha=0.2))
  model.add(Dense(1, activation='sigmoid'))
  model.summary()
  seq = Input(shape=seq_shape)
  validity = model(seq)
  return Model(seq, validity) 

如代码片段所示,判别器也是一个非常简单的模型,由几个递归和密集层组成。接下来,让我们将所有这些组件组合起来并训练整个 GAN。

训练与结果

第一步是使用我们在前几节介绍的实用程序实例化生成器和判别器模型。一旦我们有了这些对象,我们将生成器和判别器组合成一个堆栈,形成整体的 GAN。以下片段展示了三个网络的实例化:

rows = 100
seq_length = rows
seq_shape = (seq_length, 1)
latent_dim = 1000
optimizer = Adam(0.0002, 0.5)
# Build and compile the discriminator
discriminator = build_discriminator(seq_shape)
discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])
# Build the generator
generator = build_generator(latent_dim,seq_shape)
# The generator takes noise as input and generates note sequences
z = Input(shape=(latent_dim,))
generated_seq = generator(z)
# For the combined model we will only train the generator
discriminator.trainable = False
# The discriminator takes generated images as input and determines validity
validity = discriminator(generated_seq)
# The combined model  (stacked generator and discriminator)
# Trains the generator to fool the discriminator
gan = Model(z, validity)
gan.compile(loss='binary_crossentropy', optimizer=optimizer) 

就像我们在前几章中所做的那样,在堆叠到 GAN 模型对象之前,首先将鉴别器训练设置为false。这确保只有在生成周期期间更新生成器权重,而不是鉴别器权重。我们准备了一个自定义训练循环,就像我们在之前的章节中多次介绍的那样。

为了完整起见,我们在此提供参考:

def train(latent_dim, 
          notes, 
          generator, 
          discriminator, 
          gan,
          epochs, 
          batch_size=128, 
          sample_interval=50):
  disc_loss =[]
  gen_loss = []
  n_vocab = len(set(notes))
  X_train, y_train = prepare_sequences(notes, n_vocab)
  # ground truths
  real = np.ones((batch_size, 1))
  fake = np.zeros((batch_size, 1))
  for epoch in range(epochs):
      idx = np.random.randint(0, X_train.shape[0], batch_size)
      real_seqs = X_train[idx]
      noise = np.random.normal(0, 1, (batch_size, latent_dim))
      # generate a batch of new note sequences
      gen_seqs = generator.predict(noise)
      # train the discriminator
      d_loss_real = discriminator.train_on_batch(real_seqs, real)
      d_loss_fake = discriminator.train_on_batch(gen_seqs, fake)
      d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
      #  train the Generator
      noise = np.random.normal(0, 1, (batch_size, latent_dim))
      g_loss = gan.train_on_batch(noise, real)
      # visualize progress
      if epoch % sample_interval == 0:
        print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0],100*d_loss[1],g_loss))
        disc_loss.append(d_loss[0])
        gen_loss.append(g_loss)
  generate(latent_dim, generator, notes)
  plot_loss(disc_loss,gen_loss) 

我们使用了与上一节相同的训练数据集。我们将我们的设置训练了大约 200 个时代,批量大小为 64。图 11.5展示了鉴别器和生成器在训练周期中的损失以及在不同时间间隔内的一些输出:


图 11.5:a)随着训练的进行,鉴别器和生成器损失。b)在不同训练间隔内生成器模型的输出

图中显示的输出突显了基于 GAN 的音乐生成设置的潜力。读者可以选择尝试不同的数据集,甚至是 Mogren 等人在 C-RNN-GAN 论文中提到的细节。生成的 MIDI 文件可以使用 MuseScore 应用程序播放。

与上一节中基于 LSTM 的模型相比,基于这个 GAN 的模型的输出可能会感觉更加精致一些(尽管这纯粹是主观的,考虑到我们的数据集很小)。这可能归因于 GAN 相对于基于 LSTM 的模型更好地建模生成过程的固有能力。有关生成模型拓扑结构及其各自优势的更多细节,请参阅第六章使用 GAN 生成图像

现在我们已经看到了两种单声部音乐生成的变体,让我们开始尝试使用 MuseGAN 进行复声音乐生成。

MuseGAN – 复声音乐生成

到目前为止,我们训练的两个模型都是音乐实际感知的简化版本。虽然有限,但基于注意力的 LSTM 模型和基于 C-RNN-GAN 的模型都帮助我们很好地理解了音乐生成过程。在本节中,我们将在已学到的基础上进行拓展,朝着准备一个尽可能接近实际音乐生成任务的设置迈出一步。

在 2017 年,Dong 等人在他们的作品《MuseGAN: 多轨序列生成对抗网络用于符号音乐生成和伴奏》中提出了一种多轨音乐生成的 GAN 类型框架⁵。这篇论文详细解释了各种与音乐相关的概念,以及 Dong 和他的团队是如何应对它们的。为了使事情保持在本章的范围内,又不失细节,我们将涉及这项工作的重要贡献,然后继续进行实现。在我们进入“如何”部分之前,让我们先了解 MuseGAN 工作试图考虑的与音乐相关的三个主要属性:

  • 多轨互依性:大多数我们听的歌曲通常由多种乐器组成,如鼓,吉他,贝斯,人声等。在这些组件的演奏方式中存在着很高的互依性,使最终用户/听众能够感知到连贯性和节奏。
  • 音乐结构:音符常常被分成和弦和旋律。这些分组以高度重叠的方式进行,并不一定是按照时间顺序排列的(这种对时间顺序的简化通常适用于大多数与音乐生成相关的已知作品)。时间顺序的排列不仅是出于简化的需要,也是从 NLP 领域,特别是语言生成的概括中得出的。
  • 时间结构:音乐具有分层结构,一首歌可以看作是由段落组成(在最高级别)。段落由各种短语组成,短语又由多个小节组成,如此类推。图 11.6以图像方式描述了这种层级结构:

图 11.6:一首歌的时间结构

  • 如图所示,一根小节进一步由节拍组成,在最低的级别上,我们有像素。MuseGAN 的作者们提到小节作为作曲的单位,而不是音符,这是为了考虑多轨设置中的音符分组。

MuseGAN 通过基于三种音乐生成方法的独特框架来解决这三个主要挑战。这三种基本方法分别采用即兴演奏,混合和作曲家模型。我们现在简要解释一下这些方法。

即兴演奏模型

如果我们将前一节中的简化单声部 GAN 设置外推到多声部设置,最简单的方法是利用多个发电机-鉴别器组合,每个乐器一个。干扰模型正是这个设定,其中M个独立的发电机从各自的随机向量准备音乐。每个发电机都有自己的评论家/鉴别器,有助于训练整体 GAN。此设置如图 11.7所示:


图 11.7: 由 M 个发电机和鉴别器对组成的干扰模型,用于生成多轨道输出

如上图所示,干扰设置模拟了一群音乐家的聚合,他们通过独立即兴创作音乐,没有任何预定义的安排。

作曲家模型

如其名称所示,此设置假设发生器是一个典型的能够创建多轨钢琴卷的人类作曲家,如图 11.8所示:


图 11.8: 单发电机组成的作曲家模型,能够生成 M 轨道,一个用于检测假样本和真实样本的鉴别器

如图所示,这个设置只有一个鉴别器来检测真实或假的(生成的)样本。与前一个干扰模型设置中的M个随机向量不同,这个模型只需要一个公共随机向量z

混合模型

这是通过将干扰和作曲家模型结合而产生的有趣想法。混合模型有M个独立的发电机,它们利用各自的随机向量,也被称为轨内随机向量。每个发电机还需要另一个称为轨间随机向量的额外随机向量。这个额外的向量被认为是模仿作曲家并帮助协调独立的发电机。图 11.9描述了混合模型,每个发电机都需要轨内和轨间随机向量作为输入:


图 11.9: 由 M 个发电机和一个单一鉴别器组成的混合模型。每个发电机需要两个输入,即轨间和轨内随机向量的形式。

如图所示,混合模型的M发电机仅与一个鉴别器一起工作,以预测一个样本是真实的还是假的。将演奏和作曲家模型结合的优势在于生成器端的灵活性和控制。由于我们有M个不同的发电机,这个设定允许在不同的轨道上选择不同的架构(不同的输入大小、过滤器、层等),以及通过轨间随机向量的额外控制来管理它们之间的协调。

除了这三个变体,MuseGAN 的作者还提出了一个时间模型,我们将在下面讨论。

临时模型

音乐的时间结构是我们讨论的 MuseGAN 设置的三个重要方面之一。我们在前几节中解释的三个变体(即即兴、作曲家和混合模型)都在小节级别上工作。换句话说,每个模型都是一小节一小节地生成多音轨音乐,但可能两个相邻小节之间没有连贯性或连续性。这与分层结构不同,分层结构中一组小节组成一个乐句等等。

为了保持生成歌曲的连贯性和时间结构,MuseGAN 的作者提出了一个时间模型。在从头开始生成时(作为其中一种模式),该额外的模型通过将小节进行为一个附加维度来生成固定长度的乐句。该模型由两个子组件组成,时间结构生成器 G[时间] 和小节生成器 G[小节]。该设置在 图 11.10 中呈现:


图 11.10:时间模型及其两个子组件,时间结构生成器 G[时间] 和小节生成器 G[小节]

时间结构生成器将噪声向量 z 映射到一个潜在向量序列 。这个潜在向量  携带时间信息,然后由 G[小节] 用于逐小节生成音乐。时间模型的整体设置如下所示:


作者指出,该设置类似于一些关于视频生成的作品,并引用了进一步了解的参考文献。作者还提到了另一种情况,其中呈现了一个条件设置,用于通过学习来生成由人类生成的音轨序列的时间结构。

我们已经介绍了 MuseGAN 设置的具体构建块的细节。现在让我们深入了解这些组件如何构成整个系统。

MuseGAN

MuseGAN 的整体设置是一个复杂的架构,由多个活动部分组成。为了使时间结构保持连贯,该设置使用了我们在前一节中讨论的两阶段时间模型方法。图 11.11 展示了 MuseGAN 架构的简化版本:


图 11.11:简化的 MuseGAN 架构,由 M 个生成器和一个判别器组成,以及一个用于生成短语连贯输出的两阶段时间模型。

如图所示,该设置使用时间模型用于某些音轨和直接的随机向量用于其他音轨。时间模型和直接输入的输出然后在传递给小节生成器模型之前进行连接(或求和)。

然后小节生成器逐小节创建音乐,并使用评论者或鉴别器模型进行评估。在接下来的部分,我们将简要触及生成器和评论者模型的实现细节。

请注意,本节介绍的实现与原始工作接近,但并非完全复制。为了简化并便于理解整体架构,我们采取了某些捷径。有兴趣的读者可以参考官方实现详情和引文工作中提到的代码库。

生成器

如前一节所述,生成器设置取决于我们是使用即兴演奏、作曲家还是混合方法。为简单起见,我们只关注具有多个生成器的混合设置,其中每个音轨都有一个生成器。

一组生成器专注于需要时间连贯性的音轨;例如,旋律这样的组件是长序列(超过一小节长),它们之间的连贯性是一个重要因素。对于这样的音轨,我们使用如下片段所示的时间架构:

def build_temporal_network(z_dim, n_bars, weight_init):
    input_layer = Input(shape=(z_dim,), name='temporal_input')
    x = Reshape([1, 1, z_dim])(input_layer)
    x = Conv2DTranspose(
        filters=512,
        kernel_size=(2, 1),
        padding='valid',
        strides=(1, 1),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Conv2DTranspose(
        filters=z_dim,
        kernel_size=(n_bars - 1, 1),
        padding='valid',
        strides=(1, 1),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    output_layer = Reshape([n_bars, z_dim])(x)
    return Model(input_layer, output_layer) 

如图所示,时间模型首先将随机向量重塑为所需的维度,然后通过转置卷积层将其传递,以扩展输出向量,使其跨越指定小节的长度。

对于我们不需要小节间连续性的音轨,我们直接使用随机向量 z。在实践中,与节奏或节拍相关的信息涵盖了这些音轨。

时序生成器和直接随机向量的输出首先被连结在一起,以准备一个更大的协调向量。然后,这个向量作为输入传递给下面片段所示的小节生成器 G[bar]:

def build_bar_generator(z_dim, n_steps_per_bar, n_pitches, weight_init):
    input_layer = Input(shape=(z_dim * 4,), name='bar_generator_input')
    x = Dense(1024)(input_layer)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Reshape([2, 1, 512])(x)
    x = Conv2DTranspose(
        filters=512,
        kernel_size=(2, 1),
        padding='same',
        strides=(2, 1),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Conv2DTranspose(
        filters=256,
        kernel_size=(2, 1),
        padding='same',
        strides=(2, 1),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Conv2DTranspose(
        filters=256,
        kernel_size=(2, 1),
        padding='same',
        strides=(2, 1),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Conv2DTranspose(
        filters=256,
        kernel_size=(1, 7),
        padding='same',
        strides=(1, 7),
        kernel_initializer=weight_init
    )(x)
    x = BatchNormalization(momentum=0.9)(x)
    x = Activation('relu')(x)
    x = Conv2DTranspose(
        filters=1,
        kernel_size=(1, 12),
        padding='same',
        strides=(1, 12),
        kernel_initializer=weight_init
    )(x)
    x = Activation('tanh')(x)
    output_layer = Reshape([1, n_steps_per_bar, n_pitches, 1])(x)
    return Model(input_layer, output_layer) 
shows that the bar generator consists of a dense layer followed by batch-normalization, before a stack of transposed convolutional layers, which help to expand the vector along time and pitch dimensions.

评论者

评论者模型相对于我们在前一节中构建的生成器来说更简单。评论者基本上是一个卷积 WGAN-GP 模型(类似于 WGAN,在 第六章 使用 GAN 生成图像 中涵盖的),它从小节生成器的输出以及真实样本中获取信息,以检测生成器输出是伪造的还是真实的。以下片段呈现了评论者模型:

def build_critic(input_dim, weight_init, n_bars):
    critic_input = Input(shape=input_dim, name='critic_input')
    x = critic_input
    x = conv_3d(x,
                num_filters=128,
                kernel_size=(2, 1, 1),
                stride=(1, 1, 1),
                padding='valid',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=64,
                kernel_size=(n_bars - 1, 1, 1),
                stride=(1, 1, 1),
                padding='valid',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=64,
                kernel_size=(1, 1, 12),
                stride=(1, 1, 12),
                padding='same',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=64,
                kernel_size=(1, 1, 7),
                stride=(1, 1, 7),
                padding='same',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=64,
                kernel_size=(1, 2, 1),
                stride=(1, 2, 1),
                padding='same',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=64,
                kernel_size=(1, 2, 1),
                stride=(1, 2, 1),
                padding='same',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=128,
                kernel_size=(1, 4, 1),
                stride=(1, 2, 1),
                padding='same',
                weight_init=weight_init)
    x = conv_3d(x,
                num_filters=256,
                kernel_size=(1, 3, 1),
                stride=(1, 2, 1),
                padding='same',
                weight_init=weight_init)
    x = Flatten()(x)
    x = Dense(512, kernel_initializer=weight_init)(x)
    x = LeakyReLU()(x)
    critic_output = Dense(1,
                          activation=None,
                          kernel_initializer=weight_init)(x)
    critic = Model(critic_input, critic_output)
    return critic

一个需要注意的重点是使用 3D 卷积层。对于大多数任务,我们通常使用 2D 卷积。在这种情况下,由于我们有 4 维输入,需要使用 3D 卷积层来正确处理数据。

我们使用这些实用工具来为四个不同的音轨准备一个通用的生成器模型对象。在下一步中,我们准备训练设置并生成一些示例音乐。

训练和结果

所有组件都准备就绪。最后一步是将它们组合在一起,并按照典型 WGAN-GP 的训练方式进行训练。论文的作者提到,如果他们每更新 5 次鉴别器,就更新一次生成器,模型将达到稳定的性能。我们遵循类似的设置来实现 图 11.12 中显示的结果:


图 11.12:从 MuseGAN 设置中得到的结果展示了多轨输出,这在各个小节之间似乎是连贯的,并且具有一致的节奏。

如图所示,MuseGAN 产生的多轨多声部输出确实令人印象深刻。我们鼓励读者使用 MIDI 播放器(甚至是 MuseScore 本身)播放生成的音乐样本,以了解输出的复杂性及其相较于前几节中准备的简单模型的改进。

总结

恭喜你完成了另一个复杂的章节。在本章中,我们覆盖了相当多的内容,旨在建立对音乐作为数据源的理解,然后使用生成模型生成音乐的各种方法。

在本章的第一部分,我们简要讨论了音乐生成的两个组成部分,即乐谱表演生成。我们还涉及了与音乐生成相关的不同用例。下一部分集中讨论了音乐表示的不同方法。在高层次上,我们讨论了连续和离散的表示技术。我们主要关注1D 波形2D 频谱图作为音频或连续域中的主要表示形式。对于符号或离散表示,我们讨论了基于音符/和弦的乐谱。我们还使用music21库进行了一个快速的动手练习,将给定的 MIDI 文件转换成可读的乐谱。

当我们对音乐如何表示有了基本的了解后,我们开始构建音乐生成模型。我们首先研究的最简单方法是基于堆叠的 LSTM 架构。该模型利用注意力机制和符号表示来生成下一组音符。这个基于 LSTM 的模型帮助我们窥探了音乐生成的过程。

下一部分集中使用 GAN 设置来生成音乐。我们设计的 GAN 类似于 Mogren 等人提出的C-RNN-GAN。结果非常鼓舞人心,让我们深入了解了对抗网络如何被用于音乐生成任务。

在前两个动手练习中,我们将我们的音乐生成过程仅限于单声音乐,以保持简单。在本章的最后一节,我们的目标是理解生成复音轨/多轨音乐所需的复杂性和技术。我们详细讨论了* MUSEGAN*,这是 2017 年由 Dong 等人提出的基于 GAN 的复音轨/多轨音乐生成架构。Dong 和他的团队讨论了多轨相互依赖音乐纹理时间结构三个主要方面,这些方面应该由任何多轨音乐生成模型处理。他们提出了音乐生成的三种变体,即即兴演奏作曲家混合模型。他们还讨论了时间小节生成模型,以便更好地理解这些方面。MUSEGAN 论文将混音音乐生成模型作为这些更小组件/模型的复杂组合来处理多轨/复音轨音乐的生成。我们利用了这一理解来构建这项工作的简化版本,并生成了我们自己的复音轨音乐。

本章让我们进一步了解了可以使用生成模型处理的另一个领域。在下一章中,我们将升级并专注于令人兴奋的强化学习领域。使用 RL,我们也将构建一些很酷的应用程序。请继续关注。

参考

  1. Butcher, M. (2019 年 7 月 23 日). 看起来 TikTok 已经收购了英国创新音乐人工智能初创公司 Jukedeck。 TechCrunch. techcrunch.com/2019/07/23/it-looks-like-titok-has-acquired-jukedeck-a-pioneering-music-ai-uk-startup/
  2. Apple. (2021). GarageBand for Mac - Apple. www.apple.com/mac/garageband/
  3. Magenta. (未知发布日期) 使用机器学习创作音乐和艺术. magenta.tensorflow.org/
  4. Mogren, O. (2016). C-RNN-GAN:带对抗性训练的连续循环神经网络. NIPS 2016 年 12 月 10 日,在西班牙巴塞罗那举办的建设性机器学习研讨会(CML)。arxiv.org/abs/1611.09904
  5. Dong, H-W., Hsiao, W-Y., Yang, L-C., & Yang, Y-H. (2017). MuseGAN:用于符号音乐生成和伴奏的多轨序列生成对抗网络. 第 32 届 AAAI 人工智能会议(AAAI-18)。salu133445.github.io/musegan/pdf/musegan-aaai2018-paper.pdf
相关文章
|
1月前
|
存储 人工智能 开发工具
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
只需要通过向AI助理提问的方式输入您的需求,即可瞬间获得核心流程代码及参数,缩短学习路径、提升开发效率。
1432 4
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
|
6天前
|
人工智能 IDE 开发工具
Python AI 编程助手
Python AI 编程助手。
23 5
|
4天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
21 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
4天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
16 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
4天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
16 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
8天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
利用Python和TensorFlow构建简单神经网络进行图像分类
利用Python和TensorFlow构建简单神经网络进行图像分类
27 3
|
15天前
|
人工智能 C语言 Python
AI师傅+通义灵码=零基础小白上手python真·不是梦
作为一名不懂编程的设计师,我一直渴望掌握AI辅助设计。在快刀青衣的推荐下,我尝试了AI师傅和通义灵码,成功写出了第一个Python程序,并理解了编程的基本概念。通过AI师傅的引导和通义灵码的帮助,我顺利完成了Coursera上的Python课程,获得了两张证书。这种学习方式让编程变得不再遥不可及,为我的未来学习打开了新大门。
|
20天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
65 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
2月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
108 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
30天前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?