基于HTK的语音拨号系统

来源:互联网 发布:python 参数估计 编辑:程序博客网 时间:2024/05/22 03:40
转自Veket http://blog.csdn.net/chenah/article/details/6568346

目标:

该系统能够识别连续说出的数字串和若干组姓名。建模是针对子词(sub-word,eg..音素),具有一定的可扩充性。当加入一个新名字时,只需修改发音词典和任务语法即可。模型为连续混合高斯输出,运用语音决策树聚类形成的绑定状态式三音素。

内容:

1.数据准备

(1)      任务语法定义

(2)      字典定义

(3)      录制语音数据

(4)      标注数据,得到真值文件

(5)      数据特征的提取

2.创建单音素HMM模型

(6)      一致初始化法创建单音素模型

 

(7)      修补哑音素模型

(8)      重新校正数据

3.创建绑定状态的三音素HMM模型

(9)      得到三音素HMM

(10)  绑定三音素

4.识别器评估

(11)验证测试结果

步骤:

1.数据准备

需要录制训练数据和测试数据。为了进行校准,还需要数据的标注文本。这里用任务语法(task grammar)产生真值文本(ground truth).为了处理训练数据,需要定义一个语音集合和一个字典用以涵盖训练和测试数据中涉及的单词。

(1)      任务语法定义

任务语法以包含变量的正则表达式形式定义,存储在文件gram(手工制作,在Notepad++或UltraEdit环境下进行,最后要空一行)里:

上面的语法是高层表示,必须通过HParse转换成HTK的底层表示。

运行指令:HParse gram wdnet

底层表示存于文件wdnet(HParse工具生成 )中。

(2)      字典定义

利用BEEP语音词典(现成的),除去其中的重音符。

在每个发音后加入sp(short pause).如果有哑音标志,就用MP命令把sil和sp合并成sil,这些处理命令放在global.ded(手工制作)的脚本中。

文件wlist(此系统由于涉及的单词较少,于是手工制作即可)是出现在任务语法中的所有单词的有序列表。

       文件names是专有人名的发音(手工制作,包括SEND-START,SENT-END)。

       执行HDMan:

HDMan -m -w lists/wlist -g global.ded  -n lists/monophones0 -l dlog dict/dict1  dict/beep dict/names

生成的文件monophones0是用到的音素列表(包括sp),生成的dlog是参数文件,其中包含生成的字典dict1的相关统计信息,还会提示是否丢失单词。生成的与任务相关的发音词典dict1,需要手工修改,为SENT-END和SENT-START加上无输出标志。

为了避免在dlog里出现warnning,可在names和beep同一目录下分别建立同名的编辑脚本,内容为空即可。

(3)      录制语音数据

HSGen工具可以生成符合task grammar 的句子,用来指导录音:

HSGen -l -n 10 wdnet dict/dict1>labels/trainprompts

HSGen -l -n 10 wdnet dict/dict1>labels/testprompts

       根据上述生成的指令文件,录制相应的10个训练用语音数据文件和10个测试用语音数据文件。一个录制例子如下:

HSLab ./data/Train/speech/S0001

(4)      标注数据,得到真值文件

perl脚本prompts2mlf(现成的)可以把录音文本截成单词级真值文件trainwords_2.mlf,testwords_2.mlf:

perl scripts/prompts2mlf labels/trainwords_2.mlf labels/trainprompts

perl scripts/prompts2mlf labels/testwords_2.mlf labels/testprompts

注:将生成的文件trainwords_2.mlf(testwords_2.mlf) 按trainwords_1.mlf(testwords_1.mlf) 的格式"*/S0*.lab"添加到其文件末尾,并保存为trainwords.mlf(testwords.mlf)

标注编辑器HLEd 可把单词级真值文本(word level MLF)转成音素级真值文本(phone level MLF)phones0.mlf:

HLEd -l * -d dict/dict1 -i labels/phones0.mlf mkphones0.led labels/trainwords.mlf

编辑脚本mkphones0.led 的内容如下:

其中EX 命令表示按照字典dict1 进行展开,IS 表示在每个话语的前后插入标志,DE 一行表示phones0.mlf 中单词间不用sp 隔开。

(5)  数据的特征提取

这里所用特征为MFCC。工具HCopy 可以实现提取特征的工作。

HCopy -T 1 -C config/config1 -S codetr.scp

 

其中,配置文件config1要设置转换参数(红色标出),config内容如下:

# Coding parameters

    TARGETKIND = MFCC_0_D_A           //目标文件参数类型

    TARGETRATE = 100000.0               //目标速率,100帧/秒

    SOURCEFORMAT = WAV               //源文件格式

    SAVECOMPRESSED = T                //以压缩的方式存储

    SAVEWITHCRC = T                    //附加校验和到输出参数中

    ZMEANSOURCE=TRUE

    SOURCERATE=208                    //源文件的速率

    WINDOWSIZE = 250000.0              //以25ms为一帧进行分帧处理

    USEHAMMING = T                    //采用汉明窗,进行加窗处理

    PREEMCOEF = 0.97                   //预加重系数

    NUMCHANS = 26                     //26组滤波器

    CEPLIFTER = 22                      //倒谱滤波系数

    NUMCEPS = 12                       //参数个数

    ENORMALISE = F                    //对log能量不进行归一化

 

实现该命令所需的脚本文件codetr.scp可采用如下方式生成:在DOS环境下进入到wav文件所在路径,用dir/b/s > wav.scp指令将所有的wav文件名写入到wav.scp文件中(注意删除多出的一行),然后在Notepad++中构造下图所示的文件, 存为coder.scp。(注:生成的wav.scp中的文件路径是绝对路径,可以手动改成相对路径)

codetr.scp指定训练及输入和输出文件列表。执行结果,HCopy 对codetr.scp 文件左侧的语音数据按config 1的配置提取特征并存入codetr.scp 文件右侧特征文件中。

对于测试数据如法炮制。

HCopy -T 1 -C config/config1 -S codete.scp

2.创建单音素HMM模型

(6)一致初始化法创建单音素模型

       定义一个原始模型proto:

 

训练文件train.scp的生成也是在DOS环境下进入到MFCC特征的文件路径下,执行 dir/b/s> train.scp。需要注意的是要在Nodepad++或UltraEdit下把多余的一行删除掉。

用全局均值和方差来初始化HMM模型的高斯参数:

HCompV -T 1 -C config/config1 -f 0.01 -m -S train.scp -M hmms/hmm0  proto

       在目录hmm0 下生成了更新后的proto和一个截至宏vFloors。基于./hmms/hmm0/下的两个文件,手工制作主宏文件hmmdefs和与vFloors相关的宏macro,具体制作过程参见HTKbook。

由于暂时不使用sp模型,删除monophones0中的sp,构成monophones1文件,重估参数:

HERest  -C config/config1 -I  labels/phones0.mlf  -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm0/macros -H hmms/hmm0/hmmdefs  -M hmms/hmm1  lists/monophones1

同上,重复估计两次:

HERest  -C ./config/config1 -I ./labels/phones0.mlf -t 250.0 150.0 1000.0 -S train.scp -H ./hmms/hmm1/macros -H ./hmms//hmm1/hmmdefs -M ./hmms/hmm2 ./lists/monophones1

 

HERest  -C ./config/config1 -I ./labels/phones0.mlf -t 250.0 150.0 1000.0 -S train.scp -H ./hmms/hmm2/macros -H ./hmms/hmm2/hmmdefs -M ./hmms/hmm3 ./lists/monophones1

(6)      修补哑音素模型

将hmm3中的macros复制到hmm4中,hmmdefs中的sil复制到文件末尾并将sil改为sp及状态改为3放到hmm4。

(1)利用HHEd 加入回溯转移概率:

HHEd -T 1 -H hmms/hmm4/macros -H hmms/hmm4/hmmdefs -M hmms/hmm5 sil.hed  lists/monophones0

修改mkphones0.led,去掉最后一行,存为mkphones1.led,利用HLEd 工具得到包含sp

的音素级真值文本:

HLEd -l * -d ./dict/dict1 -i ./labels/phones1.mlf mkphones1.led ./labels/trainwords.mlf

 

(2)重估两次:

HERest -C config/config1 -I labels/phones0.mlf -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm5/macros -H hmms/hmm5/hmmdefs -M hmms/hmm6  lists/monophones0

 

HERest -C config/config1 -I labels/phones0.mlf -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm6/macros -H hmms/hmm6/hmmdefs -M hmms/hmm7  lists/monophones0

(8)重校准训练数据

确认trainwords.mlf 中的路径为”*/S0*.lab”并且加上前面的140句话,修改dict1 加入silence sil 一项,另存为dict2,执行HVite 进行Viterbi 校准:

HVite -l * -o SWT -b silence -C config/config1 -a -H hmms/hmm7/macros  -H hmms/hmm7/hmmdefs -i labels/aligned.mlf -m -t 350.0 -y lab -I labels/trainwords.mlf -S train.scp  dict/dict2  lists/monophones0

 

利用HERest重估两次,最后保存到hmm9

HERest_3.4 -C config/config1 -I labels/aligned.mlf -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm7/macros -H hmms/hmm7/hmmdefs -M hmms/hmm8  lists/monophones0

 

HERest_3.4 -C config/config1 -I labels/aligned.mlf  -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm8/macros -H hmms/hmm8/hmmdefs -M hmms/hmm9  lists/monophones0

来看看这时的识别率怎么样:

HVite -H ./hmms/hmm9/macros -H ./hmms/hmm9/hmmdefs -S test.scp -l * -i ./results/recout_step9.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict2 ./lists/monophones0

HResults -I ./labels/testwords.mlf ./lists/monophones0 results/recout_step9.mlf

 

我们继续重估两次测试一下结果,看看会出现什么情况:

HERest_3.4 -C config/config1 -I labels/aligned.mlf  -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm9/macros -H hmms/hmm9/hmmdefs -M hmms/hmm9_1  lists/monophones0

 

HERest_3.4 -C config/config1 -I labels/aligned.mlf  -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm9_1/macros -H hmms/hmm9_1/hmmdefs -M hmms/hmm9_2  lists/monophones0

HVite -H ./hmms/hmm9/macros -H ./hmms/hmm9/hmmdefs -S test.scp -l * -i ./results/recout_step8_2.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict2 ./lists/monophones0

HResults -I ./labels/testwords.mlf ./lists/monophones0  results/recout_step8_2.mlf

识别结果没有再提高,所以之后就要通过绑定状态的三音素模型来进一步提高效果。

3.创建绑定状态的三音素HMM模型

目的是加入上下文依赖(context-dependent)三音素模型并得到稳健的训练。包括两步,先由单音素得到三音素并重估参数,第二步就是绑定三音素的状态以使输出分布更加稳健。

(9)得到三音素HMM

上下文依赖三音素模型可以用单音素作为初始,再进行重估。由于重估时要三音素级标注文本wintri.mlf,于是先生成标注文本。

HLEd -n lists/triphones1 -l * -i labels/wintri.mlf mktri.led labels/aligned.mlf

编辑脚本mktri.led包括如下命令:

其中文件wintri.mlf 是由单音素标注文本文件aligned.mlf 转换成的等价三音素标注文本。一个三音素的列表保存到了triphones1.

下面利用HMM 编辑器初始化三音素模型。所用命令为:

HHEd -H hmms/hmm9/macros -H hmms/hmm9/hmmdefs -M hmms/hmm10 mktri.hed lists/monophones0

其中的mktri.hed文件由 perl 脚本生成:

perl ./scripts/maketrihed ./lists/monophones1 ./lists/triphones0

修改mktri.hed文件,把第一行的./lists/triphones1改成./lists/triphones1。

运行HHEd得到如下警告,没有大碍的:

WARNING [-2631]  ApplyTie: Macro T_sp has nothing to tie of type t in HHEd

WARNING [-2631]  ApplyTie: Macro T_sil has nothing to tie of type t in HHEd

重估两次:

HERest -C config/config1 -I labels/wintri.mlf -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm10/macros -H hmms/hmm10/hmmdefs -M hmms/hmm11  lists/triphones1

HERest -C config/config1 -I labels/wintri.mlf -t 250.0 150.0 1000.0  -s stats -S train.scp -H hmms/hmm11/macros -H hmms/hmm11/hmmdefs -M hmms/hmm12  lists/triphones1

对于象FOUR,SUE 这样有多个发音的单词,在Vitebi 算法的作用下,会选择最大化似然率的单词,结果使dict2 中的发音在扩展成三音素时在音素级真值文本中没有实例,当然也就找不到该三音素的HMM 模型。这时会报错。包含在scripts 文件夹里的脚本makedict.pl 可以代替手工注释工作,使用下面的命令可以得到dict3:perl ./scripts/makedict.pl ./dict/dict2 ./dict/dict3 ./lists/triphones1

试着执行一下识别任务,看看怎么样:

HVite -H ./hmms/hmm12/macros -H ./hmms/hmm12/hmmdefs -S test.scp -l * -i results/recout_step9_1.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict3 ./lists/triphones1

进行识别验证:

HResults -I ./labels/testwords.mlf ./lists/monophones1  results/recout_step9_1.mlf

所得结果如下图:

基于三音素的HMM比基于单音素的HMM 有了较大的性能提升。

(10)在上一步估计模型时,因数据不足导致很多分布的方差只好用截至方差vFloors。这一步就是通过绑定状态来共享数据,使输出分布更加的稳健。HHEd提供两种聚类状态的机制,这里采用的是决策树:

HHEd  -B -H hmms/hmm12/macros -H hmms/hmm12/hmmdefs -M hmms/hmm13 tree.hed lists/triphones1 > log

上面的tree.hed用perl脚本mkclscript.prl(./scripts/目录下)生成:

perl mkclscript.prl TB 350.0 ./lists/monophones1>tree.hed

这时的tree.hed的内容:

这里往tree.hed中插入问题集和trace等信息。最终形式如下:

在tree.hed中,tiedlist是绑定后的不同三音素列表。Fulllist是输入参数,代表绑定前的所有三音素列表,所以要事先制作。HTK book的制作方法:

HDMan –b sp –n ./lists/fulllist –g global2.ded –l flog ./dict/beep-tri ./dict/beep

其中,文件global2.ded 是在global.ded基础上加入了TC命令:

HDMan 这里所做的工作包括:

1)           按照global2.ded的配置把beep字典中的发音扩展成(词内)三音素形式,保存到beep-tri字典;

2)           提取beep-tri中出现的所有不同三音素保存到fulllist列表中。但你会发现,按照上述方式制作的fulllist在执行HHEd时会引发错误,下面是一个例子:

ERROR [+2662]  FindProtoModel: no proto for k-b+l in hSet

FATAL ERROR - Terminating program HHEd

这是什么原因呢?其实上面错误提示中的k-b+l并没在我们的演示任务中出现。正因为没出现,所以HMM模型文件里没它的位置。 要解决这个错误,有两种解决途径。第一个路子,既然提示模型文件里没有三音素的模型,那就给它制作一个。可以把单音素*-b+*的模型复制一份给k-b+l,对于其他没模型的三音素也这样处理。我们这里不用这个路子,因为工作量太大了。我们走第二条路,这条路在htk的maillist中有人提到过,详见2006年4月24日的一封信,作者是Moustafa Nabil。这条路不用beep字典,而使用我们制作的任务字典。我们对dict2进行修改,另存为dict5,其中去掉了下述两项:

SENT-END [] sil

SENT-START [] sil

执行HDMan生成fulllist:

HDMan -b sp -n ./lists/fulllist -g global2.ded -l flog ./dict/beep-tri ./dict/beep

上面的global3.ded 是在global2.ded 基础上去掉了AS sp 一行,因为dict5中的每一单词发音后已经存在sp了。文件global3.ded的内容如下:

在fulllist中加入sil.重新执行HHEd,不会再出错了。重估两次:

HERest  -C config/config1 -I labels/wintri.mlf -t 250.0 150.0 1000.0 -S train.scp -H hmms/hmm13/macros -H hmms/hmm13/hmmdefs -M hmms/hmm14 lists/tiedlist

 

HERest  -C ./config/config1 -I ./labels/wintri.mlf -t 250.0 150.0 1000.0 -S train.scp -H ./hmms/hmm14/macros -H ./hmms/hmm14/hmmdefs -M hmms/hmm15 ./lists/tiedlist

4.识别器评估

(11)验证测试结果

HVite -C ./config/config2 -H ./hmms/hmm15/macros -H ./hmms/hmm15/hmmdefs -S test1.scp -l * -i ./results/recout_step10_1.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict3 ./lists/tiedlist

进行识别验证:

HResults -I ./labels/testwords0.mlf ./lists/tiedlist ./results/recout_step10_1.mlf

其中config2是在config1基础上加入FORCECXTEXP=T,ALLOWXWRDEXP=F。进行识别验证:HResults -I ./labels/testwords0.mlf ./lists/tiedlist ./results/recout_step10_1.mlf

/Test/目录下15句的识别结果:

HVite -C ./config/config2 -H ./hmms/hmm15/macros -H ./hmms/hmm15/hmmdefs -S test2.scp -l * -i ./results/recout_step10_2.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict3 ./lists/tiedlist

进行识别验证:

HResults -I ./labels/testwords00.mlf ./lists/tiedlist ./results/recout_step10_2.mlf

B集合10句话的识别结果:

HVite -C ./config/config2 -H ./hmms/hmm15/macros -H ./hmms/hmm15/hmmdefs -S test.scp -l * -i ./results/recout_step10.mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict3 ./lists/tiedlist

进行识别验证:

HResults -I ./labels/testwords.mlf ./lists/tiedlist ./results/recout_step10.mlf

/Test/ + B集合 共计25句话的识别结果:

整个HMM训练过程完毕。

总结:

(1)本实验主要参考HTK book和http://maotong.blog.hexun.com/6204849_d.html(苏统华,哈尔滨工业大学)

(2)尽管不断调整改进,可是识别结果还是不好,识别率低。

(3)生成的aligned.mlf文件缺失了好几句,为了下一步实验,给它手动添加了。

(4)wav文件参数(采样频率,量化位数,音量)的设置可能不大合适,影响结果这么差。

(5)对HTK工具包的使用过程不熟悉,理解不深入。总是出现很多问题,以后要多深入学习,提高。

原创粉丝点击