Kaldi特征提取之-VAD
背景
VAD即 Voice Activity Detection, 用于检测静音和非静音。通过使用VAD,我们可以找到有效语音段,剔除静音段,在语音识别等过程中可以大大减少要处理的数据量。VAD通常有多种方法,简单的如帧能量或者帧幅度,复杂的还可以用神经网络。下图是一段语音的波形图,VAD可以将图中红色框内的地方剔除。
VAD检测
注意:以下所有方法都以帧为单位进行,帧长度为N。
方法一: 帧幅度(绝对值和)
这种方法计算最为简单,但是如果背景声音比较大,则效果会比较差,计算公式如下:
amplitudesi=∑j=1N|framei(j)|
对比上下两幅图可以看到一些规律,静音区对应的幅度较低,通过设置low_thres和high_thres 可以过滤掉一部分静音。方法二:帧能量(平方和)
这种计算方法也比较简单,和方法一的性质基本一致,但是可以增大声音强度的对比度。计算公式如下:
energyi=∑j=1Nframei(j)2
对比中间和最下边的图,可以发现方法二加强了声音幅度的对比度。同样的,还是通过设置合理的low_thres和high_thres过滤掉一部分静音。方法三:短时过零率分析
短时过零率表示一帧语音中语音信号波形穿过横轴(零电平)的次数。对于连续语音信号(模拟信号),过零意味着时域波形通过时间轴;对于离散信号(数字信号),相邻采样值改变符号即意味着过零,过零率就是样本符号改变的次数。计算公式如下:
Zi=12∑j=2N|sgn(framei(j))−sgn(framei(j−1))|,其中sgn为符号函数从图中可以看出,过零率在没有噪声的位置表现良好,但是在有噪声的地方表现并不好,坑干扰能力比较差。方法四: 能量+滑动窗口(Kaldi)
首先,需要说明的是,这里的能量是方法一或者方法二的计算结果,这里我们假设使用的是方法二计算。代码如下:
void ComputeVadEnergy(const VadEnergyOptions &opts, const MatrixBase<BaseFloat> &feats, Vector<BaseFloat> *output_voiced) { int32 T = feats.NumRows(); output_voiced->Resize(T); if (T == 0) { KALDI_WARN << "Empty features"; return; } Vector<BaseFloat> 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利用了前后帧的关系,而不是孤立的单独考察每一帧。
方法五 : 神经网络
- 随着神经网络的兴起,也有些人开始用CNN、DNN做VAD。用神经网络的优点是:神经网络表达能力强大,具有良好的抗噪声能力,而且我们可以把识别范围外的所有其他都当做是Sil,当然这种情况下就不再是严格意义上的VAD;缺点是:计算量比较大,有点得不偿失的感觉。
难点分析
- 上面几种方法大都需要设置各种阈值,这是一个难点。阈值太小,过滤效果不明显;阈值太大,可能会过滤掉有效语音。实际使用中,通常阈值会设置的比较松,避免过滤掉有用信息。合理的阈值设置,需要考虑实际使用情况,用一个较大的数据集进行统计,得到一个合理的阈值。