Kaldi特征提取之-VAD

Kaldi特征提取之-VAD

背景

  • VAD即 Voice Activity Detection, 用于检测静音和非静音。通过使用VAD,我们可以找到有效语音段,剔除静音段,在语音识别等过程中可以大大减少要处理的数据量。VAD通常有多种方法,简单的如帧能量或者帧幅度,复杂的还可以用神经网络。下图是一段语音的波形图,VAD可以将图中红色框内的地方剔除。

    Kaldi特征提取之-VAD_第1张图片

VAD检测

  • 注意:以下所有方法都以帧为单位进行,帧长度为N

  • 方法一: 帧幅度(绝对值和)
    这种方法计算最为简单,但是如果背景声音比较大,则效果会比较差,计算公式如下:

    amplitudesi=j=1N|framei(j)|
    Kaldi特征提取之-VAD_第2张图片
    对比上下两幅图可以看到一些规律,静音区对应的幅度较低,通过设置low_thres和high_thres 可以过滤掉一部分静音。

  • 方法二:帧能量(平方和)
    这种计算方法也比较简单,和方法一的性质基本一致,但是可以增大声音强度的对比度。计算公式如下:

    energyi=j=1Nframei(j)2
    Kaldi特征提取之-VAD_第3张图片
    对比中间和最下边的图,可以发现方法二加强了声音幅度的对比度。同样的,还是通过设置合理的low_thres和high_thres过滤掉一部分静音。

  • 方法三:短时过零率分析
    短时过零率表示一帧语音中语音信号波形穿过横轴(零电平)的次数。对于连续语音信号(模拟信号),过零意味着时域波形通过时间轴;对于离散信号(数字信号),相邻采样值改变符号即意味着过零,过零率就是样本符号改变的次数。计算公式如下:

    Zi=12j=2N|sgn(framei(j))sgn(framei(j1))|sgn
    Kaldi特征提取之-VAD_第4张图片从图中可以看出,过零率在没有噪声的位置表现良好,但是在有噪声的地方表现并不好,坑干扰能力比较差。

  • 方法四: 能量+滑动窗口(Kaldi)

    • 首先,需要说明的是,这里的能量是方法一或者方法二的计算结果,这里我们假设使用的是方法二计算。代码如下:

      void ComputeVadEnergy(const VadEnergyOptions &opts,
                        const MatrixBase &feats,
                        Vector *output_voiced) {
        int32 T = feats.NumRows();
        output_voiced->Resize(T);
        if (T == 0) {
          KALDI_WARN << "Empty features";
          return;
        }
        Vector log_energy(T);
        log_energy.CopyColFromMat(feats, 0); // column zero is log-energy.
      
        BaseFloat energy_threshold = opts.vad_energy_threshold;
        if (opts.vad_energy_mean_scale != 0.0) {
            KALDI_ASSERT(opts.vad_energy_mean_scale > 0.0);
            energy_threshold += opts.vad_energy_mean_scale * log_energy.Sum() / T;
        }
      
        KALDI_ASSERT(opts.vad_frames_context >= 0);
        KALDI_ASSERT(opts.vad_proportion_threshold > 0.0 &&
                 opts.vad_proportion_threshold < 1.0);
        for (int32 t = 0; t < T; t++) {
          const BaseFloat *log_energy_data = log_energy.Data();
          int32 num_count = 0, den_count = 0, context = opts.vad_frames_context;
          for (int32 t2 = t - context; t2 <= t + context; t2++) {
            if (t2 >= 0 && t2 < T) {
              den_count++;
              if (log_energy_data[t2] > energy_threshold)
                num_count++;
            }
          }
          if (num_count >= den_count * opts.vad_proportion_threshold)
            (*output_voiced)(t) = 1.0;
          else
            (*output_voiced)(t) = 0.0;
        }
      }  
      参数 意义
      vad_energy_threshold 能量阈值
      vad_energy_mean_scale 平均能量的放大(缩小)系数
      vad_frames_context 窗口长度的一半
      vad_proportion_threshold 窗口内超过阈值的帧数的比例

      效果如下图:
      Kaldi特征提取之-VAD_第5张图片

    • 与其他方法不同之处在于,kaldi利用了前后帧的关系,而不是孤立的单独考察每一帧。

  • 方法五 : 神经网络

    • 随着神经网络的兴起,也有些人开始用CNN、DNN做VAD。用神经网络的优点是:神经网络表达能力强大,具有良好的抗噪声能力,而且我们可以把识别范围外的所有其他都当做是Sil,当然这种情况下就不再是严格意义上的VAD;缺点是:计算量比较大,有点得不偿失的感觉。
  • 难点分析

    • 上面几种方法大都需要设置各种阈值,这是一个难点。阈值太小,过滤效果不明显;阈值太大,可能会过滤掉有效语音。实际使用中,通常阈值会设置的比较松,避免过滤掉有用信息。合理的阈值设置,需要考虑实际使用情况,用一个较大的数据集进行统计,得到一个合理的阈值。

资源

  • wav
  • matlab脚本

参考

  1. VAD
  2. 神经网络
  3. 过零率
  4. 语音信号处理,第三版,4.3节

你可能感兴趣的:(Kaldi)