日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

搞懂语音去噪

發布時間:2024/7/5 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 搞懂语音去噪 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 1 概述
  • 2 傳統語音去噪
    • 2.1 譜減法
    • 2.2 維納濾波法
  • 3 深度語音去噪
  • 參考資料

1 概述

語音去噪(noise reduction)又被稱為語音增強(speech enhancement),主要是針對于有人聲的音頻進行處理,目的是去除那些背景噪聲,增強音頻中人聲的可懂性(intelligibility)。其應用范圍很廣,可以用于人與人之間的語音通訊,也可以用于很多語音任務的預處理,比如Automatic speech recognition。

這里的噪聲通常被分為兩大類,stationary和non-stationary。

stationary noise是指不隨著時間發生變化變化的噪聲,比如菜場的嘈雜聲,電臺的雜訊聲等等

non-stationary noise是指隨時間發生變化的噪聲,比如說話時背后突然經過一輛汽車,又比如突然響起的警報聲等等。

舉個實際應用中去噪的例子,我們的手機一般會為我們的通話自動做降噪處理,它會在離說話人嘴巴較近的地方裝一個聲音接收器,又會在離說話人嘴巴較遠的地方裝一個聲音接收器,并認為后者接收到的聲音基本就是noise,然后在這個前提下對人說的話進行去噪。有這樣的設備的幫助,去除non-stationary noise會更方便一些,但很多情況下,我們拿到的就只有一段有噪聲的語音。

2 傳統語音去噪

2.1 譜減法

譜減法應該是最早被用于語音去噪的方法,它的思想非常簡單,就是通過估計出噪聲,并在頻域里將其幅值剪掉,再還原,就結束了。為了表示方便,我們先假設純凈的聲音為x(n)x(n)x(n),原始聲音為y(n)y(n)y(n),噪聲為e(x)e(x)e(x),就有

y(n)=x(n)+e(n)(2-1)y(n) = x(n) + e(n) \tag{2-1} y(n)=x(n)+e(n)(2-1)

這里只有y(n)y(n)y(n)是我們有的,其他x(n)x(n)x(n)e(n)e(n)e(n)都還不知道,目的是把x(n)x(n)x(n)給求出來。

noisereduce中的stationary的方法就是用譜減法去做的,效果還是不錯的,不過也只能應對于stationary noise。

我們按譜減法步驟來說明一下整個過程。

(1)截取頭部一小段語音作為噪聲
e(m)=y(n)[:m]e(m) = y(n)[:m] e(m)=y(n)[:m]

其中eee表示噪聲信號,yyy表示原始信號,mmmnnn表示sample的數量。

我們認為stationary noise是一直存在于背景當中的聲音,而人聲一般在開頭的幾十毫秒是沒有的,所以就默認取前面一小段作為噪聲。不過當無法確定噪聲的時候,把整段聲音都作為噪聲也是可以的,noisereduce就是這么做的。

(2)分別計算原始音頻和噪聲的STFT,Y(ω)Y(\omega)Y(ω)E(ω)E(\omega)E(ω)。
(3)根據噪聲的頻譜幅值,對原始音頻的頻譜幅值進行譜減。

最粗暴的做法是直接對每個頻率上的∣E(ω)∣|E(\omega)|E(ω)沿時間軸取均值得到∣E(ω)∣mean|E(\omega)|_{mean}E(ω)mean?,然后再把原始音頻每個時間點每個頻率上的幅值減去對應的均值,并把相減后幅值小于0的置0,作為對純凈音頻的頻譜幅值估計∣X^(ω)∣|\hat{X}(\omega)|X^(ω)。有的地方也會用能量譜∣X^(ω)∣2|\hat{X}(\omega)|^2X^(ω)2,這里只是為了說明大意,不管這些細節了。

∣X^(ω)∣={∣Y(ω)∣?∣E(ω)∣mean,if∣Y(ω)∣?∣E(ω)∣mean>00,otherwise(2-2)|\hat{X}(\omega)| = \begin{cases} |Y(\omega)| - |E(\omega)|_{mean}, & if \ |Y(\omega)| - |E(\omega)|_{mean} > 0 \\ 0, &otherwise \end{cases} \tag{2-2} X^(ω)={Y(ω)?E(ω)mean?,0,?if?Y(ω)?E(ω)mean?>0otherwise?(2-2)

這樣做不好的地方就是會有很多坑坑洼洼的噪聲頻率殘留,這個現象也被稱為是音樂噪聲。實際操作過會發現這種方法減了和沒減差不多。因此有人提出了過減法,就是寧可錯殺一千不能放過一個的做法。

∣X^(ω)∣={∣Y(ω)∣?α∣E(ω)∣mean,if∣Y(ω)∣>(α+β)∣E(ω)∣meanβ∣E(ω)∣,otherwise(2-3)|\hat{X}(\omega)| = \begin{cases} |Y(\omega)| - \alpha |E(\omega)|_{mean}, & if \ |Y(\omega)| > (\alpha + \beta)|E(\omega)|_{mean}\\ \beta |E(\omega)|, &otherwise \end{cases} \tag{2-3} X^(ω)={Y(ω)?αE(ω)mean?,βE(ω),?if?Y(ω)>(α+β)E(ω)mean?otherwise?(2-3)

其中,α∈[0,+∞]\alpha \in [0, +\infin]α[0,+]是過減因子,β∈[0,1]\beta \in [0, 1]β[0,1]是譜下限參數,用來控制殘留多少的噪聲。這樣減出來噪聲會明顯少了很多,但聲音也會隨著α\alphaα的增大而逐漸失真。

noisereduce中的具體實現略有不同,它過減用∣E(ω)∣|E(\omega)|E(ω)的方差來控制,一般是1.5倍或者1.0倍的方差。代碼片段如下所示

self.mean_freq_noise = np.mean(noise_stft_db, axis=1) self.std_freq_noise = np.std(noise_stft_db, axis=1) self.noise_thresh = self.mean_freq_noise + self.std_freq_noise * self.n_std_thresh_stationary

小于noise_thresh的幅值會置0,其余的保留。n_std_thresh_stationary為0時,就是沒有過減的式(2?2)(2-2)(2?2)。

(4)對∣X^(ω)∣|\hat{X}(\omega)|X^(ω)做平滑處理,使得聲音失真沒那么嚴重。

noisereduce中使用的scipy.signal.fftconvolve來實現這一過程。

(5)結合原始音頻的相位,還原譜減后的音頻。這就是個反向STFT的過程。

建議看一下noisereduce的代碼,還是比較容易理解的。

2.2 維納濾波法

維納濾波法(wiener filter)也是一個比較經典的傳統做法,它的本質是估計出一個線性濾波器,也就是一個向量,這個濾波器會對不同的頻段進行不同程度的抑制,其保真效果會比譜減法要好一些。

我們這里不會講詳細的推導過程,只講其大致思想。因為這么大功夫推導出來,還是有很多不能解決的問題,還不如深度學習train一發。想看詳細推導了可以去看知乎的卡爾曼濾波器詳解——從零開始(3) Kalman Filter from Zero這篇,于泓-語音增強-維納濾波這個視頻講的更偏向于應用,都很棒。

還有就是這里講的是smoothing的問題,即根據未來的信號,過去的信號以及現在的信號來推測出現在的干凈信號。除此之外,還有prediction和filtering的問題,prediction是指根據過去的和現在的信號,預測未來的干凈信號;filtering的問題是指根據過去和現在的信號,推測現在的干凈信號。所以這里講的方法沒法應用于實時語音去噪,只能在拿到整段信號之后,對這段信號進行去噪。

維納濾波器的設計準則為使得干凈信號x(n)x(n)x(n)和估計的干凈信號x^(n)\hat{x}(n)x^(n)之間的差值越小越好,即計算一個最小均方差

MSE(x^)=E(x^(n)?x(n))2(2-4)MSE(\hat{x}) = E(\hat{x}(n) - x(n))^2 \tag{2-4} MSE(x^)=E(x^(n)?x(n))2(2-4)

這里的x^(n)\hat{x}(n)x^(n)是估計的干凈信號,x(n)x(n)x(n)是真實的干凈信號。

我們假設設計出來的濾波器為h(n)h(n)h(n),則我們有

x^(n)=h(n)?y(n)(2-5)\hat{x}(n) = h(n)*y(n) \tag{2-5} x^(n)=h(n)?y(n)(2-5)

這里的y(n)y(n)y(n)是原始信號,?*?表示卷積。時域的卷積就是頻域的乘積。就有

X^(ω)=H(ω)Y(ω)(2-6)\hat{X}(\omega) = H(\omega)Y(\omega) \tag{2-6} X^(ω)=H(ω)Y(ω)(2-6)

我們用(2?4)(2-4)(2?4)來計算這里的H(ω)H(\omega)H(ω),這里省略去一大波的推導過程,最終有

H(ωk)=Pxx(ωk)Pxx(ωk)+Pnn(ωk)(2-7)H(\omega_k) = \frac{P_{xx}(\omega_k)}{P_{xx}(\omega_k) + P_{nn}(\omega_k)} \tag{2-7} H(ωk?)=Pxx?(ωk?)+Pnn?(ωk?)Pxx?(ωk?)?(2-7)

其中,Pxx(ωk)=E[∣X(ωk)∣2]P_{xx}(\omega_k) = E[|X(\omega_k)|^2]Pxx?(ωk?)=E[X(ωk?)2]Pnn(ωk)=E[∣N(ωk)∣2]P_{nn}(\omega_k) = E[|N(\omega_k)|^2]Pnn?(ωk?)=E[N(ωk?)2],這里為了避免符號混淆,把噪聲的頻域用N(ωk)N(\omega_k)N(ωk?)來表示的。

(2?7)(2-7)(2?7)也可以表示為

H(ωk)=ξkξk+1(2-8)H(\omega_k) = \frac{\xi_k}{\xi_k + 1} \tag{2-8} H(ωk?)=ξk?+1ξk??(2-8)

其中,ξk=Pxx(ωk)Pnn(ωk)\xi_k=\frac{P_{xx}(\omega_k)}{P_{nn}(\omega_k)}ξk?=Pnn?(ωk?)Pxx?(ωk?)?為先驗信噪比,就是干凈信號的能量譜和噪聲能量譜的比例。

(2?8)(2-8)(2?8)可以看出,當噪聲占比比較小時,H(ωk)H(\omega_k)H(ωk?)就比較大,表示允許干凈信號通過;當噪聲占比比較大時,H(ωk)H(\omega_k)H(ωk?)就比較小,表示抑制噪聲信號通過。

(2?8)(2-8)(2?8)有一個變種的泛化形式

H(ωk)=(ξkξk+α)β(2-9)H(\omega_k) = (\frac{\xi_k}{\xi_k + \alpha})^{\beta} \tag{2-9} H(ωk?)=(ξk?+αξk??)β(2-9)

這里的α\alphaαβ\betaβ都是可以設置的參數,當α=1\alpha = 1α=1并且β=1\beta=1β=1時,式(2?9)(2-9)(2?9)就變成了式(2?8)(2-8)(2?8)。不同的α\alphaαβ\betaβ的值可以控制對噪聲的抑制程度,當我們事先知道噪聲大概在哪個頻段的時候,就可以對不同的頻段設置不同的α\alphaαβ\betaβ

實際應用時我們并沒有干凈信號,也沒有噪聲信號,所以似乎沒法算H(ωk)H(\omega_k)H(ωk?)。這就需要我們先去估計一個噪聲信號和干凈的信號了。估計的方法可以用2.1中的譜減法,也就是說當只有含噪聲的原始信號時,維納濾波就是在譜減法的基礎上再進行了一次估計。

比如我們有一個長度為(23410,)(23410,)(23410,)的信號,經過譜減法之后得到了一個(23296,)(23296,)(23296,)的干凈信號和噪聲信號。由于短時傅里葉的原因,信號長度會變短一些,這個不影響。我們拿譜減估計的干凈信號和噪聲信號去計算濾波器。干凈信號和噪聲信號經過STFT之后都變成了(129,183)(129, 183)(129,183)的信號,其中129表示有129個頻段,183時間維度上按窗口分割的分段數量。H(ωk)H(\omega_k)H(ωk?)計算出來是一個(129,1)(129, 1)(129,1)的向量,即對每個頻段的抑制程度,然后整條信號過這個濾波器之后,做ISTFT還原。示例代碼可見test_wiener_2.py。

從這里也不難看出,對整條信號使用的濾波器參數是固定的。這也使得該方法無法搞定non-stationary noise。

3 深度語音去噪

前人想了這么多用公式推導而來的去噪方法,都不能很好地搞定non-stationary noise,還不如深度學習train一發。深度學習的效果是真的好,而且速度都比傳統的方法快,只要有數據就行,數據驅動才是王道啊。

這里要講的是facebook出品的機遇DEMUCS的denoiser。DEMUCS之前是用于音頻分軌(source separation)的,去噪的本質其實也就是把人聲軌給分離出來,與其說是去噪,不如說是提取人聲更為合理一些。當然,這個都是由數據控制的。其目的是用神經網絡構建一個函數fff使得式(2?1)(2-1)(2?1)中的

x(n)=f(y(n))(3-1)x(n) = f(y(n)) \tag{3-1} x(n)=f(y(n))(3-1)

denoiser的模型架構非常簡明易懂,也非常輕量,可以用于實時的語音去噪,其結構示意圖如下圖3-1所示。

圖3-1 DEMUCS網絡結構示意圖

整個結構就是一個U-net的結構,輸入和輸出都直接是聲音信號,Encoder和Decoder都分別有LLL層,每一層都是由一個conv1d+relu+conv1d+glu組成的,其示意圖如下圖3-2所示。

圖3-2 encoder和decoder結構示意圖

其中,glu中的conv1d是一個kernel_size=1的卷積,主要目的是改變channel的數量,同時也可以在channel之間做特征的融合。encoderiencoder_iencoderi?的輸入只有上一個encoderi?1encoder_{i-1}encoderi?1?的輸出,decoderidecoder_idecoderi?的輸入除了上一個decoderi+1decoder_{i+1}decoderi+1?的輸入之外,還有encoderiencoder_iencoderi?的輸出。decoderidecoder_idecoderi?利用encoderiencoder_iencoderi?這樣的操作也被稱作skip connection。

encoderLencoder_LencoderL?的最終輸出會經過一個LSTM之后再進入decoderLdecoder_LdecoderL?。記encoderLencoder_LencoderL?的輸出為zzzdecoderLdecoder_LdecoderL?的輸入特征為z^\hat{z}z^,則有

z^=LSTM(z)+z(3-2)\hat{z} = LSTM(z) + z \tag{3-2} z^=LSTM(z)+z(3-2)

網絡的loss由兩部分組成,分別是L1 loss和多尺度的STFT loss組成。前者保證輸出信號相近,后者保證組成該輸出信號的頻率相近。

L1 loss表示了目標信號和模型輸出信號之間的差值,表示為

Lwaveform=1T∣∣x?x^∣∣1(3-3)L_{waveform} = \frac{1}{T} ||\bold{x} - \bold{\hat{x}}||_1 \tag{3-3} Lwaveform?=T1?x?x^1?(3-3)

其中,x\bold{x}x是干凈的目標信號,x^\bold{\hat{x}}x^是模型輸出的信號,TTT為采樣點的數量。

不過在實際的代碼實現中,這個loss可以是L1 loss,也可以是L2 loss,還可以是smooth L1 loss。

多尺度的STFT loss是指用不同的fft bins,hop sizes和window lengths的到的各個STFT下的loss,這也是為了讓模型不過擬合于某一種參數下的STFT變換。

Lstft=1T∑i=1MLstft(i)(x,x^)(3-4)L_{stft} = \frac{1}{T} \sum_{i=1}^M L_{stft}^{(i)}(\bold{x}, \bold{\hat{x}}) \tag{3-4} Lstft?=T1?i=1M?Lstft(i)?(x,x^)(3-4)

其中,每個Lstft(i)(x,x^)L_{stft}^{(i)}(x, \hat{x})Lstft(i)?(x,x^)由spectral convergence (sc) loss和magnitude loss組成。

Lstft(i)(x,x^)=Lsc(i)(x,x^)+Lmag(i)(x,x^)(3-5)L_{stft}^{(i)}(\bold{x}, \bold{\hat{x}}) = L_{sc}^{(i)}(\bold{x}, \bold{\hat{x}}) + L_{mag}^{(i)}(\bold{x}, \bold{\hat{x}}) \tag{3-5} Lstft(i)?(x,x^)=Lsc(i)?(x,x^)+Lmag(i)?(x,x^)(3-5)

spectral convergence (sc) loss為

Lsc(i)(x,x^)=∣∣∣STFT(i)(x)∣?∣STFT(i)(x^)∣∣∣F∣∣∣STFT(i)(x)∣∣∣F(3-6)L_{sc}^{(i)}(\bold{x}, \bold{\hat{x}}) = \frac{|| |STFT^{(i)}(\bold{x})| - |STFT^{(i)}(\bold{\hat{x}})| ||_F}{|| |STFT^{(i)}(\bold{x})| ||_F} \tag{3-6} Lsc(i)?(x,x^)=STFT(i)(x)F?STFT(i)(x)?STFT(i)(x^)F??(3-6)

magnitude loss為
Lmag(i)(x,x^)=∣∣log∣STFT(i)(x)∣?log∣STFT(i)(x^)∣∣∣1L_{mag}^{(i)}(\bold{x}, \bold{\hat{x}}) = || log|STFT^{(i)}(\bold{x})| - log|STFT^{(i)}(\bold{}\hat{x})| ||_1 Lmag(i)?(x,x^)=logSTFT(i)(x)?logSTFT(i)(x^)1?

沒錯,效果這么好的一個網絡就是這么簡單明了。訓練的時候當然也用到了一些數據增強等等的方法,這里就不說了,想了深入了解的可以看參考資料中的文獻和代碼。

參考資料

[1] 雷霄驊-譜減法語音降噪原理
[2] 于泓-語音增強-譜減法
[3] https://github.com/timsainb/noisereduce
[4] 于泓-語音增強-維納濾波
[5] https://github.com/facebookresearch/denoiser
[6] Real Time Speech Enhancement in the Waveform Domain
[7] 卡爾曼濾波器詳解——從零開始(3) Kalman Filter from Zero

總結

以上是生活随笔為你收集整理的搞懂语音去噪的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。