生成text wav.scp utt2pk spk2utt
负责此处的是run.sh中的第22行,即:
local/thchs-30_data_prep.sh $H $thchs/data_thchs30 || exit 1;
其中H是当前目录名,thchs指的是语音语料库位置。
该程序的执行流程是读取语料库中的{train, dev, test}文件夹下的.wav文件和.trn文件。利用wav文件的名字和所在路径生成wav.scp文件,利用wav.trn文件中的第1行和第3行生成word.txt和phone.txt。这里的word和phone都是直接从文件中读取的。同时由于此处没有说话人识别,因此对于utt2spk(语段到说话人)和spk2utt(说话人到语段)里的内容都是两列相同的wav文件名。
wav.scp
文件格式是:
<recording-id> <extended-filename>
extended-filename 可能是确切的文件名,或者是提取wav格式文件的命令。extended-filename 最后的管道符号意味着它将被解读成管道。如果分割文件不存在,那么wav.scp每行的第一个字符就是语音-id。wav.scp必须是单声道的,如果底层语音文件有多个声道,就必须有一个短命令在wav.scp中要用到来提取一个特殊的通道。
utt2pk
格式:
<utterance-id> <speaker-id>
语音-id 说话人-id
spk2utt
<spaker-id> <utterance-id>…
说话人-id 语音-id
提取MFCC特征
对应代码为:
steps/make_mfcc.sh --nj $n --cmd "$train_cmd" data/mfcc/$x exp/make_mfcc/$x mfcc/$x || exit 1;
其中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)计算该点能量(有则对数能量则没有则 C 0 C_0 C0).
- 4)做快速傅里叶变换(FFT)并计算功率谱.
- 5)计算每个梅尔滤波器的能量,如23个部分重叠的三角滤波器,其中心在梅尔频域等间距.
- 6)计算对数能量并作余弦变换,根据要求保留系数(如13个).
- 7)选做倒谱变;它仅仅是比例变换,确保系数在合理范围内.
上下截止频率根据三角滤波器界定,由选项–low-freq和–high-freq控制,通常分别设置为0Hz和奈奎斯特频率附近,如对16kHz采样的语音设置为–low-freq=20 和 –high-freq=7800。
倒谱均值方差归一化(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特征。
Hanmming窗
前面说过,我们要处理的语音信号一般在10ms到30ms之间,我们可以把它看作是平稳的。为了处理语音信号,我们要对语音信号进行分段,即每次仅处理一段数据。
那怎么能够获取一段数据呢?一种方式就是构造一个函数。这个函数在某一区间有非零值,而在其余区间皆为0.汉明窗就是这样的一种函数。它主要部分的形状像sin(x)在0到pi区间的形状,而其余部分都是0.这样的函数乘上其他任何一个函数f,f只有一部分有非零值。
为什么汉明窗这样取呢?因为之后我们会对汉明窗中的数据进行FFT,它假设一个窗内的信号是代表一个周期的信号。(也就是说窗的左端和右端应该大致能连在一起)而通常一小段音频数据没有明显的周期性,加上汉明窗后,数据形状就有点周期的感觉了。
因为加上汉明窗,只有中间的数据体现出来了,两边的数据信息丢失了,所以等会移窗的时候,只会移1/3或1/2窗,这样被前一帧或二帧丢失的数据又重新得到了体现。
简单的说汉明窗就是个函数,它的形状像窗,所以类似的函数都叫做窗函数。