1. 程式人生 > 其它 >WebRTC VAD流程解析【摘自“語音演算法組”公眾號-Ryuk】

WebRTC VAD流程解析【摘自“語音演算法組”公眾號-Ryuk】

摘自 https://mp.weixin.qq.com/s/tLfI7me6TMdcwLG4wjOw9A

1. Introduction

WebRTC VAD支援8/16/24/32/48kHz取樣率,不過都會重取樣到8kHz進行計算,每一幀長度可以為80/10ms、160/20ms和240/30ms三種。VAD具有如下的四種模式,分別表示通用模式、低位元率模式、激進模式和非常激進模式,在不同模式下高斯混合模型的引數和判決的門限值有所不同。

    enum Aggressiveness {
        kVadNormal = 0,
        kVadLowBitrate = 1,
        kVadAggressive = 2,
        kVadVeryAggressive = 3
    };

WebRTC採用GMM統計模型對語音進行VAD判決,將0~4kHz劃分為如下的六個頻段:80~250Hz,250~500Hz,500~1kHz,1k~2kHz,2k~3kHz,3k~4kHz,並使用這些頻段的子帶能量作為GMM相關特徵。

2. Initialization

Talk is cheap, 直接看程式碼,WebRtcVad_InitCore 函式對以下內容進行初始化。

  • VAD初始狀態,這裡將VAD初始狀態設為語音存在,這會導致對於某些樣本開始的一段語音VAD檢測結果均為1。
  • Hang-over的相關引數。
  • 下采樣濾波器的係數,前面講過不管輸入的取樣率是多少,最後都會下采樣到8kHz進行處理。
  • GMM的語音噪聲的均值和方差,這裡kTableSize=12表示兩個模型各6個子帶,定標Q=7。
  • 最小值向量,用來跟蹤噪聲。
  • split filter係數,WebRTC對語音進行子帶劃分是通過split filter進行處理的而非FFT。
  • 檢測模式預設為aggressiveness,後面可通過WebRtcVad_set_mode函式進行修改。
int WebRtcVad_InitCore(VadInstT *self) {
    int i;

    if (self == NULL) {
        return -1;
    }

    // Initialization of general struct variables.
    self->vad = 1;  // Speech active (=1).
    self->frame_counter = 0;
    self->over_hang = 0;
    self->num_of_speech = 0;

    // Initialization of downsampling filter state.
    memset(self->downsampling_filter_states, 0,
           sizeof(self->downsampling_filter_states));

    // Initialization of 48 to 8 kHz downsampling.
    WebRtcSpl_ResetResample48khzTo8khz(&self->state_48_to_8);

    // Read initial PDF parameters.
    for (i = 0; i < kTableSize; i++) {
        self->noise_means[i] = kNoiseDataMeans[i];
        self->speech_means[i] = kSpeechDataMeans[i];
        self->noise_stds[i] = kNoiseDataStds[i];
        self->speech_stds[i] = kSpeechDataStds[i];
    }

    // Initialize Index and Minimum value vectors.
    for (i = 0; i < 16 * kNumChannels; i++) {
        self->low_value_vector[i] = 10000;
        self->index_vector[i] = 0;
    }

    // Initialize splitting filter states.
    memset(self->upper_state, 0, sizeof(self->upper_state));
    memset(self->lower_state, 0, sizeof(self->lower_state));

    // Initialize high pass filter states.
    memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state));

    // Initialize mean value memory, for WebRtcVad_FindMinimum().
    for (i = 0; i < kNumChannels; i++) {
        self->mean_value[i] = 1600;
    }

    // Set aggressiveness mode to default (=|kDefaultMode|).
    if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) {
        return -1;
    }

    self->init_flag = kInitCheck;

    return 0;
}

3. VAD Decision

下面開始介紹WebRTC的VAD處理流程(WebRtcVad_Process),具體的步驟如下所示:

  1. 進行一些基本的檢測(WebRtcVad_ValidRateAndFrameLength),檢測VAD結構體是否被初始化,語音幀長度是否滿足條件。
  2. 對語音進行下采樣,取樣到8kHz,WebRTC的下采樣並不是一步到位。以48kHz下采樣到8kHz為例(WebRtcSpl_Resample48khzTo8khz):首先48kHz下采樣到24kHz,然後對24kHz的語音資料進行低通濾波(這一步並不改變取樣率),後面繼續進行下采樣24kHz->16kHz,16kHz->8kHz,最終得到8kHz的語音資料。
  3. 得到8kHz的語音資料之後,我們計算語音各個子帶的能量作為GMM相關特徵(WebRtcVad_CalculateFeatures)。首先將4kHz的資料分為02kHz和2k4kHz,然後將2k4kHz部分劃分為2k3kHz和3k4kHz兩部分。02kHz中則先分為01kHz和1k2kHz兩部分,其中01kHz再分為0250Hz和250500Hz,最後對0250Hz部分進行80Hz高通濾波得到80250Hz的部分,至此得到六個子帶:80250Hz,250500Hz,5001kHz,1k2kHz,2k3kHz,3k~4kHz六個子帶,分別計算這六個子帶的對數能量作為GMM相關特徵。除此之外,還計算了一個total_energy,這個引數會在後面計算GMM的時候使用(WebRtcVad_GmmProbability)。
  4. 接下來就是計算GMM的部分的,關於GMM的原理可以參考從零實現機器學習演算法(十九)高斯混合模型。在計算前會根據語音幀長度選擇不同的判決閾值。
  • a. 首先判斷上一步驟計算得到的total_energy是否大於能量的門限值kMinEnergy,如果大於則對當前幀進行處理;否則直接將vad_flag置為0。
  • b. 計算每個子帶對應的高斯概率(WebRtcVad_GaussianProbability)並與子帶的權重相乘作為語音/噪聲最終的概率,這裡WebRTC為了簡化計算,假設語音和噪聲的高斯模型是不相關的。
  • c. 計算每個子帶的對數似然比(log likelihood ratio, LLR),每個子帶的似然比會和閾值進行比較作為一個區域性的VAD判決。所有子帶的對數加權似然比之和和閾值比較作一個全域性的VAD判決。當局部判決或者全域性判決結果有一個判決有語音時則認定當前幀是語音幀。
  • d. 使用hangover對結果進行平滑

4. Updation

WebRTC的VAD具有自適應的能力是因為其做完VAD判決後會更新GMM的引數。

  1. 計算區域性(每個子帶)語音和噪聲的概率用於更新GMM引數。
  2. 跟蹤每個子帶特徵的最小值(WebRtcVad_FindMinimum), 函式對每個特徵求出了100個幀裡頭的16個最小值。這些最小值都有一個age,最大不超過100,如果當前特徵是100 幀裡 16 個最小值之一,那麼計算並返回五個最小值的中位數。這裡得到的最小值後面會用來更新噪聲。
  3. 更新GMM引數即語音/噪聲的均值和方差,其中噪聲的均值只在當前語音幀為非語音幀時進行更新。
  4. 當語音高斯模型和噪聲高斯模型很相似時,分離它們。

5. Conclusion

WebRTC的VAD在信噪比較高的情況下可以得到比較好的結果,隨著信噪比的下降,其檢測結果也隨之惡化。此外,WebRTC的VAD的工程實現使用了定點數運算和一些近似運算這使得其資源佔用不是很高,但使得程式碼比較難讀。本文只解析了WebRTC中VAD大致的流程,其中一些具體的細節還有待讀者自己去深究。WebRTC VAD的內容還是很蠻多的,如有所遺漏敬請見諒。