介紹一個深度語音降噪庫
代碼已 clone 到:https://gitee.com/nwaycn/rnnoise.git
原鏈接:https://github.com/xiph/rnnoise
這是 RNNoise
此演示介紹了 RNNoise 項目,展示瞭如何將深度學習應用於噪聲抑制。 主要思想是將_經典_信號處理與 深度學習,用於創建小型且快速的實時噪聲抑制算法。無需昂貴的 GPU — 它在 Raspberry Pi 上輕鬆運行。結果更簡單(更容易調音),聽起來比傳統噪音更好 抑制系統!
噪聲抑制
噪聲抑制是語音處理中一個相當古老的話題,至少可以追溯到 70 年代。 顧名思義,這個想法是接收嘈雜的信號並儘可能多地消除噪聲 同時對感興趣的語音造成最小失真。
從上圖來看,噪聲抑制看起來很簡單:概念上只有三個 簡單的任務,我們就完成了,對吧?對——也有錯!任何本科 EE 學生都可以寫作 一種有效的噪聲抑制算法... 有點...... 有時。困難的部分是讓它發揮作用 嗯,每時每刻,各種噪音。這需要非常仔細地調整 算法,奇怪信號的許多特殊情況和大量測試。總有一些奇怪的 信號會導致問題並需要更多調整,並且很容易破壞更多東西 比你修復的要多。這是 50% 的科學,50% 的藝術。我以前用噪音抑制器去過那裏 在 SpeexDSP 庫中。它有點管用,但不是很好。
深度學習和遞歸神經網絡
深度學習是一箇舊想法的新版本:人工神經網絡。儘管那些 自 60 年代以來,近年來的新變化是:
-
我們現在知道如何使它們比兩個隱藏層更深
-
我們知道如何讓循環網絡記住很久以前的模式
-
我們擁有實際訓練它們的計算資源
循環神經網絡 (RNN) 在這裏非常重要,因爲它們使時間建模成爲可能 序列,而不僅僅是獨立考慮輸入和輸出幀。這是 對於噪聲抑制尤其重要,因爲我們需要時間來獲得良好的估計 的噪音。長期以來,RNN 的能力受到嚴重限制,因爲 它們無法長時間保存信息,並且因爲梯度下降 當隨時間反向傳播時所涉及的過程效率非常低(消失的梯度 問題)。這兩個問題都通過_門控單元_的發明得到了解決,例如 長短期記憶 (LSTM)、門控循環單元 (GRU) 及其許多變體。
RNNoise 使用門控循環單元 (GRU),因爲它的性能略好於 LSTM 此任務需要更少的資源(權重需要 CPU 和內存)。與_簡單的_循環單元相比,GRU 有兩個額外的_門_。_reset_ gate 控制 state (memory) 用於計算新 state,而 _Update_ Gate 控制 狀態將根據新輸入更改的程度。此更新門 (關閉時) 使其 GRU 可能(且容易)長時間記住信息,並且是 原因 GRU(和 LSTM)的性能比簡單的循環單元好得多。
混合方法
由於深度學習的成功,現在流行的是拋出深度神經網絡 解決整個問題。這些方法稱爲_端到端_ — 全是神經元 下山的路。端到端方法已應用於語音識別和語音合成一方面,這些端到端系統已經證明了深度的強大功能 神經網絡可以是。另一方面,這些系統有時可能既不是最優的, 在資源方面浪費。例如,一些噪聲抑制方法使用 具有數千個 神經元 — 以及數千萬個權重 — 來執行噪聲抑制。缺點 不僅是運行網絡的計算成本,也是模型_的大小_ 本身,因爲您的庫現在是 1000 行代碼以及數十兆字節(如果不是更多的話) 的神經元權重。
這就是爲什麼我們在這裏採用了不同的方法:保留所有基本的信號處理 無論如何都需要(沒有神經網絡嘗試模擬它),但讓神經 網絡 學習所有需要無休止調整的棘手部分 信號處理. _另一個不同_於現有深度學習噪聲抑制工作的事情 是我們的目標是實時通信而不是語音識別,所以我們負擔不起 _向前看_超過幾毫秒(在本例中爲 10 毫秒)。
定義問題
爲了避免出現大量 output — 從而避免出現大量神經元 — 我們決定不直接使用樣品或光譜。相反,我們考慮遵循 Bark 標度的_頻段_,Bark 標度是一種與我們感知聲音的方式相匹配的頻率標度。我們使用 總共 22 個波段,而不是我們必須考慮的 480 個(複數)光譜值。
當然,我們不能僅根據 22 個頻段的能量來重建音頻。不過,我們能做的是 計算應用於每個頻段的信號的增益。您可以將其視爲使用 22 波段 均衡器並快速更改每個頻段的電平以衰減噪聲,但讓 信號通過。
使用每頻段增益工作有幾個優點。首先,它使 更簡單的模型,因爲要計算的波段較少。其次,它使創建 所謂的_音樂噪聲_僞影,只有一個音調通過,而它的鄰居 被衰減。這些僞像在噪聲抑制中很常見,而且非常煩人。使用帶 足夠寬,我們要麼讓一整條帶通過,要麼全部剪掉。第三個優勢來自 我們如何優化模型。由於增益始終介於 0 和 1 之間,因此只需使用 sigmoid 激活函數(其輸出也介於 0 和 1 之間)來計算它們可確保 我們永遠不能做一些非常愚蠢的事情,比如添加一開始就不存在的噪音。
For the output, we could also have chosen a rectified linear activation function to represent an attenuation in dB between 0 and infinity. To better optimize the gain during training, the loss function is the mean squared error (MSE) applied to the gain raised to the power α. So far, we have found that α=0.5 produces the best results perceptually. Using α→0 would be equivalent to minimizing the log spectral distance, and is problematic because the optimal gain can be very close to zero.
我們從使用頻段獲得的較低分辨率的主要缺點是我們不會 具有足夠精細的分辨率,以抑制音高泛音之間的噪聲。幸運 這並不那麼重要,甚至有一個簡單的技巧可以做到這一點(請參閱下面的 Pitch Filtering 部分)。
由於我們正在計算的輸出基於 22 個頻段,因此使用 輸入上的頻率分辨率更高,因此我們使用相同的 22 個頻段來饋送頻譜信息 到神經網絡。因爲音頻具有很大的動態範圍,所以計算要好得多 能量的對數,而不是直接饋送能量。雖然我們正在努力,但它從來沒有 使用 DCT 去關聯特徵很受傷。結果數據是基於 Bark 量表的_倒譜_,它與 Mel 頻率倒譜系數 (MFCC) 密切相關 這些方法在語音識別中非常常用。
除了我們的倒譜系數外,我們還包括:
-
跨幀的前 6 個係數的一階和二階導數
-
音高週期 (1 / 基頻頻率)
-
6 個頻段的音高增益(發聲強度)
-
一個特殊的非平穩性值,可用於檢測語音(但超出了本演示的範圍)
這使得神經網絡總共有 42 個輸入特徵。
深度架構
我們使用的深度架構的靈感來自傳統的噪聲抑制方法。 大部分工作由 3 個 GRU 層完成。下圖顯示了我們用於計算 頻帶增益以及架構如何映射到噪聲抑制中的傳統步驟。答案是肯定的 與神經網絡通常的情況一樣,我們沒有實際證據表明網絡正在使用其 層,但事實上,這種拓撲比我們嘗試過的其他拓撲效果更好,這使得它 有理由認爲它的行爲符合我們的設計。
一切都與數據有關
即使是深度神經網絡有時也可能非常愚蠢。他們非常擅長他們所知道的 about,但是他們可能會在與輸入相差太遠的輸入上犯下非常嚴重的錯誤 知道。更糟糕的是,他們真的是懶惰的學生。如果他們可以在訓練中使用任何形式的漏洞 過程以避免學習困難的東西,那麼他們就會。這就是爲什麼培訓的質量 數據至關重要。
在噪聲抑制的情況下,我們不能只收集可以 用於監督學習,因爲我們很少能同時獲得乾淨的語音和嘈雜的語音 speech 同時。相反,我們必須人爲地從單獨的 乾淨的語音和噪音錄音。棘手的部分是獲取各種各樣的噪聲數據 以添加到語音中。我們還必須確保涵蓋各種錄製條件。爲 例如,僅在全頻段音頻 (0-20 kHz) 上訓練的早期版本將失敗,當 音頻在 8 kHz 時進行低通濾波。
音高過濾
由於我們頻段的頻率分辨率太粗糙,無法過濾 Pitch Harmonis,我們使用基本的信號處理來實現。這是 混合方法。當一個人對同一變量進行多次測量時,最簡單的 提高精度(減少噪聲)的方法就是簡單地計算平均值。 顯然,僅僅計算相鄰音頻樣本的平均值並不是我們想要的,因爲 這將導致低通濾波。但是,當信號是週期性的(例如濁音 speech),那麼我們可以計算被 pitch period 偏移的樣本的平均值。結果 在_梳狀濾波器_中,讓 Pitch 諧波通過,同時衰減頻率 在他們之間——噪音所在的地方。爲避免信號失真, 梳狀濾波器對每個頻段獨立應用,其濾波器強度取決於音高相關性 以及神經網絡計算的頻帶增益。
從 Python 到 C
神經網絡的所有設計和訓練都是使用 Python 完成的,使用了出色的 Keras 深度學習庫。由於 Python 通常是 不是實時系統的首選語言,我們必須實現運行時代碼 幸運的是,運行神經網絡比訓練神經網絡要容易得多,因此 我們所要做的就是實現前饋和 GRU 層。爲了更容易地適應 weights 的 weights 中,我們將權重的大小限制爲 +/- 0.5 training,這使得使用 8 位值輕鬆存儲它們。生成的模型擬合 僅需 85 kB(而不是將權重存儲爲 32 位浮點數所需的 340 kB)。
C 代碼在 BSD 許可證下可用。儘管在編寫此演示時,代碼 尚未優化,但它的運行速度已經比 x86 CPU 上的實時快 60 倍左右。它的運行速度甚至比 在 Raspberry Pi 3 上實時運行。 通過良好的矢量化 (SSE/AVX),應該可以使其比現在快 4 倍左右。
相關論文
鏈接:https://arxiv.org/pdf/1709.08243
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/DWdu8QjVh7AqnU-2hJIAxQ