WebRTC VAD算法初探

时间:2024-03-31 08:27:51

这几天对webrtc中的VAD算法做了一些研究,有了一些心得


VAD算法中核心的是使用了GMM进行分类,noise作为一类,speech作为一类,两类求后验概率,并且实时的更新GMM的参数

但是这个GMM的具体情况是怎么样的,它的均值,方差,都是多少,使用特征的维度是多少?参数又是怎么更新的


一、GMM的 权重,均值,方差分析

频率域上分成了6个子带(channel),对每个子带求能量,初始值有一个GMM参数,包括 权重,均值,方差。

对噪声、语音,每个子带上的GMM的混合系数2,即2个高斯的mixture,一共6(6个channel,或者子带)*2(noise和speech)*2(每个GMM和混合系数是2)

你比如噪声的权重,kNoiseDataWeights,前六个和后六个分别是两个GMM的两组权重,Q7量化为2^7 =128

显然, 34/128 + 94/128 = 1; 62/128+66/128 = 1;...依次类推

WebRTC VAD算法初探

使用的特征是6维的,但是这6维不是直接就使用一个GMM模型,而是裂解成6个子特征(6个channel),每个一维度的特征作为一个混合高斯模型的输入,每个高斯混合模型的混合系数是2

问题比较简单了,既然不是多维度的,那么协方差矩阵的 正定问题 就归在一个方差值上面,也就这一个方差数大于0即可。

、高斯混合模型的后验概率

后验概率的公式我们先复习一下:WebRTC VAD算法初探(单维的公式就是简单明了啊)

函数 WebRtcVad_GaussianProbability 就是专门求这个后验概率,它先计算

 1 / s 然后计算 1 / s^2 再  |tmp32| = (x - m)^2 / (2 * s^2), 再计算 exp(-(x - m)^2 / (2 * s^2)),最后算出来  (1 / s) * exp(-(x - m)^2 / (2 * s^2))

暂时还没有看出来 1/sqrt(2*pi) 在哪里,估计在后面,或者忽略了。

WebRTC VAD算法初探


WebRTC VAD算法初探

注意输入的input是Q4的。实际上求后验概率,就这么简单,但是程序中非出来一个判断函数,这个主要是为了如果要求 x-> exp(-x)

当 |tmp32| = (x - m)^2 / (2 * s^2) (x是均值)这个值非常大的时候,超过一个范围 kCompVar = 22005的时候,认为 exp(-|tmp32|) 接近是 0直接给成0

这下面 令 x  = |tmp32| (下图中的红色的X), 主要目的是使用了 ”换底公式” ,以前是求exp的幂,现在是求2的幂【2的幂在定点代码中比e的幂好算】

我们主要方向,x --- > exp(-x) 考虑到Q值,Q10的量 另外 log2(exp(1)) = 1.4427WebRTC VAD算法初探
 x是Q10的,最后算出来的exp表达式也得是Q10,所以真正的 x到exp(-x),应该是

exp(-x/1024)*1024 = 1024*( 2 ^ [log2(e))*(-x/1024)]) = 1024* 2^ (-1.4427* x/1024)

这里面用了一些技巧,主要是为了方便求2个幂,我们给这个表达式上下都乘以一个数,2^[fix(x*1.4427/1024)+1]

2^10 * 2^ (-1.4427* x/1024) = 2^ (10 + -1.4427*x/1024) = 2^(10 + -1.4427*x/1024 +1 + fix(x*1.4427 /1024) ) /2^[fix(x*1.4427/1024)+1]

乘以这个数的主要目的是为了使得  -1.4427*x/1024 + 1 + fix(x*1.4427 /1024) 能是一个不大于1的一个纯小数【小学概念】

上面那个除法表达式分子记为 Y(就是代码中的exp_value),所以有 Y = 2^(10 + -1.4427*x/1024 + 1 + fix(x*1.4427 /1024) ),另外 分母记为2^[fix(x*1.4427/1024)+1],最后分子准备右移(除法)就得结果了

对Y除2^10,                           Y/1024 = 2^(-1.4427*x/1024 + 1 + fix(x*1.4427 /1024) )


上面也说了,这个括号里面的数,应该为 1 + α , α是一个接近0比较小的数,我们利用二项式展开公式,分解2的幂

WebRTC VAD算法初探


WebRTC VAD算法初探


Y/1024 ≈ 2 + -1.4427*x/1024 + fix(x*1.4427 /1024) 那么Y有

                       Y  = 1024 *(2 + fix(x*1.4427 /1024)-1.4427*x/1024)

                          = 1024* ( 1-x* 1.4427/1024+  fix( x * 1.4427 / 1024)+1)

                         =   1024- x * 1.4427+1024* fix( x * 1.4427 / 1024)+1024

                         =  2^16 - x * 1.4427 - 1024 *  (63) + 1024* fix( x * 1.4427 / 1024)  + 1024

                         =  2^16 - x * 1.4427 - 1024 *  (63 - fix( x * 1.4427 / 1024) ) + 1024

                      而         fix(( 2^16 - x * 1.4427) / 1024)=   63 - fix( x * 1.4427 / 1024); 【的确不是64减】

                      故  Y =     2^16 - x * 1.4427 -  1024*fix(( 2^16 - x * 1.4427) / 1024)  + 1024 = 2^16 - x * 1.4427-  1024*fix(( 2^16 - x * 1.4427) / 1024) + 1024

2^16 - x * 1.4427  是求相反数,代码中的刚从 WEB...MUL...RSFT算出来的 tmp16 = 1.4427* x ;

1024*fix(( 2^16 - x * 1.4427) / 1024) 为了抛掉整数,只留小数部分(我知道这个蓝色表达式求得是整数部分),所以前面要加个“-”

1024 加上1024

再来看代码

WebRTC VAD算法初探

分母就不用多说了:  2^[fix(x*1.4427/1024)+1],除法(Y/tmp16)相当于右移 (exp_value>>tmp16)

22005 是这样算出来的   fix(22005*1.4427/1024)+1  = 32(最大右移数) ,那么 31 * 1024 /1.4427 =  2.2003e+004(倒算出来的,先有32-1)

Tips: 这个整体思路是要计算 x 到 exp(-x/1024)*1024,其中tmp16的值为 tmp16(最终值) = 2^(fix(x*1.4427/1024)+1)

我已经计算出来了 exp(-x/1024)*1024 = Y/tmp16 (令Y为分子,tmp16为分母)

我先计算Y/1024, 为的是这个数比较能用2的幂级数展开近似求,求出来之后, 得到Y,一个除法(Y/tmp16)就是最终结果

代码中为什么是 exp_value >> = tmp16?  它相当于 是在求一个除法,Y >>fix(x*1.4427/1024)+1

也就是 Y / 2^[fix(x*1.4427/1024)+1]

为什么exp的算法最后是个除法?原因是用了“换底公式”都换成2的幂去计算了


、高斯混合模型的参数更新

参数更新问题,很多博客已经给出了很详细的说明,比如http://blog.csdn.net/shichaog/article/details/52399354  【这里感谢博主】

噪声均值的更新WebRTC VAD算法初探 参考代码 vad_sp.c中的  WebRtcVad_FindMinimum 函数

WebRTC VAD算法初探

WebRTC VAD算法初探

从这个公式我们就可以看出来了,对于noise的mean增大,比较抠门,尽可能的保持原有的噪声水平不变

对缩小,放的比较开,这是为了保证噪声跟进能比较准确


对于下面的参数更新,我这里做一些啰嗦的说明,以便大家理解的更好一些,【先放成果照片,拜大神,后面我再详细说明】

WebRTC VAD算法初探


WebRTC VAD算法初探

偏导公式太复杂了,我也记不住,用matlab来算吧

WebRTC VAD算法初探

代码最核心的更新部分:GmmProbability函数中

WebRTC VAD算法初探


WebRTC VAD算法初探