语音去噪:从传统方法到深度学习

亚洲365bet比分 📅 2025-09-23 09:41:50 👤 admin 👁️ 7771 ❤️ 50
语音去噪:从传统方法到深度学习

文章目录

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]

其中

e

e

e表示噪声信号,

y

y

y表示原始信号,

m

m

m和

n

n

n表示sample的数量。

我们认为stationary noise是一直存在于背景当中的声音,而人声一般在开头的几十毫秒是没有的,所以就默认取前面一小段作为噪声。不过当无法确定噪声的时候,把整段声音都作为噪声也是可以的,noisereduce就是这么做的。

(2)分别计算原始音频和噪声的STFT,

Y

(

ω

)

Y(\omega)

Y(ω)和

E

(

ω

)

E(\omega)

E(ω)。 (3)根据噪声的频谱幅值,对原始音频的频谱幅值进行谱减。

最粗暴的做法是直接对每个频率上的

E

(

ω

)

|E(\omega)|

∣E(ω)∣沿时间轴取均值得到

E

(

ω

)

m

e

a

n

|E(\omega)|_{mean}

∣E(ω)∣mean​,然后再把原始音频每个时间点每个频率上的幅值减去对应的均值,并把相减后幅值小于0的置0,作为对纯净音频的频谱幅值估计

X

^

(

ω

)

|\hat{X}(\omega)|

∣X^(ω)∣。有的地方也会用能量谱

X

^

(

ω

)

2

|\hat{X}(\omega)|^2

∣X^(ω)∣2,这里只是为了说明大意,不管这些细节了。

X

^

(

ω

)

=

{

Y

(

ω

)

E

(

ω

)

m

e

a

n

,

i

f

Y

(

ω

)

E

(

ω

)

m

e

a

n

>

0

0

,

o

t

h

e

r

w

i

s

e

(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

(

ω

)

m

e

a

n

,

i

f

Y

(

ω

)

>

(

α

+

β

)

E

(

ω

)

m

e

a

n

β

E

(

ω

)

,

o

t

h

e

r

w

i

s

e

(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)之间的差值越小越好,即计算一个最小均方差

M

S

E

(

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

)

=

P

x

x

(

ω

k

)

P

x

x

(

ω

k

)

+

P

n

n

(

ω

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)

其中,

P

x

x

(

ω

k

)

=

E

[

X

(

ω

k

)

2

]

P_{xx}(\omega_k) = E[|X(\omega_k)|^2]

Pxx​(ωk​)=E[∣X(ωk​)∣2],

P

n

n

(

ω

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

=

P

x

x

(

ω

k

)

P

n

n

(

ω

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)的,去噪的本质其实也就是把人声轨给分离出来,与其说是去噪,不如说是提取人声更为合理一些。当然,这个都是由数据控制的。其目的是用神经网络构建一个函数

f

f

f使得式

(

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都分别有

L

L

L层,每一层都是由一个conv1d+relu+conv1d+glu组成的,其示意图如下图3-2所示。

图3-2 encoder和decoder结构示意图

其中,glu中的conv1d是一个kernel_size=1的卷积,主要目的是改变channel的数量,同时也可以在channel之间做特征的融合。

e

n

c

o

d

e

r

i

encoder_i

encoderi​的输入只有上一个

e

n

c

o

d

e

r

i

1

encoder_{i-1}

encoderi−1​的输出,

d

e

c

o

d

e

r

i

decoder_i

decoderi​的输入除了上一个

d

e

c

o

d

e

r

i

+

1

decoder_{i+1}

decoderi+1​的输入之外,还有

e

n

c

o

d

e

r

i

encoder_i

encoderi​的输出。

d

e

c

o

d

e

r

i

decoder_i

decoderi​利用

e

n

c

o

d

e

r

i

encoder_i

encoderi​这样的操作也被称作skip connection。

e

n

c

o

d

e

r

L

encoder_L

encoderL​的最终输出会经过一个LSTM之后再进入

d

e

c

o

d

e

r

L

decoder_L

decoderL​。记

e

n

c

o

d

e

r

L

encoder_L

encoderL​的输出为

z

z

z,

d

e

c

o

d

e

r

L

decoder_L

decoderL​的输入特征为

z

^

\hat{z}

z^,则有

z

^

=

L

S

T

M

(

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表示了目标信号和模型输出信号之间的差值,表示为

L

w

a

v

e

f

o

r

m

=

1

T

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^是模型输出的信号,

T

T

T为采样点的数量。

不过在实际的代码实现中,这个loss可以是L1 loss,也可以是L2 loss,还可以是smooth L1 loss。

多尺度的STFT loss是指用不同的fft bins,hop sizes和window lengths的到的各个STFT下的loss,这也是为了让模型不过拟合于某一种参数下的STFT变换。

L

s

t

f

t

=

1

T

i

=

1

M

L

s

t

f

t

(

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=1∑M​Lstft(i)​(x,x^)(3-4)

其中,每个

L

s

t

f

t

(

i

)

(

x

,

x

^

)

L_{stft}^{(i)}(x, \hat{x})

Lstft(i)​(x,x^)由spectral convergence (sc) loss和magnitude loss组成。

L

s

t

f

t

(

i

)

(

x

,

x

^

)

=

L

s

c

(

i

)

(

x

,

x

^

)

+

L

m

a

g

(

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为

L

s

c

(

i

)

(

x

,

x

^

)

=

S

T

F

T

(

i

)

(

x

)

S

T

F

T

(

i

)

(

x

^

)

F

S

T

F

T

(

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为

L

m

a

g

(

i

)

(

x

,

x

^

)

=

l

o

g

S

T

F

T

(

i

)

(

x

)

l

o

g

S

T

F

T

(

i

)

(

x

^

)

1

L_{mag}^{(i)}(\bold{x}, \bold{\hat{x}}) = || log|STFT^{(i)}(\bold{x})| - log|STFT^{(i)}(\bold{}\hat{x})| ||_1

Lmag(i)​(x,x^)=∣∣log∣STFT(i)(x)∣−log∣STFT(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

相关养生推荐

如何讓陶瓷食器歷久彌新?七個必學的保養技巧
亚洲365bet比分

如何讓陶瓷食器歷久彌新?七個必學的保養技巧

📅 09-18 👁️ 6906
英文双引号怎么打出来?英文单双引号的用法
bat365官方网站

英文双引号怎么打出来?英文单双引号的用法

📅 08-28 👁️ 6220
王源的家庭背景 王俊凯父母家庭背景
亚洲365bet比分

王源的家庭背景 王俊凯父母家庭背景

📅 08-20 👁️ 9658
怎么用办公软件做字卡
亚洲365bet比分

怎么用办公软件做字卡

📅 07-21 👁️ 7574