2022 AIdea 人聲語音去噪競賽 — 第三名作法分享 | Speech Enhancement Competition 3rd Place Sharing

Jay Wu
Jay’s Data Science and Machine Learning Note
15 min readApr 21, 2022

競賽連結

目前人工智慧語音識別的應用已越來越成熟、廣泛,然而背景音的干擾容易造成語音識別上的困難,因此,人聲去噪的技術將是一個重要的研究議題。

本議題期望以 AI 的方式識別混音檔案中的人聲,並保留人聲的部分以進行去噪,期望獲得更純淨的人聲音訊,提高語音識別應用的服務品質。

Leaderboard 結果

分享會影片存檔

環境與軟硬體

  • NVIDIA GeForce RTX 3060 Laptop GPU
  • Intel Core i7–11375H 11th
  • WSL2(Windows Subsystem for Linux)
  • Docker (Ubuntu 18.04.5 LTS in container)
  • CUDA Toolkit 11.6
  • Anaconda 4.11.0
  • Visual Studio Code

使用套件

  • Python 3.7.11
  • PyTorch 1.10.0
  • torchaudio 0.10.0
  • librosa 0.9.1
  • SoundFile 0.10.3.post1
  • speechbrain 0.5.11

前言

本文主要包含競賽模型上的做法,由於自己本身只對健康大數據以及影像領域較有相關經驗,先前除了工程數學與自動控制外有些許對數位訊號的概念,此外皆沒有修過 Digital Processing 或是其他與音訊處理有關的課程也沒有實作經驗,因此此篇文章也可以當做是一個零 Domain Knowledge 的菜鳥對音訊處理領域 from scratch 的學習記錄,內容若有疏漏也請鞭小力一點!

資料前處理

參考資料

Practical Deep Learning Audio Denoising — Thalles’ blog (sthalles.github.io)

深入理解短时傅里叶变换 STFT + Python 代码详解_IT说的博客-CSDN博客_python短时傅里叶变换

從參考資料以及先前與工程數學相關的修課經驗中可以了解到,針對如音訊等波形資料使用傅立葉轉換進行前處理是個值得嘗試的方向。在這次競賽研究相關方法的初期,發現近幾年基於深度學習類 Speech Enhancement (語音增強)的模型雖有部分是直接使用時域的音訊資料 (waveform) 當做模型輸入,但經前期研究後決定鎖定在近期表現較好使用傅立葉轉換到頻域後的資料作為模型輸入此種方式為主。

在經參考過許多參考資料後,了解到多數音訊資料在訊號的角度都是不平穩的 (non-stantionary),如這次議題的目標是將長度 3 秒帶有雜訊的人聲音訊還原成乾淨音訊,若直接進行傅立葉轉換的話效果會非常差。因此本次競賽中,採用 Pytorch 中的Short-time Fourier transform (STFT) 配合窗函數 hann_window 將每段音訊切分成前後有部分重疊的獨立音訊,示意圖可參考以下:

Source: Short-time Fourier transform — MATLAB stft (mathworks.com)

在完成音訊切分後,可以使用 torch.atan2 從每一段音訊中獨立計算 phase 以及使用 torch.norm 得到對應的 square root norm。得到上述資訊後,即可分別藉由 phase 與 magnitude(norm) 得到每段音訊的實部 (Real) 與虛部 (Imaginary) 當做模型的輸入。簡易程式碼可參考如下:

Modified from: yuguochencuc/DB-AIAT: The implementation of “Dual-branch Attention-In-Attention Transformer for single-channel speech enhancement” (github.com)

模型介紹

A. 模型選擇、描述

候選模型如下:

在競賽初期,首先在 Papers With Code 網站上針對關鍵字 Speech Enhancement 搜尋近年表現較好且有提供開源程式碼以及預訓練模型的相關 paper,主要希望能減少從細節建立模型所花費的時間成本,將重點放在修改並且調整現有 SOTA(state-of-the-art) 方法,期望能在本次競賽的資料集上能獲得較好的表現。

https://paperswithcode.com/task/speech-enhancement

在上述的前提下,首先使用 Speech Brain toolkit 中包裝好的 MetricGAN API 與預訓練模型參數對測試資料直接進行預測,發現效果並不是非常好。幾經思考後決定先行搜尋其他方法,若時間上允許再回來使用提供的預訓練模型在競賽資料上繼續進行訓練。

在經過多篇 paper 的比較後,瞭解到 DB-AIAT 可能是當下以我的能力可以找到最新、表現最好並且有提供完整開源程式碼與預訓練模型的方法(與其他方法的比較如下),因此接下來將會以此為主進行介紹。

首先,在目前 Speech Enhancement 的任務中,有一部分是採用 encoder-decoder架構預測出抗噪遮噪 (mask) 來與原始音訊的 magnitude 進行 element-wise multiplication 後得到降噪後的結果,而我所使用的 model DB-AIAT 的核心想法也是想要去改善現有 mask generation 的任務,示意圖參考如下:

Source: https://www.mdpi.com/2076-3417/10/9/3230/htm

DB-AIAT 的整體架構如下圖所示,大致上可以分為兩個 Branch,將會於接下來做更細節的介紹。這裡先稍微帶過模型有使用的部份 layer 但部分的人可能有點陌生的 LNPRelu,分別為 Layer NormalizationParametric Relu,這裡就不贅述如果大家有興趣可以點進連結去了解更多背後的核心想法。

在 Magnitude Masking Branch 中即為典型的 encoder-decoder 架構,試圖找出能降低噪音的遮噪,最終的輸出為原始輸入的 magnitude|Xt,f| 與 mask(Mmmb) 內積後得到的降噪 magnitude,並使用原始噪音中的 phase (θx) 分別得到降噪後的實部與虛部預測結果,式子可參考如下:

Complex Refining Branch 中,則希望能使用 Magnitude Masking Branch 缺失的實部與虛部資訊來改善降噪品質,因此採用與 Magnitude Masking Branch 大致相同的模型架構,但輸入則為噪音的實部與虛部資料,並且輸出實部與虛部的「改善殘差」與 Magnitude Masking Branch 中的預測結果進行相加得到最終的預測,式子可參考如下:

回到下圖的整體模型結構,可以發現作者在兩個 branch 中也有加入資訊『互傳』的設計,無論是在 Dense-encoder 或是 ATFAT module 中皆可發現這樣的機制存在,接下來將會針對 ATFAT module 做更詳細的介紹。

在 ATFAT 模塊分別有 adaptive temporal attention branch (ATAB) 與 adaptive frequency attention branch (AFAB) 兩種 branch,能針對「時域」與「頻域」兩個面向去增強音訊資料前後可能的長期依賴關係,並分別使用 α 與 β 兩種可被學習的 adaptive weight 去進行最終資訊融合。為了達成這樣的目的並希望降低計算資源的使用,這裡採用了在文字處理 (e.g. BERT) 或是時間序列領域已經被很長使用的『注意力機制』aka Attention Mechanism,在這裡所使用的是 Multi-head self-attention,有興趣的朋友們請參考此連結:https://blog.csdn.net/qq_37394634/article/details/102679096

ATFAT 模塊

除了上述所提 ATFAT 模塊,以下將介紹此模型另一個重要的 adaptive hierarchical attention (AHA) 同樣基於注意力機制的模塊。

AHA 則主要設計用來融合不同高低等級的特徵,使模型能從不同尺度去學習到資料彼此間的相關訊息。如下圖所式,AHA 模塊接受來自不同層 ATFAT 模塊的資訊,F1 為第一層 ATFAT ,並且疊的越來越深總共疊了 N 層,因此最後一層也就是最深的那層即為 FN。會想設計此模塊的原因是想融合不同 scale 的資訊,因為有時隨著網路越深學到越精細的特徵卻可能會丟失全局資訊,因此 AHA 再次利用 attention 的方法,讓模型自己去學習如何融合這些深淺不一的特徵,而融合後的資訊則稱為 Global Contextual feature map。值得一提的是,可以看到最深的那一個 ATFAT 模塊 FN 的資訊直接與經過 attention 處理的 Global Contextual feature map 進行 element-wise sum的處理,這樣的方式我在以前看時間序列資料相關的 paper 中也有不少類似操作,我個人判斷是因為 FN 包含較為精細的資訊,因此雖然前面已經與淺層 ATFAT 模塊做 attention 讓模型自己決定哪些資訊要留下來,但這樣的操作可以讓 FN 的資訊較為優先地被保留下來。

AHA 模塊

Loss Function 的設計上,分別以 magnitude 和實虛部的預測結果與真實值的差值得到兩種不同的 loss 並進行加權相加,式子如下圖所示,這裡的 μ 按照作者的實驗流程使用 0.5 代表兩種不同的 loss 對結果影響是同樣重要的。

B. 參數調校

DB-AIAT 中的網路結構中有許多可以調整的部份,例如每個小模塊中用了幾層 layer、每層 layer 的 dimension、CNN 的 kernel_size 等,但因為時間安排以及資源有限,無法在作者的基礎架構下使用 Neural Network Search (NAS) 的方式進行大量實驗去得到最佳的網路參數組合,此外調整模型架構後將會難以使用作者提供的原始模型預訓練模型參數在競賽資料上繼續進行訓練,因此在訓練時網路參數採用如原始 paper 中的設定。

在前處理時,使用 torch.stft 中有部分的參數是可以調整進行實驗的,但基於與上述相同理由,改變前處理流程中的參數也會導致輸入的形態改變(例如 input shape),這樣的調整將會使輸入型態與原始模型有差異而無法使用預訓練模型參數,詳細參數可參考如下:

torch.stft

在 Optimizer 上,本次使用 Ranger 進行訓練。可參考以下連結:https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer

在此 optimizer 中有許多參數可以調整,在簡單參考網路資料以及進行幾次實驗以後,決定僅給定 learning rate 與 weight_decay (用以防止 overfitting 的 L2 normalization penalty),其他皆使用原始預設參數,可參考如下:

Ranger Optimizer

結果說明

本次競賽結果可簡單彙總如下,leaderboard score 使用 PESQ 計算,可參考:

http://www.pal-acoustics.com/index.php?a=services&id=143&lang=cn

https://github.com/ludlows/python-pesq

1. MetricGAN Pre-trained: 使用 Speech Brain toolkit 中提供的預訓練模型參數直接對本次競賽的測試資料進行預測,並無額外經過訓練。可以看出以結果來說並不是太差,以比賽結束時的排名大約能坐落在中間排名(若以有提交者 67 位來進行計算的話)。

2. DB-AIAT Pre-trained: 使用作者提供的預訓練模型參數直接對本次競賽的測試資料進行預測,並無額外經過訓練。原先預期若以作者提供的方法比較上可能會比 MetricGAN Pre-trained 的方法還要好,但以結果來說卻是低了不少。因此在此簡單得到的結論為DB-AIAT可能對資料來源比較敏感,無法比較 general 地在非原始模型訓練資料外的資料也能達到不錯的表現,若需要有進一步的效果提昇勢必需要在本次競賽的訓練資料上進行訓練。

3. DB-AIAT Trained: 使用作者提供的預訓練模型參數,載入後繼續在本次競賽資料上進行訓練。訓練過程中依照噪音類型等比例切分 10% 的訓練資料當做驗證集,在每輪訓練過程結束後計算 validation PESQ 分數,除了以此為依據來存下所有訓練流程中表現最好的模型參數,也用來判斷是否需要進行 early stopping。以結果來看,相對未在競賽資料上進行訓練前有非常顯著的提升。

4. DB-AIAT Trained by Noise Type: 使用 DB-AIAT Trained 中在驗證集中或獲得最高 validation PESQ 分數的模型參數,在將資料依照噪音種類區分後,載入上述模型參數個別訓練專屬於特定噪音的模型。在競賽後期偶然觀察到測試集中的資料名稱皆有提供其噪音種類,例如「mixed_00001_air_conditioner.flac」即代表其為 air_conditioner 此種類型的噪音,因此可利用此資訊先在訓練資料中依噪音類型進行分類,並依照不同噪音類別進行訓練後得到針對不同種類噪音優化後的結果。

其他

雖然這次得分最高的結果是使用 DB-AIAT Trained by Noise Type 此種有針對不同噪音進行優化的方法,但此方法可能在應用於真實方案時會有問題。在現實世界的系統中,個人認為照理講是不會如這次的測試資料一樣預先得知需要降噪的音頻資料是參雜哪些種類的噪音,假設本次競賽預期是能得到較為 general 的降噪模型,應該需要考慮隱藏測試資料檔案名稱中的噪音類別資訊,此設定就會比較貼近真實應用中可能遇到的解題情形。然而,假設在進行 Speech Enhancement 任務前能有其他模型進行噪音初步分類,例如使用分類模型去判斷噪音屬於哪個種類或是使用 clustering 的方法將可能為同類別噪音的資料做簡單區分,此設定則比較能說明針對不同噪音類型進行優化訓練的合理性,但個人經驗中這樣的操作會增加部屬模型時 inference 時的耗時以及 GPU memory 的使用,也較難用在 real-time 應用,並不一定符合使用上的效益與需求。

寫在最後

去年的競賽,讓我這個 Computer Vision 完全零經驗的菜雞累積了不少經驗,後續也因為好好整理了競賽過程得到不少寶貴的機會;同樣地,這次的機會也讓我從 0 開始進入音訊處理的領域,除了發現自己工程上的能力變強一點可以快速進行實驗與測試 code 的撰寫與操作,更發現過去一年看 paper 下來所累積的 knowledge 已經可以轉移到其他領域上了,而不會因為要從頭接觸一個新的領域卻毫無方向不知道如何下手,這個部分真的有明顯感受到自己的成長,也期許自己能在閒暇時間中繼續接觸各式各樣的議題持續進步!

如果大家能耐心看到這,希望能對你有一丁點幫助我都會很高興,也可以幫我拍個手讓我知道!

若有任何問題、錯誤或是單純想互相認識一下的話,可以透過下列資訊聯絡我。

信箱:e14051350@gs.ncku.edu.tw

--

--