#
#作者:韦访
#博客:https://blog.csdn.net/rookie_wei
#微信:1007895847
#添加微信的备注一下是CSDN的
#欢迎大家一起学习
#

1、概述

上一讲,我们用LSTM实现了分离歌曲中的人声和背景音乐的功能,这一讲,我们继续学习LSTM的应用,来实现一个简单的语音识别的功能。

 

环境配置:

操作系统:Win10 64位

显卡:GTX 1080ti

Python:Python3.7

TensorFlow:1.15.0

2、与传统语音识别的对比

传统的语音识别是基于语音学的方法,通常包含拼写、声学和语音模型等单独组件。训练模型的语料除了标注具体的文字外。还要标注按时间对应的音素,这就需要大量的人工成本。

而使用神经网络的语音识别就变得简单多了,通过能进行时序分类的连续时间分类目标函数(CTC),计算多个标签序列的概率,而序列是语音样本中所有可能的对应文字的集合。然后把预测结果跟实际比较,计算误差,不断更新网络权重。这样就丢弃音素的概念,就省了大量人工标注的成本,也不需要语言模型,只要有足够的样本,就可以训练各种语言的语音识别了。

3、下载并分析数据集

我们先来做中文的语音识别,使用清华大学公开的语料库样本thchs30,以前的下载地址

http://data.cslt.org/thchs30/zip/wav.tgz

http://data.cslt.org/thchs30/zip/doc.tgz

http://data.cslt.org/thchs30/zip/lm.tgz

已经无法访问了。

新的下载地址为:http://www.openslr.org/18/

百度网盘链接: https://pan.baidu.com/s/1v7yjVqRpmOivbpigyijsEA  密码: w81c

下载data_thchs30,

下载完后,解压,根据上图的介绍,data_thchs30文件夹包含的是语音数据和其翻译,那我们来看看这个文件夹吧,

文件夹的内容如上图,先打开README.TXT文件看看它说了什么,

 

上面介绍这个数据集的历史和作者之类的我们就不看了,看看上图的内容,data文件夹下,“.wav”文件保存的是音频文件,”.wav.trn”保存的是翻译文件,然后,train/dev/test文件夹下的文件是将data文件夹下的文件分割过来的,这3个文件夹具体哪个文件夹分了多少文件,下面有个表显示了。这里有个词“symlinks”,链接?难道都是链接文件?不可能吧?去看看再说,打开data文件夹,内容如下图所示,

就那第一个文件来看吧,播放A2_0.wav文件,是一段音频文件,再打开A2_0.wav.trn文件,

共有3行,我为了方便看,就把字体放大了,再用红色的框框起来,框起来的部分就是同一行的内容,

第一行的内容就是A2_0.wav文件读的文字。

第二行是第一行的拼音,后面的数字其实就是声调。

第三行我就不知道是什么东西了。

不知道没关系,因为上面说了,我们用神经网络的方法来做语音识别只需要知道音频文件和对应的翻译就可以了。

再来看看train文件夹,

跟data文件夹下的文件名一样,只不过这里总共只有20000个文件,而data文件夹下有26776个文件,可以猜测另外的6776个文件应该是放到dev和test文件夹下了。打开A2_0.wav文件听听,跟data下的A2_0.wav文件一样的。再打开A2_0.wav.trn文件看看,

只有一个路径,就是data文件夹下的A2_0.wav.trn文件,所以这个“symlinks”的意思我们就明白了。

lm_word文件夹和lm_phone文件夹是什么东西我也不知道,不过我们这里用不着,就不管了。好了,知道数据集的结构以后,我们接着就来读取样本了。

4、读取样本

训练的话,我们就用train文件夹下的数据来训练,音频文件可以直接使用train文件夹下的,翻译的话,就得用data文件夹下的了,还好是有规律的,音频文件是XX.wav,对应的翻译文件则是XX.wav.trn,所以我们先找出所有的train文件夹下的音频文件,再找data文件夹下音频文件名+”.trn”后缀的文件就是翻译文件,取翻译文件的第一行,就是翻译内容了,将音频文件和翻译的内容一一对应,加载到内存中,方便我们进一步使用。

第一步,先来实现获取指定文件夹下所有WAV文件的函数,代码如下,

# 获取文件夹下所有的WAV文件
def get_wavs(wav_path):
    wavs = []
    for (dirpath, _, filenames) in os.walk(wav_path):
        for filename in filenames:
            if filename.endswith('.wav') or filename.endswith('.WAV'):
                # print(filename)
                filename_path = os.path.join(dirpath, filename)
                # print(filename_path)
                wavs.append(filename_path)
    return wavs

第二步,根据上面获取的WAV文件,获取其指定文件夹下对应的翻译文件里的第一行,即翻译文字,代码如下,

# 获取wav文件对应的翻译文字
def get_tran_texts(wavs, tran_path):
    tran_texts = []
    for wav_file in wavs:
        (_, wav_filename) = os.path.split(wav_file)
        tran_file = os.path.join(tran_path, wav_filename + '.trn')
        # print(tran_file)
        if os.path.exists(tran_file) is False:
            return None

        with open(tran_file, encoding='utf-8') as fd:        
            text = fd.readline()
            tran_texts.append(text.split('\n')[0])
        
    return tran_texts

将上面两个函数整合成一个函数,方便我们调用,代码如下,

# 获取wav和对应的翻译文字
def get_wavs_and_tran_texts(wav_path, tran_path):
    wavs = get_wavs(wav_path)
    tran_texts = get_tran_texts(wavs, tran_path)
    print(wavs[0], tran_texts[0])
    # print(len(wavs), len(tran_texts))
    return wavs, tran_texts

测试一下看看结果对不对,代码如下,

wav_path = 'dataset/data_thchs30/train'
tran_path = 'dataset/data_thchs30/data'
wavs, labels = get_wavs_and_tran_texts(wav_path, tran_path)

运行结果,

dataset/data_thchs30/train\A11_0.wav 绿 是 阳春 烟 景 大块 文章 的 底色 四月 的 林 峦 更是 绿 得 鲜活 秀媚 诗意 盎然

 

打开data_thchs30/data/A11_0.wav.trn文件看看,第一行是否跟我们打印的内容一样,

一样,说明上面的函数没问题了。读取样本这一步就算完成了。

5、梅尔频率倒谱系数(MFCC)

在继续之前,我们先来了解一下MFCC,因为为了让电脑识别音频数据,我们必须先将音频数据从时域转到频域,然后提取特征,而MFCC是语音识别中广泛使用的特征。

下面先了解一下语音信号处理的一些知识。

5.1、声谱图(Spectrogram)

 如上图所示,一段语音被分成很多帧,每帧经过一个快速傅里叶变换(FFT)得到一个频谱,频谱反映的是信号频率与能量的关系。在实际应用中,一般有三种频谱图:线性振幅谱、对数振幅谱、自功率谱。对数振幅谱对各谱线的振幅都做了对数计算,其目的是使振幅较低的成份相对振幅较高的成份得以拉高,以便观察掩盖在低振幅噪声中的周期信号,所以其纵坐标的单位是分贝(dB)。

如上图所示,我们先将语音信号的某一帧频谱用坐标表示,注意此时横轴已经是频率了,纵轴是振幅,然后将坐标旋转90度,得到如下图所示,

接着,将振幅映射到一个灰度水平线,其值为0-255,0表示黑,255表示白,振幅越大,对应的区域越黑,如下图所示,

这样就增加了时间的维度,就可以显示一段语音而不是一帧语音的频谱,

我们就会得到一个随时间变化的频谱图,这个就是描述语音信号的声谱图,如下图所示。

如上图所示,很黑的地方就是频谱图中的峰值(共振峰)。为什么要这样搞呢?因为在声谱图中能更好的观察音素和它的特征。

另外,通过观察共振峰和它们的跃迁可以更好地识别声音。

隐马尔科夫模型(Hidden Markov Models)就是隐含地对声谱图进行建模以达到好的识别性能。还有一个作用就是它可以直观的评估TTS系统(text to speech)的好坏,直接对比合成的语音和自然的语音声谱图的匹配度即可。

5.2、倒谱分析(Cepstrum Analysis)

 

上图是一个语音的频谱图,峰值表示语音的主要频率成分,称为共振峰,共振峰携带了声音的辨识属性(相当于人的身份证),用它就可以识别不同的声音,这个属性特别重要,所以我们要把它提取出来。

我们不仅要提取出共振峰的位置,还得提取它们的转变过程,也就是频谱的包络(Spectral Envelope)。这个包络就是一条连接这些共振峰的平滑曲线,如下图所示,

我们可以理解为,原始频谱由包络和频谱的细节组成,如果我们将这两部分分离,就可以得到包络了,如下图所示,

首先,画出伪频率坐标,如下图所示,

伪频率坐标上分为低频率区域和高频率区域,通过IFFT将包络和频谱细节转换到伪频率坐标上,

首先,将包络当成是一个每秒4个周期的正弦波,这样在伪频率坐标轴上给出一个4Hz的峰值。

同理,将频谱细节看成一个每秒100个周期的正弦波,这样在伪频率坐标轴上给出一个100Hz的峰值。

把它俩叠加在一起,就是原始频谱信号了,

5.3、梅尔频率分析(Mel-Frequency Analysis)

通过上面的步骤,我们可以得到一段语音的频谱包络,但是,对于人类听觉感知的实验表明,人类听觉的感知只聚焦在某些特定的区域,而不是整个频谱包络。

梅尔频率分析就是基于人类听觉感知实验的,实验观测发现人耳就像一个滤波器组,它只关注某些特定的频率分量。但是这些滤波器在频率坐标轴上却不是统一分布的,在低频区域有很多的滤波器,它们分布比较密集,在高频区域,分布的比较稀疏,如下图所示,

5.4、梅尔频率倒谱系数(MFCC)

提取MFCC的大致过程如上图所示。

 1)先对语音进行预减轻、分帧和加窗;

 2)对每个短时分析窗,通过FFT失掉对应的频谱;

 3)将上面的频谱通过Mel滤波器组失掉Mel频谱;

 4)在Mel频谱上面进行倒谱分析(取对数,做逆变换,现实逆变换一般是通过DCT离散余弦变换来实现,取DCT后的第2个到第13个系数作为MFCC系数),取得Mel频率倒谱系数MFCC,这个MFCC就是这帧语音的特征;

到这里,语音信号就能通过一系列倒谱向量来描述了,每个向量就是每帧的MFCC特征向量。

注:上述MFCC知识点参考自博客:https://blog.csdn.net/zouxy09/article/details/9156785/

文档:http://www.speech.cs.cmu.edu/15-492/slides/03_mfcc.pdf

感谢博主们的贡献。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐