说话人识别中的VAD

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

本文根据kaldi中的vad的算法 kaldi/src/ivector/voice-activity-detection.cc以及网上的一些资源来总结一下这个知识点。

首先VAD的全称是:Voice Activity Detection (语音激活检测), 能够区分传输语音信号中的语音信号和背景噪音, 当然还能在通信中区分语音和静默段能够区分传输语音信号中的语音信号和背景噪音,

避免带宽资源的浪费,这里我们只讨论在说话人识别中需要区分背景噪音来构建UBM模型。

下面直接看kaldi的源码,注意看注释

run.sh中调用下面computer_vad_decision.sh

Usage: $0 [options] <data-dir> <log-dir> <path-to-vad-dir>

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. sid/compute_vad_decision.sh --nj 40 --cmd "$train_cmd" \  
  2.     data/train exp/make_vad $vaddir  
computer_vad_decision.sh调用的是

Usage: compute-vad [options] <feats-rspecifier> <vad-wspecifier>

输入的是每一个feats文件,由于上边的nj是40,所以这JOB: 1~40, 输入mfcc.ark 输出vad.ark

compute-vad --config=$vad_config scp:$sdata/JOB/feats.scp ark,scp:$vaddir/vad_${name}.JOB.ark,$vaddir/vad_${name}.JOB.scp

computer-vad是  kaldi/src/ivectorbin/compute-vad.cc
下面是 computer-vad.cc中的逻辑:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. for (;!feat_reader.Done(); feat_reader.Next()) {  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #读取每一句话  
  2. std::string utt = feat_reader.Key();  
  3. Matrix<BaseFloat> feat(feat_reader.Value());  
  4. if (feat.NumRows() == 0) {  
  5.   KALDI_WARN << "Empty feature matrix for utterance " << utt;  
  6.   num_err++;  
  7.   continue;  
  8. }  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.   #声明一个vector, 维数 = 一句话的帧数  
  2.   Vector<BaseFloat> vad_result(feat.NumRows());  
  3.   #然后是计算vad,一个可选参数集合,mfcc的matrix, 返回的结果vertor, 看下一个的源码片段  
  4.   ComputeVadEnergy(opts, feat, &vad_result);  
  5.     
  6.   double sum = vad_result.Sum();  
  7.   if (sum == 0.0) {  
  8.     KALDI_WARN << "No frames were judged voiced for utterance " << utt;  
  9.     num_unvoiced++;  
  10.   } else {  
  11.     num_done++;  
  12.   }  
  13.   tot_decision += vad_result.Sum();  
  14.   tot_length += vad_result.Dim();  
  15.   
  16.   if (!(omit_unvoiced_utts && sum == 0)) {  
  17.     vad_writer.Write(utt, vad_result);  
  18.   }  
  19. }  

下面这个是计算vad结果的函数:  kaldi / src / ivector / voice-activity-detection.cc

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include "ivector/voice-activity-detection.h"  
  2. #include "matrix/matrix-functions.h"  
  3.   
  4.   
  5. namespace kaldi {  
  6.   
  7. void ComputeVadEnergy(const VadEnergyOptions &opts,  
  8.                       const MatrixBase<BaseFloat> &feats,  
  9.                       Vector<BaseFloat> *output_voiced) {  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #feats是mfcc的特征矩阵  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int32 T = feats.NumRows();  
  2. output_voiced->Resize(T);  
  3. if (T == 0) {  
  4.   KALDI_WARN << "Empty features";  
  5.   return;  
  6. }  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #定义一个维度为T的vector  
  2. Vector<BaseFloat> log_energy(T);  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #激昂feats的第0列as log_energy的value  
  2. log_energy.CopyColFromMat(feats, 0); // column zero is log-energy.  
  3. #读取配置文件中的噪声的阈值: <span style="font-family: Menlo; font-size: 11px;">--vad-energy-threshold=5.5, 若小于这个值则为噪音,若大于则为语音信号  
  4. BaseFloat energy_threshold = opts.vad_energy_threshold;  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #读取配置文件中:  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.  if (opts.vad_energy_mean_scale != 0.0) {  
  2.     KALDI_ASSERT(opts.vad_energy_mean_scale > 0.0);  
  3.     energy_threshold += opts.vad_energy_mean_scale * log_energy.Sum() / T;  
  4.   }  
  5.     
  6.   KALDI_ASSERT(opts.vad_frames_context >= 0);  
  7.   KALDI_ASSERT(opts.vad_proportion_threshold > 0.0 &&  
  8.                opts.vad_proportion_threshold < 1.0);  
  9.   for (int32 t = 0; t < T; t++) {  
  10.     const BaseFloat *log_energy_data = log_energy.Data();  
  11.     int32 num_count = 0, den_count = 0, context = opts.vad_frames_context;  
  12.     for (int32 t2 = t - context; t2 <= t + context; t2++) {  
  13.       if (t2 >= 0 && t2 < T) {  
  14.         den_count++;  
  15.         if (log_energy_data[t] > energy_threshold)  
  16.           num_count++;  
  17.       }  
  18.     }  
  19.     if (num_count >= den_count * opts.vad_proportion_threshold)  
  20.       (*output_voiced)(t) = 1.0;  
  21.     else  
  22.       (*output_voiced)(t) = 0.0;  
  23.   }  
  24. }    
  25.   
  26. }  

下面我将给出一个实际的计算过程的demo:

其中raw_mfcc_train1.txt 和 vad_train1.txt分别是在mfcc目录下执行:

./../../../../src/bin/copy-vector ark:vad_train.1.ark ark,t:- > vad_train1.txt 

./../../../../src/featbin/copy-feats ark:raw_mfcc_train.1.ark ark,t:- > raw_mfcc_train1.txt 

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import numpy as np  
  2.   
  3. def read_feats(filename):  
  4.     f = open(filename, 'r')  
  5.     all_xs = []  
  6.     arr = []  
  7.     for line in f:  
  8.         temp = []  
  9.         if '[' in line:  
  10.             pass  
  11.         else:  
  12.             l = line.strip().split(' ')  
  13.             #print "l->",len(l)  
  14.             if ']' in l:  
  15.                 l_temp = l[:-1]  
  16.                 for i in range(len(l_temp)):  
  17.                     if l_temp[i] != '':  
  18.                         temp.append(eval(l_temp[i]))  
  19.                 #print "temp->",len(temp)  
  20.                 arr.append(temp)  
  21.                 all_xs.append(arr)  
  22.                 arr = []  
  23.             else:  
  24.                 for i in range(len(l)):  
  25.                     if l[i] != '':  
  26.                         temp.append(eval(l[i]))  
  27.                 #print "temo->",len(temp)  
  28.                 arr.append(temp)  
  29.     return all_xs  
  30. mfcc_filename = 'raw_mfcc_train1.txt'  
  31. all_feats = read_feats(mfcc_filename)  
  32. vad_energy_threshold = 5.5  
  33. vad_energy_mean_scale = 0.5  
  34. vad_frames_context = 5  
  35. vad_proportion_threshold = 

猜你喜欢

转载自blog.csdn.net/ggjttfc/article/details/84063211