如何使用神经网络弹奏出带情感的音乐?

开发 开发工具
神经网络在音乐方面的应用已经不是一个新鲜的话题了。在音频检索领域中,人们一直在尝试着用神经网络对一系列音乐元素进行建模。

神经网络在音乐方面的应用已经不是一个新鲜的话题了。在音频检索领域中,人们一直在尝试着用神经网络对一系列音乐元素进行建模 [1],例如和弦、音高等等。正如作者所提及的,人们在 1943 年开始用神经网络解决语音识别的问题。但是在那个年代,没有足够的计算能力来得到较好的结果,所以神经网络的方法在那个时候并不流行。而现在,由于 GPU 计算资源和可获得的大数据,结果可以变得相当好,于是作者就希望使用像图 1 中的神经网络来进行一个音乐实验,来实现音乐风格的神经转换。在这篇文章中,作者给出了非常详细的分析和什么会这样思考,本文也表明使用作者提出的方法,我们可以得到良好的结果。

深度神经网络

图 1. 深度神经网络

音乐和神经网络

谷歌的一个名为 Google Magenta[2] 的项目正在使用 AI 作曲家来产生开创性的结果,它使用神经网络来生成旋律。这证明了神经网络是成功的应用。其惊人的性能让作者认为神经网络还可以做一些有趣的音乐预测。

随后作者分析了音乐中的两个重要元素,音乐构成和音乐表现。音乐构成关注的是音乐本身,它的指的是能够定义一首歌曲的音符。如作者所说,你可以将它看作是图 2 中的乐谱。

一段乐谱图

图 2. 一段乐谱图

然而这对音乐家而言只是***步。这些乐谱如何被演奏家演奏,这才是音乐工作的灵魂。因为演奏者演奏者演奏得各不相同,所以我们用音乐风格来描述个人化的音乐演奏。

什么是音乐风格

音乐风格很难定义,因为不能把音乐风格像音高一样被参数化。如果你曾听过很多经典的钢琴曲,那么你会发现一个新手和一个资深的钢琴家会奏出大不相同的强弱力度(dynamics),这里指的是音乐响度的变化。一个音符的响度可以通过控制敲击琴键的轻重程度来实现。在音乐符号中这些不同级别的强弱力度一般用意大利字母表示。这些字母被称为情感符。不同的人会有不同的感觉,所以这里的特定的强弱集合都有着各自的情感表现。因此情感表现就意味着一组***的强弱力度,而强弱力度也就成了风格的重要特征。

乐谱中的强弱力度范围

图 3:乐谱中的强弱力度范围

此外,人们还用一些流派来标记音乐,例如经典音乐、爵士音乐等等。由此我们可以发现,在一些特定的音乐风格中是存在一些规则的,因此人们可以通过强弱力度来识别音乐风格。这也意味着人么可以用流派来归类音乐风格。

我们可以拿强弱力度来干什么?

在参考文献 [3,4,5] 中,他们在尝试着生成音乐构成的那一部分,但是并没有音乐表现的那一部分。所以作者在这篇文章中通过添加强弱信息使用乐器数字接口(MIDI)来像人一样演奏音乐。

是人还是机器人在演奏呢?

作者设计并训练模型来为活页乐谱合成强弱力度(dynamics)。作者展示了一种乐谱的两个不同的演奏,其中一个来自于人,另一个来自于机器。并进行了盲测,即看一看你能不能区分出哪一个是人演奏的,哪一个是机器演奏的。如作者提到的那样。只有不到一半的受试者能够正确地区分出来。我也听过这两种音乐,不幸的是,我能够很轻易地区分出来哪一个是人演奏的。因为由机器演奏的那一段中仍然存在很奇怪的强弱力度,并且我能够确保人类不会做出那样的演奏。即便如此,这个结果还是足以令人印象深刻了。

背景知识

1. 神经元

图 4 所示是神经网络中最基本的计算单元--神经元。

人工神经元

图 4. 人工神经元

输入与对应权重 w 的乘积和,然后再加上偏置单元 b。净输入可以通过方程 1 计算得到:

神经元的输出通过使用方程 2 所示的激活函数 g() 来计算:

Sigmoid 函数是最常用的激活函数。这个函数将任意实数作为输入,并将它们压缩在 0 到 1 之间。我们可以在图 5 中看到,一个很小的数字可以被替代成接近于 0 的结果,一个很大的数字可以被替代为接近于 1 的结果。其他常见的激活函数还有 Tanh 和 Relu。

sigmoid 激活函数

图 5. sigmoid 激活函数

2. 前馈神经网络

前馈神经网络(FNN)是最常用的结构。神经元逐层相连。***层是输入层,***一层是输出层。输入层和输出层之间是隐藏层。图 6 所示是一个只有一层隐藏层的前馈神经网络。在前馈神经网络中有一个假设:即每一个输入都是和其余输入相互独立。

前馈神经网络

前馈神经网络

3. 循环神经网络

一个简单的前馈神经网络的主要局限性是缺乏记忆。这是因为前馈神经网络假设输入之间是彼此独立的。但是在音乐中,乐谱是在全局结构下写成的,因为音乐家是基于他想要表达的某种情感来谱曲的,所以音符序列不能简单地认为音符序列是独立的。循环神经网络(RNN)可以解决这类问题。循环神经网络有状态(states),以及一个被称作循环权重的反馈回路。这个结构在计算当前输出的时候还利用了前一时刻的状态。这意味着循环神经网络有一个短期记忆机制来记住过去的计算结果,并将它用来计算当前的结果。图 7 展示了这个机制。

按时间展开的循环神经网络

图 7. 按时间展开的循环神经网络

4. 双向循环神经网络

音乐家有能力预测乐谱中的走向,这有助于对即将到来的情感符号做好准备。但是对于简单的循环神经网络而言,它是按顺序读取输入的。所以需要有一个能够访问即将到来时间步骤的神经网络。有一种叫做双向循环神经网络(Bi-Directional RNN)的结构。如图 8 所示,这个结构结合了两个循环神经网络层。

 双向循环神经网络

图 8. 双向循环神经网络

***层被称为前向层,它以原始的顺序读取输入。第二层叫做反向层,它以反向顺序读取输入。对于作者提出的目标而言,这个结构貌似是一个不错的选择。

5. 长短期记忆网络

根据参考文献 [7,8],循环神经网络***的问题就是它无法记住长期依赖的关系。为了解决这个问题,文献 [9] 中提出了长短期记忆网络(LSTM),为了控制类似于该记住多少,该遗忘多少的问题,LSTM 中提供了门控机制。

一个 LSTM 单元

图 9. 一个 LSTM 单元

架构设计

***我们开始设计整个系统的架构。作者在这篇文章中使用了双向-长短期记忆网络(Bi-Directional LSTM)。分别用两个网络实现对音乐流派和风格的分析,分别叫做 GenreNet 和 StyleNet。

1. GenreNet

流派具有可定义的音乐风格,所以作者使用这个特点来设计学习一首乐曲演奏强弱力度的基本模型。如图 10 所示,这个模型中有两个主要的层:双向 LSTM(Bi-Directional LSTM)和线性层。

GenreNet

图10. GenreNet

双向 LSTM 层结合了 LSTM 网络的优点,它对学习相关的依赖提供了记忆,双向结构还使得模型在学习的时候同时考虑了未来的信息。这使得模型的输出可以作为另一层网络的输入。线性层就是被用来把双向 LSTM 的输出值的范围从 [-1,1] 变得更大。

2. StyleNet

这个网络被用来学习一些在 Genre 网络上无法训练得到的更加复杂的风格信息。StyleNet 中有 GenreNet 的子网络,它们被用在 StyleNet 中来学习特定流派的风格。在 StyleNet 中,有一个解释层,它可以被 GenreNet 子网络共享。这大大减少了网络需要学习的参数。并且 StyleNet 就像是一个能够将音乐转换为不同风格的转换工具。如图 11 所示,这是一个多任务学习模型。

 StyleNet

图 11. StyleNet

3. 数据

作者在这篇文章中使用了 MIDI 格式的音乐文件,因为这种格式的文件包含了音乐属性。有一个叫做速率(velocity)的参数来存储强弱力度。它类似于音量,但是取值范围在 0~127 之间。作者在本文中用速率来检测强弱力度。

在本文中,作者创建了一个钢琴数据集。MIDI 文件的流派被限定在经典和爵士这两种里面。作者采用的 MIDI 文件全部来自于雅马哈钢琴电子竞赛。如图 12 所示,通常情况人类表演至少拥有 45 中不同的速率。作者将不同速率的数量的最小阈值设置为 20。

 左:下载到的 MIDI 文件中的速率的数量。右:表演 MIDI 文件中速率的数量

图 12. 左:下载到的 MIDI 文件中的速率的数量。右:表演 MIDI 文件中速率的数量

 

***,我们我们在这篇文章中选择了 4/4 拍,因为它是最常见的一种节拍,所以作者可以拥有比其他节拍更多的数据。

我们所用的数据集总共包含 349 个经典曲钢琴曲和爵士钢琴曲。

MIDI 编码方案

在得到了钢琴数据集之后,接下来的一部就是设计输入输出矩阵。

1. 量化

首先,数据集应该被量化,这使得作者能够拿矩阵来表征乐谱。但是但是这样做会导致一个结果,那就是我们会丢失乐谱相关的定时信息。文章中作者将乐谱的时间戳近似到了最接近的第 1/16 个音符。然后我们呢就可以捕获乐谱。图 13 展示了量化之前和量化之后的乐谱表征的不同。

量化

图 13. 量化

2. 输入矩阵表征

输入将会携带有关乐谱音高、开始时间以及结束时间等相关信息。乐谱总共有三个状态,所以作者使用二进制向量来表示这三个状态。「on」被编码为 [1,1],「sustained」被编码为 [0,1],「off」被编码为 [0,0]。

乐谱音高也需要被编码,我们会创建一个矩阵,其中***维是关于 MIDI 音高数量的值,第二维是关于 1/16 音符量化为时间步骤的值。这些在图 14 中可以看到。

输入输出表征

图 14. 输入输出表征

3. 输出矩阵的表征

输出矩阵携带着输入的速率。如图 14 所示,矩阵的列也表示音高,行表示时间步骤。音高维度只有 88 个音符,因为我们这次只需要表示速率。然后我们以***的速率 127 把数据进行分割,***输出速率被解码为一个 MIDI 文件。

训练

作者给出了训练网络的每一个细节过程。这里我仅仅向你们展示一些关键步骤。输入应该是 176 个节点的宽度和一层的深度。用 tensorflow 建立具有两个 GenreNet 单元的模型(经典和爵士)。每一个 GenreNet 有 3 层。使用 Mini-batch,大小为 4。将学习率设置为 0.001. 使用 Adam 优化器来进行随机优化。作者使用数据集中的 95% 来训练,剩下的 5% 来做验证。另外,在如图 15 所示的实验中,dropout rate 设置为 0.8。这样的 dropout rate 使模型能够学到潜在的模式。模型被训练了 160 个 epoch,最终的损失值和验证损失值分别为 0.0007 和 0.001。

训练误差和验证误差

在图 16 中,作者展示了训练误差和验证误差。

训练误差率和验证误差率

图 16. 训练误差率和验证误差率

作者还展示了很多训练过程的快照,所以我们可以在快照中发现经典音乐和爵士音乐的不同。图 17 是快照之一。

 训练过程的一次快照

图 17. 训练过程的一次快照

结果

测试结果的关键就是看看 StyleNet 是否能够生成像人一样的表演。作者在这里使用了图灵测试来测试结果 [11]。作者组织了一个叫做「鉴别人类演奏」的调查。这两部分总共有 9 个问题,如图 18 所示,参与者需要在 10 秒内听完一个音乐片段。

 [鉴别人类演奏] 测试

图 18. [鉴别人类演奏] 测试

在测试中参与者需要鉴别出人类的演奏。如图 19 所示,大约平均 53% 的参与者能够听出人类的演奏。

[鉴别人类的演奏] 测试结果

图 19. [鉴别人类的演奏] 测试结果

为了让这个调查更加完整,作者还添加了一项名为「不能确定」的选项来确保参与者不是在瞎蒙。如图 20 所示,这一次作者发现只有 46% 的人能够鉴别出人类的演奏。这意味着 StyleNet 模型能够通过图灵测试,它可以生成与人类并无区别的演奏。

最终鉴别测试结果

图 20. 最终鉴别测试结果

我学会演奏小提琴已经有 19 年了,所以我特别赞同作者关于音乐的两大元素的观点,也就是说,音乐构成和音乐表现。有时候表演会更加困难一些。在听完生成的演奏之后,我觉得 StyleNet 的表演的确是令人印象深刻的。我认为如果音符量化能够做的更小,例如 1/32 甚至 1/64,那么它有可能得到更好的结果。此外,我觉得其中的一项挑战就是你并不能确保 StyleNet 从人类的表演中学到了正确的风格。在作者提供的测试中,我能够正确地分辨出人类的演奏的原因就是仍然有一部分音符的细节并没被网络学习到,而这些细节正是我用来判断一段音乐是不是人类演奏的关键。我的建议是让音乐家去听 StyleNet 生成的音频,我相信他们能够给出一些专业的建议,然后这些专业的建议会帮助网络学习得更好。

我还想将作者提出的工作与计算机视觉中的风格变换 [12,13] 做一个对比。他们的基本方法是相似的:它们都是用了两个与风格对应的网络,其他的都用于内容。但是对于图像的风格转换,这两个网络的不同点是很大的(一个用于内容重建,另一个用于风格重建)。对于内容重建,它会通过计算不同子集的卷积神经网络捕捉不同尺寸的空间特征而生成,例如:conv1_1,[conv1_1, conv2_1],[conv1_1, conv2_1, conv3_1],[conv1_1, conv2_1, conv3_1,conv4_1],[conv1_1, conv2_1, conv3_1, conv4_1, conv5_1]。而在音乐的例子中,我认为使用 LSTM 生成音乐的主要思想就是捕捉音乐风格和音乐表现中的特征。总结一下:卷积神经网络是典型的空间深度神经网络,循环神经网络是典型的时间深度神经网络。在使用卷积神经网络的时候,我们应该关注空间映射,图像特别适合这个场景。然而对于音乐,我们需要对时间序列做分析,所以我们使用了循环神经网络。

【本文是51CTO专栏机构“机器之心”的原创文章,微信公众号“机器之心( id: almosthuman2014)”】

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2020-08-06 10:11:13

神经网络机器学习算法

2018-07-03 16:10:04

神经网络生物神经网络人工神经网络

2017-08-29 13:50:03

TensorFlow深度学习神经网络

2017-03-27 16:18:30

神经网络TensorFlow人工智能

2023-10-29 18:08:33

GPU神经网络CPU

2017-04-26 08:31:10

神经网络自然语言PyTorch

2023-05-12 14:58:50

Java神经网络深度学习

2017-09-28 16:15:12

神经网络训练多层

2018-08-13 09:00:00

人工智能机器学习神经网络

2017-04-26 09:30:53

卷积神经网络实战

2017-08-28 21:31:37

TensorFlow深度学习神经网络

2019-06-06 09:00:02

卷积神经网络CNNAI

2023-06-18 23:00:39

神经网络损失函数随机变量

2017-09-10 07:07:32

神经网络数据集可视化

2018-08-27 17:05:48

tensorflow神经网络图像处理

2017-01-10 17:25:59

深度学习框架神经网络

2018-02-05 08:58:36

Python神经网络识别图像

2017-09-08 13:30:32

深度学习图像识别卷积神经网络

2022-05-16 09:40:00

神经网络工具

2017-05-04 18:30:34

大数据卷积神经网络
点赞
收藏

51CTO技术栈公众号