乐趣区

关于音频:你真的懂语音特征吗

摘要: 本文指在具体介绍语音转化声学特色的过程,并具体介绍不同声学特色在不同模型中的利用。

本文分享自华为云社区《你真的懂语音特色背地的原理吗?》,作者:白马过平川。

语音数据常被用于人工智能工作,但语音数据往往不能像图像工作那样间接输出到模型中训练,其在长时域上没有显著的特色变动,很难学习到语音数据的特色,加之语音的时域数据通常由 16K 采样率形成,即 1 秒 16000 个采样点,间接输出时域采样点训练数据量大且很难有训练出实际效果。因而语音工作通常是将语音数据转化为声学特色作为模型的输出或者输入。因而本文指在具体介绍语音转化声学特色的过程,并具体介绍不同声学特色在不同模型中的利用。

首先搞清语音是怎么产生的对于咱们了解语音有很大帮忙。人通过声道产生声音,声道的形态决定了收回怎么的声音。声道的形态包含舌头,牙齿等。如果能够精确的晓得这个形态,那么咱们就能够对产生的音素进行精确的形容。声道的形态通常由语音短时功率谱的包络中显示进去。那如何失去功率谱,或者在功率谱的根底上失去频谱包络,便是能够或得语音的特色。

一、时域图

图 1:音频的时域图

时域图中,语音信号间接用它的工夫波形示意进去,上图 1 是用 Adobe Audition 关上的音频的时域图,示意这段语音波形时量化精度是 16bit,从图中能够失去各个音的起始地位,但很难看出更加有用的信息。但如果咱们将其放大到 100ms 的场景下,能够失去下图 2 所示的图像。

图 2:音频的短时时域图

从上图咱们能够看出在短时的的工夫维度上,语音时域波形是存在肯定的周期的,不同的发音往往对应着不同的周期的变动,因而在短时域上咱们能够将波形通过傅里叶变换转化为频域图,察看音频的周期个性,从而获取有用的音频特色。

短时傅里叶变换(STFT)是最经典的时频域分析方法。所谓短时傅里叶变换,顾名思义,是对短时的信号做傅里叶变动。因为语音波形只有在短时域上才出现肯定周期性,因而应用的短时傅里叶变换能够更为精确的察看语音在频域上的变动。傅里叶变动实现的示意图如下:

图 3:傅里叶变换的从时域转化为频域的示意图

上图显示的了如何通过傅里叶变动将时域波形转化为频域谱图的过程,但在因为自身傅里叶变动的算法复杂度为 O(N^2),难以利用, 在计算机中利用中更多的是应用疾速傅里叶变换(FFT)。其中转化的推理证实参考知乎

二、获取音频特色

由上述一能够晓得获取音频的频域特色的具体方法原理,那如何操作将原始音频转化为模型训练的音频特色,其中任然须要很多辅助操作。具体流程如下图 4 所示:

图 4:音频转化为音频特色的流程图

(1) 预减轻

预减轻解决其实是将语音信号通过一个高通滤波器:

其中 \muμ,咱们通常取为 0.97。预减轻的目标是晋升高频局部,使信号的频谱变得平坦,放弃在低频到高频的整个频带中,能用同样的信噪比求频谱。同时,也是为了打消产生过程中声带和嘴唇的效应,来弥补语音信号受到发音零碎所克制的高频局部,也为了突出高频的共振峰。

pre_emphasis = 0.97
emphasized_signal = np.append(original_signal[0], original_signal[1:] - pre_emphasis * original_signal[:-1])

(2) 分帧

因为傅里叶变换要求输出信号是安稳的,不安稳的信号做傅里叶变换是没有什么意义的。由上述咱们能够晓得语音在长时间上是不稳固的,在短时上稳固是有肯定的周期性的,即语音在宏观上来看是不安稳的,你的嘴巴一动,信号的特色就变了。然而从宏观上来看,在比拟短的工夫内,嘴巴动得是没有那么快的,语音信号就能够看成安稳的,就能够截取进去做傅里叶变换了,因而要进行分帧的操作,即截取短时的语音片段。

那么一帧有多长呢?帧长要满足两个条件:

  • 从宏观上看,它必须足够短来保障帧内信号是安稳的。后面说过,口型的变动是导致信号不安稳的起因,所以在一帧的期间内口型不能有显著变动,即一帧的长度该当小于一个音素的长度。失常语速下,音素的持续时间大概是 50~200 毫秒,所以帧长个别取为小于 50 毫秒。
  • 从宏观上来看,它又必须包含足够多的振动周期,因为傅里叶变换是要剖析频率的,只有反复足够屡次能力剖析频率。语音的基频,男声在 100 赫兹左右,女声在 200 赫兹左右,换算成周期就是 10 ms 和 5 ms。既然一帧要蕴含多个周期,所以个别取至多 20 毫秒。

留神: 分帧的截取并不是严格的分片段,而是有一个帧移的概念,即确定好帧窗口的大小,每次依照帧移大小挪动,截取短时音频片段,通常帧移的大小为 5 -10ms, 窗口的大小通常为帧移的 2 - 3 倍即 20-30ms。之所以设置帧移的形式次要是为了后续加窗的操作。
具体分帧的流程如下所示:

图 5:音频分帧示意图

(3) 加窗

取出来的一帧信号,在做傅里叶变换之前,要先进行「加窗」的操作,即与一个「窗函数」相乘,如下图所示:

图 5:音频加窗示意图

加窗的目标是让一帧信号的幅度在两端突变到 0。突变对傅里叶变换有益处,能够让频谱上的各个峰更细,不容易糊在一起(术语叫做加重频谱透露),加窗的代价是一帧信号两端的局部被减弱了,没有像地方的局部那样失去器重。补救的方法是,帧不要背靠背地截取,而是互相重叠一部分。相邻两帧的起始地位的时间差叫做帧移。

通常咱们应用汉明窗进行加窗,将分帧后的每一帧乘以汉明窗,以减少帧左端和右端的连续性。假如分帧后的信号为 S(n), n=0,1,…,N-1, NS(n),n=0,1,…,N−1,N 为帧的大小,那么乘上汉明窗后:

实现的代码:

# 简略的汉明窗构建
N = 200
x = np.arange(N)
y = 0.54 * np.ones(N) - 0.46 * np.cos(2*np.pi*x/(N-1))

# 加汉明窗
frames *= np.hamming(frame_length)

(4)疾速傅里叶变换 FFT

因为信号在时域上的变换通常很难看出信号的个性,所以通常将它转换为频域上的能量散布来察看,不同的能量散布,就能代表不同语音的个性。在乘上汉明窗后,每帧还必须再通过疾速傅里叶变换以失去在频谱上的能量散布。对分帧加窗后的各帧信号进行疾速傅里叶变换失去各帧的频谱。疾速傅里叶变换的实现原理曾经在后面介绍过,这里不过多介绍。具体的推理和实现推介参考知乎 FFT(https://zhuanlan.zhihu.com/p/…

留神: 这里音频通过疾速傅里叶变换返回的是复数,其中实部示意的频率的振幅,虚部示意的是频率的相位。

蕴含 FFT 函数的库有很多,简略列举几个:

import librosa
import torch
import scipy

x_stft = librosa.stft(wav, n_fft=fft_size, hop_length=hop_size,win_length=win_length)
x_stft = torch.stft(wav, n_fft=fft_size, hop_length=hop_size, win_length=win_size)
x_stft = scipy.fftpack.fft(wav)

失去音频的振幅和相位谱,须要对频谱取模平方失去语音信号的功率谱,也就是语音合成上常说的线性频谱。

(5)Mel 频谱

人耳能听到的频率范畴是 20-20000Hz,但人耳对 Hz 这种标度单位并不是线性感知关系。例如如果咱们适应了 1000Hz 的音调,如果把音调频率进步到 2000Hz,咱们的耳朵只能觉察到频率进步了一点点,基本觉察不到频率进步了一倍。因而能够将一般的频率标度转化为梅尔频率标度,使其更合乎人们的听觉感知,这种映射关系如下式所示:

在计算机中,线性坐标到梅尔坐标的变换,通常应用带通滤波器来实现,个别罕用的应用三角带通滤波器,应用三角带通滤波器有两个次要作用:对频谱进行平滑化,并打消谐波的作用,突显原先语音的共振峰。其中三角带通滤波器结构的示意图如下所示:

图 6:三角带通滤波器结构示意图

这是非均等的三角带通滤波器结构示意图,因为人类对高频的能量感知较弱,因而低频的保留能量要显著大与高频。其中三角带通滤波器的结构代码如下:

low_freq_mel = 0
high_freq_mel = (2595 * numpy.log10(1 + (sample_rate / 2) / 700))  # Convert Hz to Mel
mel_points = numpy.linspace(low_freq_mel, high_freq_mel, nfilt + 2)  # Equally spaced in Mel scale
hz_points = (700 * (10**(mel_points / 2595) - 1))  # Convert Mel to Hz
bin = numpy.floor((NFFT + 1) * hz_points / sample_rate)
fbank = numpy.zeros((nfilt, int(numpy.floor(NFFT / 2 + 1))))

for m in range(1, nfilt + 1):
    f_m_minus = int(bin[m - 1])   # left
    f_m = int(bin[m])             # center
    f_m_plus = int(bin[m + 1])    # right

    for k in range(f_m_minus, f_m):
        fbank[m - 1, k] = (k - bin[m - 1]) / (bin[m] - bin[m - 1])
    for k in range(f_m, f_m_plus):
        fbank[m - 1, k] = (bin[m + 1] - k) / (bin[m + 1] - bin[m])
filter_banks = numpy.dot(pow_frames, fbank.T)
filter_banks = numpy.where(filter_banks == 0, numpy.finfo(float).eps, filter_banks)  # Numerical Stability
filter_banks = 20 * numpy.log10(filter_banks)  # dB

而后只需将线性谱乘以三角带通滤波器,并取对数就能失去 mel 频谱。通常语音合成的工作的音频特征提取个别就到这,mel 频谱作为音频特色根本满足了一些语音合成工作的需要。但在语音辨认中还须要再做一次离散余弦变换(DCT 变换),因为不同的 Mel 滤波器是有交加的,因而它们是相干的,咱们能够用 DCT 变换去掉这些相关性能够进步辨认的准确率,但在语音合成中须要保留这种相关性,所以只有辨认中须要做 DCT 变换。其中 DCT 变换的原理详解能够参考知乎 DCT(https://zhuanlan.zhihu.com/p/…

想理解更多的 AI 技术干货,欢送上华为云的 AI 专区,目前有 AI 编程 Python 等六大实战营供大家收费学习。(六大实战营 link:http://su.modelarts.club/qQB9)

点击关注,第一工夫理解华为云陈腐技术~

退出移动版