Kaldi特征提取之-MFCC

来源:互联网 发布:叶部长 工资 知乎 编辑:程序博客网 时间:2024/06/05 17:51

Kaldi特征提取之-MFCC

背景

  • 上一节介绍的FBank特征已经很贴近人耳的响应特性,但是仍有一些不足:FBank特征相邻的特征高度相关(相邻滤波器组有重叠),因此当我们用HMM对音素建模的时候,几乎总需要首先进行倒谱转换,通过这样得到MFCC特征。

提取MFCC特征

  • MFCC特征的提取是在FBank特征的基础上再进行离散余弦变换, 因此前面几步和FBank一样,具体请参考上一节.

    1. 傅里叶变换
    2. 计算能量谱
    3. Mel滤波
    4. 取Log
    5. 离散余弦变换

      • 假设做完取Log之后,我们得到N维的特征向量Mlog。离散余弦变换公式如下:
        Ci=2Nj=1Nmjcos(piiN(j0.5)),i[1,M]
        N是取Log之后的特征维度,M 是 DCT(离散余弦变换)之后的特征维度。
      • 关于离散余弦变换,可以用matlab脚本看一下效果。
      • 关于离散余弦的实现。从计算公式可以看出DCT的时间复杂度为O(N*M),如果每次都重新计算DCT table无疑是得不偿失的,Kaldi中的做法是首先根据N和M的值计算出整个table,之后调用blas线性代数库,可以加快计算速度。相比之下,Htk中每次都要重新计算cos函数就显得性能比较低。以下是Htk和Kaldi的代码。
        // Htk implementvoid FBank2MFCC(Vector fbank, Vector c, int n){   int j,k,numChan;   float mfnorm,pi_factor,x;   numChan = VectorSize(fbank);   mfnorm = sqrt(2.0/(float)numChan);   pi_factor = PI/(float)numChan;   for (j=1; j<=n; j++)  {      c[j] = 0.0; x = (float)j * pi_factor;      for (k=1; k<=numChan; k++)         c[j] += fbank[k] * cos(x*(k-0.5));      c[j] *= mfnorm;   }        }// Kaldi implementtemplate<typename Real> void ComputeDctMatrix(Matrix<Real> *M) {  //KALDI_ASSERT(M->NumRows() == M->NumCols());  MatrixIndexT K = M->NumRows();  MatrixIndexT N = M->NumCols();  KALDI_ASSERT(K > 0);  KALDI_ASSERT(N > 0);  Real normalizer = std::sqrt(1.0 / static_cast<Real>(N));  // normalizer for  // X_0.  for (MatrixIndexT j = 0; j < N; j++) (*M)(0, j) = normalizer;  normalizer = std::sqrt(2.0 / static_cast<Real>(N));  // normalizer for other   // elements.  for (MatrixIndexT k = 1; k < K; k++)    for (MatrixIndexT n = 0; n < N; n++)      (*M)(k, n) = normalizer          * std::cos( static_cast<double>(M_PI)/N * (n + 0.5) * k );}// 底层调用的blas库函数void VectorBase<Real>::AddMatVec(const Real alpha,                              const MatrixBase<Real> &M,                              MatrixTransposeType trans,                              const VectorBase<Real> &v,                              const Real beta) {  KALDI_ASSERT((trans == kNoTrans && M.NumCols() == v.dim_ && M.NumRows() == dim_)           || (trans == kTrans && M.NumRows() == v.dim_ && M.NumCols() == dim_));  KALDI_ASSERT(&v != this);  cblas_Xgemv(trans, M.NumRows(), M.NumCols(), alpha, M.Data(), M.Stride(),              v.Data(), 1, beta, data_, 1);}
    6. 均值方差归一化(CMVN)

      • 实际情况下,受不同麦克风及音频通道的影响,会导致相同音素的特征差别比较大,通过CMVN可以得到均值为0,方差为1的标准特征。均值方差可以以一段语音为单位计算,但更好的是在一个较大的数据及上进行计算,这样识别效果会更加robustness。Kaldi中计算均值和方差的代码在compute-cmvn-stats.cc, 归一化在apply-cmvn.cc。
    7. FBank与MFCC对比

      • 计算量,因为MFCC是在FBank的基础上进行的,所以MFCC的计算量更大
      • 特征区分度,FBank特征相关性较高,MFCC具有更好的判别度,这也是在大多数语音识别论文中用的是MFCC,而不是FBank

资料

  1. wav
  2. mfcc matlab代码
  3. dct matlab代码

参考

  1. Kaldi
  2. htkbook 3.4.1 Chapter 5.6
  3. CMVN
  4. Fbank
原创粉丝点击