问题的由来是飞鱼秀,一个我喜欢的广播节目,这是一个两人主持的音乐聊天类节目,大概形式是两人聊一会天,然后放一两首歌,然后继续聊天,以此重复。聊天很好笑,音乐很好听,可是我有一个奇怪的需求,那就是我想把穿插进行的聊天和音乐分开来,这样我就可以只听聊天或音乐了。具体而言就是要做一个分类工具,将一个聊天和音乐穿插进行的mp3文件分成两个mp3文件,一个只含音乐另一个只是聊天。这篇文章就来记录和分享下这个工具的制作过程,目前这个工具已经基本上可以满足需求了。

分析

这个问题的核心其实是一个分类问题,就是将一段音频分类为音乐类还是人声类,可以使用机器学习的技术来解决。定义好问题后,大概可以按照以下几步来解决它:

  1. 提取特征:找到一组合适的特征是解决好机器学习问题的前提,好的特征表示应该是同一类内的特征表示尽量相似,不同类间的特征表示尽量不同,这样才方便区分。
  2. 选取模型:对于同一个分类问题,可能有很多方法能够解决,选取一个又快又准的模型是很重要的。
  3. 训练模型:对于该问题,人可以给一些正确的分类样本来训练模型,有监督的分类比无监督的聚类应该能更好的解决该问题。
  4. 评价模型:当模型训练好后,我们就可以使用它了,看一下他对新来的样本的分类准确度,来评价下该模型,如果满足了需求那就解决了问题,否则就要继续重复整个过程来改进它。

行动

特征提取

首先就是特征提取,我现在有的是一个mp3的文件,我需要的是一个能表现声音特征的特征矩阵。调研得知声音的处理中常用的方法是Mel-frequency cepstral coefficients(MFCC),该方法能将一帧语音信号表示为一个12~20的向量。在Github上找到了该方法的python实现,借助这个包可以将wav格式的音频信号转化为一系列的特征向量。

这时候还要说下我利用到的另一个工具ffmpeg(A complete, cross-platform solution to record, convert and stream audio and video),借助这个工具可以将音频文件在mp3和wav格式之间相互转化。

至此,通过ffmpeg将mp3转化成wav,再使用mfcc方法就得到了该声音的特征矩阵了, 得到的特征矩阵的大小为n*13,其中n为帧数,13是每帧特征向量的长度。我们将前3个向量画出来:

mfcc

通过该图我们发现该段音频得到矩阵的振荡幅值是有所不同的,其中有3段的幅值较小,如下图所标注的。其实这3段正对应着原mp3中的人生部分,其它为音乐部分。

mfcc

通过观察我们已经发现了音乐和人声的不同,但是否能直接以此作为分类的依据呢。其实是不行的,因为我们看到的不同是结合一段音频发现的,对于其中的点来说,比如a点和b点,它们虽处于音乐段和人声段,但是单二者来看并无区别。因此我们需将一段时间的总体特征作为特征来加以利用,也就是加一个时间窗来总结时间窗内的信息得到新的特征。对于不同时间窗内的点,什么能够体现它们的不同呢?我们发现音乐和人声的均值并没有区别,只是幅值有区别,这时自然想到方差,通过计算方差来体现离散程度,来表示这种幅值的区别。下图是以1秒为时间窗计算方差后的结果。由此图可以看出,音乐和人声的区别更加明显。

modi.png

小结一下,特征的提取的方法如下:1)通过ffmpeg将mp3转化为wav格式 2)计算wav格式音频的mfcc,得到基础特征矩阵 3)通过加时间窗求方差的方法得到可以利用的特征矩阵。

模型选取

对于我们的问题,有监督的分类算法是比较合适的。下图可以辅助我们选取模型,通过实验证明,支持向量机是比较好的解决该问题的方法,因此本文选取支持向量机作为模型来解决分类问题。

ml_map.png

训练模型

我将已有的mp3文件,通过听的方式得到了音乐和人声的分类时间点,作为最初的训练样本,然后利用该样本作为训练集来训练我们的支持向量机。下图是人工给出的正确分类。

train_y.png

评价模型

利用训练好的模型,对于一个新的音频来预测它的分类,评价该模型的分类能力。下图是一个预测结果,由此图可知,该模型已经基本可以实现将二者分开的目标。

predict.png

其它

通过上面的方法,已经可以较为准确的将音乐和人声分类,但要将一个mp3文件分为两个分别包含音乐和人声的文件,还需要ffmpeg的帮助:对于一个mp3文件,我们将其在分类点处切割开,然后将同一类的文件连接成一个新的mp3文件。至此就完全实现的我的目标,文中所有的代码可以在github上找到。

结论

通过使用机器学习算法和声音信号处理技术,本文实现了声音文件中音乐和人声的自动分类,解决了自己的听电台节目时遇到的问题。另外也学习了声音处理相关的技术,还可以将文中的一些方法应用到更多的地方。