天天看点

【转载】Kaldi thchs30手札(一)特征提取阶段(line 0-33)thchs30 的运行生成text wav.scp utt2pk spk2utt提取MFCC特征倒谱均值方差归一化(CMVN)滤波器组(FilterBank, FBank)语音感知线性预测(Perceptual Linear Prediction,PLP)特征级声道长度归一化(VTLN)Hanmming窗

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/pelhans/article/details/80002009

Kaldi是一个语音识别工具包,基于C++并遵循Apache v2.0协议。它包含语音信号处理、声学模型训练、解码等一系列工具,同时内部还带有各种语言的源代码实例。非常强大。

thchs30 的运行

程序到手,当然是先跑起来看看长什么样子,功能是什么。所以本部分先介绍Kaldi的运行。

1) 从github上Clone 仓库: git clone https://github.com/kaldi-asr/kaldi

2) 进入Kaldi目录后查看INSTALL文件,它会告诉你怎么安装Kaldi,需要注意的是 extras/check_dependencies.sh这里检查依赖,一定要确保满足相关要求,否则后面会很麻烦。编译的话根据自己的CPU数目选择make -j n。

3) 下载语音预料,thchs30的语料是公开的,可以在http://www.openslr.org/18/ 里下载并解压。

4) Kaldi安装好后就可以进入到egs/thchs30/s5/目录了。首先加入你是本地运行的话,需要讲cmd.sh文件内的queue.pl替换为run.pl。然后再修改第11行的thchs= 的路径为你自己存放语音语料的路径,到此Kaldi程序就可以运行了。后面DNN那里可能会出一点问题,这个后面再说。

生成text wav.scp utt2pk spk2utt

负责此处的是run.sh中的第22行,即:

local/thchs-data_prep.sh $H $thchs/data_thchs3 || exit ;           
  • 1

其中H是当前目录名,H是当前目录名,thchs指的是语音语料库位置。这俩是thchs-30_data_prep.sh 脚本的参数。(这个local我一开始以为是bash里面的local命令,想了半天也没有想懂,后来才发现这货就一文件夹。。。)

该程序的答题执行流程是读取语料库中的{train, dev, test}文件夹下的.wav文件和.trn文件。利用wav文件的名字和所在路径生成wav.scp文件,利用wav.trn文件中的第1行和第3行生成word.txt 和phone.txt。这里的word和phone都是直接从文件中读取的。同时由于此处没有说话人识别,因此对于utt2spk(语段到说话人)和spk2utt(说话人到语段)里的内容都是两列相同的wav文件名。

提取MFCC特征

对应代码为:

steps/make_mfcc.sh --nj $n --cmd "$train_cmd" data/mfcc/$x exp/make_mfcc/$x mfcc/$x || exit ;           
  • 1

其中n是make的cpu线程数目,n是make的cpu线程数目,train_cmd 是cmd.sh里的train_cmd变量,$x就是循环里的{train,dev,test}了。

关于梅尔倒谱系数(MFCC)我们之前讲过,在Kaldi里它本身设置了合理的默认值,同事保留了一部分用户最有可能想调整的选项,如梅尔滤波器的个数,最大和最小截止频率等等.它通常需要读取wav文件或.pcm文件,假如数据源不是wav文件,我们就得使用工具来转化,Kaldi中有的sph2pipe工具能满足一般的情况.

命令工具 compute-mfcc-feats用来计算MFCC特征,若直接运行不带参数的话就会给出一个参数列表.改程序需要两个参数,rspecifier是用来度.wav数据, wspecifier是用来写特征的(就是r 和w啦).典型的用法是,将数据写入一个大的”archive”文件,也写到一个”scp”文件以便随机读取.

MFCC的计算由Mfcc类型的对象完成,它有Compute()函数可以根据波形计算特征.一个完整的MFCC计算如下:

  • 1) 计算出一个文件中帧的数目(通常帧长25ms,帧移10ms)
  • 2) 对每一帧提取数据,可选做Dithering,预加重和去除直流偏移,还可以和加窗函数想成(此处支持多种选项,如Hanmming 窗).
  • 3)计算该点能量(假如用对数能量则没有C0C0).
  • 4) 做快速傅里叶变换(FFT)并计算功率谱.
  • 5)计算每个梅尔滤波器的能量,如23个部分重叠的三角滤波器,其中心在梅尔频域等间距.
  • 6) 计算对数能量病作宇轩变换,根据要求保留系数(如13个).
  • 7) 选做倒谱变;它仅仅是比例变换,确保系数在合理范围内.

上下截止频率根据三角滤波器界定,由选项–low-freq和–high-freq控制,通常分别设置为0Hz和奈奎斯特频率附近,如对16kHz采样的语音设置为–low-freq=20 和 –high-freq=7800。

Kaldi的特征和HTK的特征在很多方面不同,但是几乎所有这些不同归结于有不同的默认值。用选项–htk-compat=true并正确设置参数,能得到同HTK非常接近的特征。一个可能重要的选项是我们不支持能量最大归一化。这是因为Kaldi希望能把无状态方式应用到归一化方法,且希望从原理上计算一帧帧特征仍能给出相同结果。但是程序compute-mfcc-feats里有–subtract-mean选项来提取特征的均值。对每个语音做此操作;每个说话人可以有不同的方式来提取特征均值。(如compute_cmvn_stats.sh,表示倒谱均值和方差归一化)。

倒谱均值方差归一化(CMVN)

代码为:

steps/compute_cmvn_stats.sh data/mfcc/$x exp/mfcc_cmvn/$x mfcc/$x || exit ;           
  • 1

在实际情况下,受不同麦克风及音频通道的影响,会导致相同音素的特征差别比较大,通过CMVN可以得到均值为0,方差为1的标准特征。均值方差可以以一段语音为单位计算,但更好的是在一个较大的数据及上进行计算,这样识别效果会更加robustness。Kaldi中计算均值和方差的代码在compute-cmvn-stats.cc, 归一化在apply-cmvn.cc。

滤波器组(FilterBank, FBank)

人耳对声音频谱的响应是非线性的,经验表明:如果我们能够设计一种前端处理算法,以类似于人耳的方式对音频进行处理,可以提高语音识别的性能。FilterBank分析就是这样的一种算法。FBank特征提取要在预处理之后进行,这时语音已经分帧,我们需要逐帧提取FBank特征。

语音感知线性预测(Perceptual Linear Prediction,PLP)

PLP和MFCC一样都是一种声学特征,且它们的前期计算工作也是一样的。PLP在Kaldi的手册中没有找到,此处再用HTK手册中的叙述。As implemented in HTK the PLP feature extraction is based on the standard mel-frequency

filterbank (possibly warped). The mel filterbank coefficients are weighted by an equal-loudness

curve and then compressed by taking the cubic root. 5 From the resulting auditory spectrum LP

coefficients are estimated which are then converted to cepstral coefficients in the normal way (see above).

特征级声道长度归一化(VTLN)

程序compute-mfcc-feats和compute-plp-feats**接收一个VTLN弯折因子选项。在目前的脚本中,这仅用作线性版的VTLN的初始化线性转换的一种方法。**VTLN通过移动三角频率箱的中心频率的位置来实现。移动频率箱的弯折函数是一个在频域空间分段线性的函数。为理解它,记住以下数量关系:

0 <= low-freq <=vtln-low < vtln-high < high-freq <= nyquist

此处,low-freq和high-freq分别是用于标准MFCC或PLP计算的最低和最高频率(忽略更低和更高的频率)。vtln-low和vtln-high是用于VTLN的截止频率,它们的功能是确保所有梅尔滤波器有合适的宽度。

Kaldi实现的VTLN弯折函数是一个分段线性函数,三个部分映射区间[low-freq,high-freq]至[low-freq, high-freq]。记弯折函数为W(f),f是频率。中段映射f到f/scale,scale是VTLN弯折因子(通常范围为0.8到1.2)。x轴上低段和中段的连接点是满足min(f,W(f)) = vtln-low的f点。x轴上中段和高端的连接点是满足max(f, W(f)) = vtln-high的f点。要求低段和高段的斜率和偏移是连续的且W(low-freq)=low-freq,

W(high-freq)=high-freq。这个弯折函数和HTK的不同;HTK的版本中,”vtln-low”和”vtln-high”的数量关系是x轴上可以不连续的点,这意味着变量”vtln-high”必须基于弯折因子的可能范围的先验知识谨慎选择(否则梅尔滤波器可能为空)。

一个合理的设置如下(以16kHz采样的语音为例);注意这反映的是我们理解的合理值,并非任何非常细致的调试实验的结果。

【转载】Kaldi thchs30手札(一)特征提取阶段(line 0-33)thchs30 的运行生成text wav.scp utt2pk spk2utt提取MFCC特征倒谱均值方差归一化(CMVN)滤波器组(FilterBank, FBank)语音感知线性预测(Perceptual Linear Prediction,PLP)特征级声道长度归一化(VTLN)Hanmming窗

Hanmming窗

前面说过,我们要处理的语音信号一般在10ms到30ms之间,我们可以把它看作是平稳的。为了处理语音信号,我们要对语音信号进行分段,即每次仅处理一段数据。

那怎么能够获取一段数据呢?一种方式就是构造一个函数。这个函数在某一区间有非零值,而在其余区间皆为0.汉明窗就是这样的一种函数。它主要部分的形状像sin(x)在0到pi区间的形状,而其余部分都是0.这样的函数乘上其他任何一个函数f,f只有一部分有非零值。

为什么汉明窗这样取呢?因为之后我们会对汉明窗中的数据进行FFT,它假设一个窗内的信号是代表一个周期的信号。(也就是说窗的左端和右端应该大致能连在一起)而通常一小段音频数据没有明显的周期性,加上汉明窗后,数据形状就有点周期的感觉了。

因为加上汉明窗,只有中间的数据体现出来了,两边的数据信息丢失了,所以等会移窗的时候,只会移1/3或1/2窗,这样被前一帧或二帧丢失的数据又重新得到了体现。

简单的说汉明窗就是个函数,它的形状像窗,所以类似的函数都叫做窗函数。

继续阅读