【干货】用神经网络识别歌曲流派(附代码)

作者:Navdeep Singh

编译:肖琴

【新智元导读】本文手把手教你如何构建一个能够识别歌曲类型的神经网络。

DataSet: 本文使用GTZAN Genre Collection音乐数据集,地址:[1]

这个数据集包含1000首不同的歌曲,分布在10种不同流派,每个流派100首,每首歌曲大约30秒。

使用的库:Python库librosa,用于从歌曲中提取特征,并使用梅尔频率倒谱系数( Mel-frequency cepstral coefficients ,MFCC)。

MFCC数值模仿人类的听觉,在语音识别和音乐类型检测中有广泛的应用。MFCC值将被直接输入神经网络。

了解MFCC

让我们用两个例子来说明MFCC。请通过Stereo Surgeon下载Kick Loop 5[2]和Whistling[3]。其中一个是低音鼓声,另一个是高音口哨声。它们明显不同,你可以看到它们的MFCC数值是不同的。

让我们转到代码(本文的所有代码文件都可以在Github链接中找到)。

以下是你需要导入的内容列表:

  • librosalibrary
  • glob,你需要列出不同类型目录中的文件
  • numpy
  • matplotlib,绘制MFCC graphs
  • Keras的序列模型,一种典型的前馈神经网络
  • 密集的神经网络层,即有很多神经元的层。

例如,与卷积不同的是,它具有2D表示。你必须使用import activation,它允许你为每个神经元层提供一个激活函数,以及to_categorical,它允许你把类的名称转换成诸如摇滚(rock),迪斯科(disco)等等,称为one-hot 编码, 如下所示:

这样,你已经正式开发了一个辅助函数来显示MFCC的值

首先,加载歌曲,然后从中提取MFCC值。然后,使用specshow,这是librosa库里的频谱图。

这是踏板鼓:

Low frequency: Kick loop 5

可以看到,在低频率下,低音是非常明显的。没有多少其他频率被表示。但是,口哨声的频谱图明显有更高的频率表示:

High frequency: Whistling

颜色越深或越接近红色,在那个频率范围内的能量越大。

限定歌曲流派

你甚至可以看到口哨声的频率的变化。下面是是disco曲的频率:

Song type/genre: Disco

下面是频率输出:

Disco Songs

你可以在前面的输出中看到节拍,但由于它们只有30秒长,因此很难看到单个的节拍。将它与古典乐相比较,会发现古典音乐没有那么多的节拍,而是有连续的低音线,比如下面是来自大提琴的低音线:

Song genre: Classical

下面是嘻哈音乐(hip-hop)的频率:

Song genre: HipHop

HipHop songs

它看起来有点像disco,分辨它们之间的细微区别是神经网络的问题。

这里还有另一个辅助函数,它只加载MFCC值,但这次你是正在为神经网络做准备:

同时加载的是歌曲的MFCC值,但由于这些值可能在-250到+150之间,它们对神经网络没有什么好处。你需要输入接近-1到+1或0到1的值。

因此,需要计算出每首歌曲的最大值和绝对值。然后将所有值除以最大值。此外,歌曲的长度略有不同,因此只需要选择25000个MFCC值。你必须非常确定你输入神经网络的东西的大小总是相同,因为只有那么多的输入神经元,一旦搭建好网络就无法改变了。

限定歌曲以获得MFCC值和流派名称

接下来,有一个名为generate _features_and_labels的函数,它将遍历所有不同的流派,并遍历数据集中的所有歌曲,然后生成MFCC值和流派名:

如上面的截图所示,准备一个所有特征和标签的列表。遍历全部10种流派。对于每种流派,请查看该文件夹中的文件。'generes /'+ genre +'/ *。au'文件夹显示数据集的组织方式。

处理这个文件夹时,每个文件会有100首歌曲; 你可以提取特征并将这些特征放在all_features.append(features)列表中。那首歌曲的流派名称也需要列在一个列表中。因此,最终,所有features将包含1000个条目,所有标签也将包含1000个条目。在所有feature的情况下,这1000个条目中的每一个都将有25000个条目。这是一个1000 x 25000矩阵。

对于目前的所有标签,有一个1000 entry的列表,里面是蓝调、古典、乡村、迪斯科、嘻哈、爵士、金属、流行、雷鬼和摇滚等等词汇。这就成问题了,因为神经网络不会预测单词或预测字母。你需要给它一个one-hot编码,这意味着这里的每个单词都将被表示为十个二进制数。

  • 蓝调(blues)的情况下,它是1后面跟着9个0。
  • 古典(classical)的情况是,是0后面跟着1,再跟着9个0。以此类推。首先,通过np.unique(all_labels, return_inverse=True) 命令将它们作为整数返回来计算所有唯一的名称。然后,使用to_categorical,将这些整数转换为one-hot编码。

那么,返回的是1000x10维。因为有1000首歌曲,每个歌曲都有10个二进制数字来表示单热编码。然后,通过命令return np.stack(all_features)返回堆叠在一起的所有特征,onehot_labels到单个矩阵,以及one-hot矩阵。因此,调用上层函数并保存特征和标签:

为了确保正确,请打印如下面的截图所示的特性和标签的形状。特性是1000×25000,标签是1000×10。现在,将数据集拆分为一个列并测试拆分。将80%的标记定义为training_split= 0.8,以执行拆分:

接下来,构建神经网络:

你会得到一个序列神经网络。第一层是100个神经元的dense layer。在第一层,你需要给出输入尺寸或输入形状,在这个例子里,就是25000。

这表示每个示例有多少输入值。25000将连接到第一层中的100。

第一层将对其输入,权重和偏差项进行加权求和,然后运行relu激活函数。relu表示任何小于0的都会变成0,任何高于0的都是值本身。

然后,这100个将连接到另外10个,就是输出层。之所以是10,是因为你已经完成了one-hot编码并且在编码中有10个二进制数。

代码中使用的激活softmax告诉你取10的输出并对它们进行规范化,使它们加起来为1。这样,它们最终成为了概率。现在考虑10个中的得分最高或概率最高的作为预测。这将直接对应于最高数字位置。例如,如果它在位置4,那么它就是disco。

接下来,编译模型,选择Adam等优化器,并定义损失函数。由于你有多个输出,你可能希望进行分类交叉熵和度量准确性,以便除了始终显示的损失之外,还可以在评估期间看到准确度。但是,准确度更有意义。接下来,打印model.summary,它会告诉你有关层的详细信息。它看起来是这样的:

第一个100神经元的层的输出形状肯定是100个值,因为有100个神经元,而密集的第二层的输出是10,因为有10个神经元。那么,为什么第一层有250万个参数或权重?这是因为你有25000个输入。

你有25000个输入,每个输入都会进入100个密集神经元中的一个。因此,也就是250万个,然后加上100,因为100个个神经元中每个都有自己的bias term,它自身的偏差权重也需要学习。

你有大约250万个参数或权重。接下来,运行拟合。这需要训练输入和训练标签,并获取你想要的epochs数量。你想要10,所以在经过训练的输入上重复10次。它需要一个batch size来告诉你这个数字,在这种情况下,歌曲在更新权重之前要遍历;并且validation_split是0.2,表示要接受20%的训练输入,将其拆分出来,实际上并没有对其进行训练,并用它来评估每个epoch之后它的表现如何。实际上从来没有训练验证拆分,但验证拆分可让你随时查看进度。

最后,因为你提前将训练和测试分开了,所以对测试、测试数据进行评估,并打印出测试数据的损失和准确度。以下是训练结果:

它边运行边打印,并始终打印损失和准确性。这是在训练集本身,而不是验证集上,所以这应该非常接近1.0。你可能不希望它接近1.0,因为这可能代表过拟合,但是如果你让它持续足够长时间,通常会在训练集上达到1.0的精度,因为它会记住训练集。

你真正关心的是验证的准确度,这就需要使用测试集。测试集是以前从未见过的数据,至少不是用于训练的数据。最终的准确性取决于你提前分离的测试数据。现在你的准确度大约为53%。这看起来比较低,但要知道有10种不同的流派。随机猜测的准确率是10%,所以这比随机猜测要好很多。

[1]marsyasweb.appspot.com/download/data_sets/.GTZAN Genre Collection

[2]https://freesound.org/people/Stereo Surgeon/sounds/266093/

[3]https://freesound.org/people/grrlrighter/sounds/98195/

原文:

https://medium.com/@navdeepsingh_2336/identifying-the-genre-of-a-song-with-neural-networks-851db89c42f0

原文发布于微信公众号 - 新智元(AI_era)

原文发表时间:2018-10-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据文摘

有这5小段代码在手,轻松实现数据可视化(Python+Matplotlib)

2636
来自专栏AI研习社

自定义损失函数Gradient Boosting

互联网上有很多关于梯度提升的很好的解释(我们在参考资料中分享了一些选择的链接),但是我们注意到很少有人提起自定义损失函数的信息:为什么要自定义损失函数,何时需要...

1.8K3
来自专栏人工智能LeadAI

C++实现神经网络之一 | Net类的设计和神经网络的初始化

闲言少叙,直接开始 既然是要用C++来实现,那么我们自然而然的想到设计一个神经网络类来表示神经网络,这里我称之为Net类。由于这个类名太过普遍,很有可能跟其他人...

3255
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

局部自适应自动色阶/对比度算法在图像增强上的应用。

    在限制对比度自适应直方图均衡化算法原理、实现及效果一文中针对全局直方图均衡化的一些缺点,提出了分块的自适应均衡化技术,很好的克服了全局直方图均衡化的一些...

6049
来自专栏技术翻译

Scikit-Learn: 机器学习的灵丹妙药

Scikit-Learn是python的核心机器学习包,它拥有支持基本机器学习项目所需的大部分模块。该库为从业者提供了一个统一的API(ApplicationP...

2811
来自专栏CSDN技术头条

LSTM实现详解

前言 在很长一段时间里,我一直忙于寻找一个实现LSTM网络的好教程。它们似乎很复杂,而且在此之前我从来没有使用它们做过任何东西。在互联网上快速搜索并没有什么帮助...

2279
来自专栏深度学习那些事儿

A trap of parameter 'size_average' in pytorch

上面的程序很简单,设定一个loss函数,然后设定一个input和target进行loss计算,然后再backward。

1373
来自专栏小鹏的专栏

机器学习进阶系列

本文为博主原创文章,未经博主允许不得转载。有问题可以加微信:lp9628(注明CSDN)。

3167
来自专栏奇点大数据

Pytorch神器(3)

上次我们的连载讲到用最简便的方法,也就是pip方法安装Pytorch。大家都成功了吧。

1241
来自专栏机器之心

教程 | 一步一步,看图理解长短期记忆网络与门控循环网络

循环神经网络(RNN)很大程度上会受到短期记忆的影响,如果序列足够长,它们将很难将信息从早期时间步传递到靠后的时间步。因此,如果你试图处理一段文字来做预测,RN...

1123

扫码关注云+社区

领取腾讯云代金券