音乐分类其实很早就有人做了,这些天在kaggle上有个Million Song Dataset Challenge 非常火,上面有大量的数据可以让选手们通过底层,高层的和基于用户协作推荐的等等手段来对歌曲进行推荐. 这里我做的音乐声音分类是底层的, 而且我觉得一般的音乐文件要处理的东西太多了,节奏,速度什么的,在这里我只对4种乐器的声音进行分类: 钢琴,吉他,口琴,小提琴。
一般底层的声音,语音分类,speech recognition 使用无外乎Mel-frequency cepstrum 和 lpc analysis。 第二是个比较老的方法,而MFCC是我所用到的。可以把MFCCs对于好分类和识别的家伙们来说可以理解为对一段声音文件的descriptor,重点是这个descriptor非常discriminant. 在实验中,使用了matlab的voicebox里的melcepst函数,可以生成长度为12的数组,每个数组一般是一很小段声音的description,由于取样和设置的问题,MFCC所包含的声音长度是不一样的,在我的实验中,差不多连续1000个MFCC差不多是6秒钟的音频。 那4种声音来源分别是verycd上名家solo哈,不过要吐槽的是找了好多title是solo的,但是其实是是几种乐器和音的。每个类里取了6首左右的歌曲(20分钟左右)作为训练数据,提取出500k的MFCCs。
在实验中我使用了两个方法, 一种是在学校里老师讲的”常规”方法, 还有一种是用于图像分类的。总觉得在做底层分类的时候,图像识别和声音识别的步骤是差不多的。
- Binary-split, SVM
- Naive Bayes Nearest Neighbor
Binary-split + SVM
500k+的数据直接用来使用的话那就太夸张了,Binary-split+SVM这方法简单的来说是通过binary-split把500k的MFCC压缩成1000到2000个clusters,通过binary-split类似的数据会在一个小组里面。这种clustering算法里最有名的是k-means,不过k-means 速度实在是太悲剧了,虽然压缩损耗度要比binary-split少一些。
通过binary-split数据给压缩到少许clusters里,这所有的clusters其实就是所谓的codebook。codebook在通讯里面非常用,往往在数据通讯里,特别是声音传输中,需要用到codebook把传输数据进行压缩,在接受点的那一端,通过decode来还原原始数据。像一般的手机通讯就是用到这个概念,所以说很多时候人们发现电话里的声音总不是特别像某个人,原因就是因为声音信息在传输的时候多少给损耗掉了。在实验中,每个声音段(通常是1000个MFCCs也就是6秒左右的声音)用codebook可以生成一个一个histogram: 把每个MFCC在binary-split树里跑一下,找到最相近的cluster,通过统计所有cluster里一个声音段落里不同的MFCCs所出现的次数来生成Histogram。
每个声音段所产生的histrogram就是所要用到用来训练SVM的数据。这里的svm是one-vs-all,所以说将有4个svm会训练出来,每个svm会应对每个类,而每个svm会长生出一个概率值,是只一个声音段是它所对应类的可能性。在测试中往往选取最高的可能性作为音频的class。
在测试中,以上的步骤都差不多,只是,不需要生成codebook,直接使用了就可以。这里要说的是,测试的音频长度不一定需要和训练的音频长度一样,只要每次生成的histogram是归一化的就行了。
Piano| | Guitar| | Violin| | Harmonica| | |||||
---|---|---|---|---|---|---|---|---|
Piano| | 16 | 8 | 0 | 0 | ||||
Guitar| | 4 | 12 | 20 | 4 | ||||
Violin| | 0 | 0 | 20 | 4 | ||||
Harmonica| | 0 | 0 | 0 | 16 |
测试的时候每个类有20个case,从结果上来看,钢琴和吉他的识别不是很高,而且他们彼此有着很高互指。其实很大的原因是:当我们用codebook的时候,会对数据进行压缩,很多时候这个压缩会让比较discriminant的数据丢失。在这个实验中,钢琴和吉他的声音是比较相似的。
上面这个图是个histogram的分布图,通过随机选取每个类里的某一个训练的音频段生成的分布图,从途中可以看出,实际上通过codebook之后,吉他和钢琴的数据分布是非常耦合和相似的。所以,实验中对钢琴和吉他的分别度不高也有了依据。
Naive Bayes Nearest Neighbor(NBNN)
实际上,在图像识别中,很多时候也是运用到了上面所讲的方法,通过codebook对图像所提取的key-points进行clusterization,之后通过第二层的分类器把codebook产出的histogram数组进行分类。所以我觉得NBNN应该也能运用到声音分类中来。 NBNN是最近以篇叫In Defense of Nearest-Neighbor Based Image Classification的论文中看到的,该论文着重指出,codebook对数据损耗在无训练模型中的影响。 NBNN就是无训练模型(也叫no parametric?), 优点就是不需要训练。。。还有一个优点是在分类里,NBNN用的是image-class距离,而不是image-image距离,这样的话,intravariance很高的类对它的影响不大。
在论文中如果我们使用的邻近邻居是1的话,算法简化成以下:
- Compute MFCCs of the query audio
- compute the NN of in :
还有一点要说的是,在寻找最近邻居的时候,计算需求是相当高的,在原文里,作者用的是kd-tree,这样的能很快的找到最近的邻居。在这个实验的时候我用的scipy里kd-tree效率非常慢,后来才发现原来原作者是用的approximate kd-tree.
这个算法虽然简单,但是结果是惊人的不错: 使用所有的训练数据里的mfcc,每个测试音频有2000个MFCC,测试过程相当慢(好几个小时,如果使用approximate kd-tree的话应该能快好几个数量级)
Piano| | Guitar| | Violin| | Harmonica| | |||||
---|---|---|---|---|---|---|---|---|
Piano| | 20 | 0 | 0 | 0 | ||||
Guitar| | 0 | 20 | 1 | 0 | ||||
Violin| | 0 | 0 | 19 | 0 | ||||
Harmonica| | 0 | 0 | 0 | 20 |
从数据集里随机在每个类中获取500个MFCC,每个音频400个MFCC
Piano| | Guitar| | Violin| | Harmonica| | |||||
---|---|---|---|---|---|---|---|---|
Piano| | 20 | 0 | 0 | 0 | ||||
Guitar| | 0 | 20 | 3 | 0 | ||||
Violin| | 0 | 0 | 17 | 0 | ||||
Harmonica| | 0 | 0 | 0 | 20 |
最后是从每个类的训练数据中随机抽取30个MFCCs,每200个MFCC做音频测试数据的长度,测试数据是每个类40个,总使用的时间几秒而已
Piano| | Guitar| | Violin| | Harmonica| | |||||
---|---|---|---|---|---|---|---|---|
Piano| | 35 | 5 | 2 | 0 | ||||
Guitar| | 4 | 35 | 1 | 0 | ||||
Violin| | 1 | 0 | 37 | 0 | ||||
Harmonica| | 0 | 0 | 0 | 20 |
结果很显然易见,NBNN在声音分类方面还是很厉害的。更证明了声音分类和图像分类的相似之处。
以后有时间的话,可以试试以下的东西:
- 可以在NBNN里不随机选取MFCC,而是选取更有代表性的
- 使用 approximate kd-tree
- 用图像分类里的 random forest算法试试看
最后,感谢电驴,感谢python,感谢scipy,感谢voicebox 让哥在3天里搞定大作业。感谢尼玛操蛋的htk,要不是因为htk(本来好想做也语音编程系统的的)出不来结果我也不会换做这个来当speech recognition的大作业。