Python音频信号分类MFCC特征神经网络

4
我正在尝试将音频信号从语音分类到情感。为此,我提取音频信号的MFCC特征,并将其馈送到一个简单的神经网络(使用PyBrain中的BackpropTrainer训练的FeedForwardNetwork)。不幸的是,结果非常糟糕。在5个类别中,该网络似乎几乎总是得出相同的类别作为结果。
我有5个情感类别和大约7000个带标签的音频文件,我将它们分成了80%用于训练网络和20%用于测试网络。
想法是使用小窗口并从中提取MFCC特征以生成大量的训练示例。在评估过程中,对一个文件中的所有窗口进行评估,并通过多数表决来决定预测标签。
Training examples per class: 
{0: 81310, 1: 60809, 2: 58262, 3: 105907, 4: 73182}

Example of scaled MFCC features:
[ -6.03465056e-01   8.28665733e-01  -7.25728303e-01   2.88611116e-05
1.18677218e-02  -1.65316583e-01   5.67322809e-01  -4.92335095e-01   
3.29816126e-01  -2.52946780e-01  -2.26147779e-01   5.27210979e-01   
-7.36851560e-01]

Layers________________________:  13 20 5 (also tried 13 50 5 and 13 100 5)
Learning Rate_________________:  0.01 (also tried 0.1 and 0.3)
Training epochs_______________:  10  (error rate does not improve at all during training)

Truth table on test set:
[[   0.    4.    0.  239.   99.]
 [   0.   41.    0.  157.   23.]
 [   0.   18.    0.  173.   18.]
 [   0.   12.    0.  299.   59.]
 [   0.    0.    0.   85.  132.]]

Success rate overall [%]:  34.7314201619
Success rate Class 0 [%]:  0.0
Success rate Class 1 [%]:  18.5520361991
Success rate Class 2 [%]:  0.0
Success rate Class 3 [%]:  80.8108108108
Success rate Class 4 [%]:  60.8294930876

好的,现在你可以看到结果在各个类之间分布非常糟糕。0和2类从未被预测。我认为这暗示了我的网络或者更可能是我的数据存在问题。

我可以在这里发很多代码,但我认为更有意义的是展示下面的图片,展示我获取MFCC特征的所有步骤。请注意,为了说明,我使用整个信号而没有进行窗口处理。这看起来还好吗?MFCC值非常大,它们不应该小得多吗?(我将它们缩小到[-2,2]并使用minmaxscaler对所有数据进行归一化后再输入到网络中,也尝试过[0,1])

从信号到MFCC的步骤

这是我用于应用离散余弦变换从Melfilter bank提取MFCC特征的代码(我从这里获得:stackoverflow):

def freqToMel(freq):
  '''
  Calculate the Mel frequency for a given frequency 
  '''
  return 1127.01048 * math.log(1 + freq / 700.0)

def melToFreq(mel):
  '''
  Calculate the frequency for a given Mel frequency 
  '''
  return 700 * (math.exp(freq / 1127.01048 - 1))

def melFilterBank(blockSize):
  numBands = int(mfccFeatures)
  maxMel = int(freqToMel(maxHz))
  minMel = int(freqToMel(minHz))

  # Create a matrix for triangular filters, one row per filter
  filterMatrix = numpy.zeros((numBands, blockSize))

  melRange = numpy.array(xrange(numBands + 2))

  melCenterFilters = melRange * (maxMel - minMel) / (numBands + 1) + minMel

  # each array index represent the center of each triangular filter
  aux = numpy.log(1 + 1000.0 / 700.0) / 1000.0
  aux = (numpy.exp(melCenterFilters * aux) - 1) / 22050
  aux = 0.5 + 700 * blockSize * aux
  aux = numpy.floor(aux)  # Arredonda pra baixo
  centerIndex = numpy.array(aux, int)  # Get int values

  for i in xrange(numBands):
    start, centre, end = centerIndex[i:i + 3]
    k1 = numpy.float32(centre - start)
    k2 = numpy.float32(end - centre)
    up = (numpy.array(xrange(start, centre)) - start) / k1
    down = (end - numpy.array(xrange(centre, end))) / k2

    filterMatrix[i][start:centre] = up
    filterMatrix[i][centre:end] = down

  return filterMatrix.transpose()

我该如何获得更好的预测结果?


你在dsp.stackexchange.com上可能会有更好的运气。 - jaket
我能否以某种方式进行更改?我认为我也可以尝试在stats.stackexchange.com上咨询有关神经网络的问题... - cowhi
实际上,告诉我你是如何测试它们的,然后我们就可以找出你所犯的错误或代码中存在的任何问题,同时你使用的分类器也很重要。 - user7289160
非常抱歉,这已经是过去的事情了,我甚至没有代码了...那只是我上课时做的一个小项目。预测不起作用,所以我得出结论,在这种情况下,仅使用MFCC特征无法进行分类。但还是谢谢你的帮助! :) - cowhi
1个回答

3

这里我举了一个语音性别识别的例子。我使用了Hyke数据集1来进行示例展示。这只是一个快速制作的示例,如果想要进行严格的性别识别,可能会有更好的方法。但是总体上错误率在降低:

Build up data...
Train network...
Number of training patterns:  94956
Number of test patterns:      31651
Input and output dimensions:  13 2
Train network...
epoch:    0   train error: 62.24%   test error: 61.84%
epoch:    1   train error: 34.11%   test error: 34.25%
epoch:    2   train error: 31.11%   test error: 31.20%
epoch:    3   train error: 30.34%   test error: 30.22%
epoch:    4   train error: 30.76%   test error: 30.75%
epoch:    5   train error: 30.65%   test error: 30.72%
epoch:    6   train error: 30.81%   test error: 30.79%
epoch:    7   train error: 29.38%   test error: 29.45%
epoch:    8   train error: 31.92%   test error: 31.92%
epoch:    9   train error: 29.14%   test error: 29.23%

我使用了来自scikits.talkbox的MFCC实现。也许以下代码可以帮助你。(性别识别肯定比情感检测更容易... 也许你需要更多和不同的特征。)

import glob

from scipy.io.wavfile import read as wavread
from scikits.talkbox.features import mfcc

from pybrain.datasets            import ClassificationDataSet
from pybrain.utilities           import percentError
from pybrain.tools.shortcuts     import buildNetwork
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.structure.modules   import SoftmaxLayer

def report_error(trainer, trndata, tstdata):
    trnresult = percentError(trainer.testOnClassData(), trndata['class'])
    tstresult = percentError(trainer.testOnClassData(dataset=tstdata), tstdata['class'])
    print "epoch: %4d" % trainer.totalepochs, "  train error: %5.2f%%" % trnresult, "  test error: %5.2f%%" % tstresult  

def main(auido_path, coeffs=13):
    dataset = ClassificationDataSet(coeffs, 1, nb_classes=2, class_labels=['male', 'female'])
    male_files = glob.glob("%s/male_audio/*/*_1.wav" % auido_path)
    female_files = glob.glob("%s/female_audio/*/*_1.wav" % auido_path)

    print "Build up data..."
    for sex, files in enumerate([male_files, female_files]):
        for f in files:
            sr, signal = wavread(f)
            ceps, mspec, spec = mfcc(signal, nwin=2048, nfft=2048, fs=sr, nceps=coeffs)
            for i in range(ceps.shape[0]):
                dataset.appendLinked(ceps[i], [sex])

    tstdata, trndata = dataset.splitWithProportion(0.25)
    trndata._convertToOneOfMany()
    tstdata._convertToOneOfMany()

    print "Number of training patterns: ", len(trndata)
    print "Number of test patterns:     ", len(tstdata)
    print "Input and output dimensions: ", trndata.indim, trndata.outdim

    print "Train network..."
    fnn = buildNetwork(coeffs, int(coeffs*1.5), 2, outclass=SoftmaxLayer, fast=True)
    trainer = BackpropTrainer(fnn, dataset=trndata, learningrate=0.005)

    report_error(trainer, trndata, tstdata)
    for i in range(100):
        trainer.trainEpochs(1)
        report_error(trainer, trndata, tstdata)

if __name__ == '__main__':
    main("/path/to/hyke/audio_data")


1 Azarias Reda、Saurabh Panjwani和Edward Cutrell所著的论文《Hyke:面向发展中国家的低成本远程考勤跟踪系统》,发表于第5届ACM Networked Systems for Developing Regions (NSDR) 研讨会。


我已经转换到使用Talkbox了。现在MFCC值看起来好多了,但是我仍然得到奇怪的结果。当我开始训练网络时,误差值基本保持不变,有点下降、有点上升,没有一个明确的方向。我在10个epochs后的准确率只比一开始的69%好了一点,最好也只有66%左右。测试结果看起来好一些,但是大部分预测都在一个类别中。 - cowhi
2
从外部人的角度很难说。以下是一些想法(您可能已经自己考虑过...):1. 对于情绪检测,您的窗口大小应该足够大。 (1024个样本可能太短,无法展现情感)2. 也许您应该添加一些与能量和音高相关的音频特征。 3. 当然,还要调整网络参数(隐藏单元数量,学习率,最终动量)。 4. 如果所有这些都不起作用,请阅读一些有关情感检测的论文。 - Frank Zalkow
是的,你说得对,我尝试了大多数这些方法。不同的窗口大小和网络参数。此外,我丢弃了第一个特征,看看是否会改善结果,并尝试对特征进行标准化和归一化处理。但是没有什么明显的提高。唯一没做的就是添加更多的特征。但是,如果我做的都是正确的(我现在认为我做到了),那么这意味着MFCC特征本身就不适合这种分类。这是一个结果,我可以接受,也足够用来写报告。感谢你花时间考虑并提供反馈! - cowhi
不客气!您使用什么类型的数据集?它是公开可用的吗? - Frank Zalkow
我正在使用IEMOCAP数据集(http://sail.usc.edu/iemocap/index.html)。它不是公开的,但我已经询问过并收到了下载链接。我和我的教授交谈过,他认为我使用的情感子集可能太相关了,比如悲伤和沮丧,并且我对MFCC使用的窗口太窄了。尽管如此,我还没有验证这一点。 - cowhi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接