为什么80%的码农都做不了架构师?>>>
基于 HTK 的语音拨号系统
Veket
NWPU
2011-6-22
目标:
该系统能够识别连续说出的数字串和若干组姓名。建模是针对子词( sub-word,eg.. 音素),具有一定的可扩充性。当加入一个新名字时,只需修改发音词典和任务语法即可。模型为连续混合高斯输出,运用语音决策树聚类形成的绑定状态式三音素。
内容:
1. 数据准备
(1) 任务语法定义
(2) 字典定义
(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/monophones 0 -l dlog dict/dict1 dict/beep dict/names
生成的文件 monophones 0 是用到的音素列表(包括 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 1 0 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/config 1 -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/config 1 -S codet e .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 hmm s/hmm0 proto
在目录 hmm0 下生成了更新后的 proto 和一个截至宏 vFloors 。基于 ./hmms/hmm0/ 下的两个文件,手工制作主宏文件 hmmdefs 和与 vFloors 相关的宏 macro, 具体制作过程参见 HTKbook 。
由于暂时不使用 sp 模型,删除 monophones 0 中的 sp, 构成 monophones 1 文件,重估参数:
HERest -C config/config1 - I labels/phone s 0.mlf - t 250.0 150.0 1000.0 - S train.scp -H hmms/hmm0/macros -H hmms/hmm0/hmmdefs -M hmms/hmm1 lists/monophones 1
同上,重复估计两次:
HERes t -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/monophones 1
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/monophone s0
修改 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/phone s0 .mlf -t 250.0 150.0 1000.0 - S train.scp -H hmms/hmm5/macros -H hmms/hmm5/hmmdefs -M hmms/hmm6 lists/monophones 0
HERest -C config/config1 -I labels/phone s0 .mlf -t 250.0 150.0 1000.0 - S train.scp -H hmms/hmm 6 /macros -H hmms/hmm 6 /hmmdefs -M hmms/hmm 7 lists/monophones 0
( 8 )重校准训练数据
确认 trainwords.mlf 中的路径为 ”*/S0 * .lab” 并且加上前面的 140 句话 ,修改 dict 1 加入 silence sil 一项,另存为 dict 2 ,执行 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/dict 2 lists/monophones 0
利用 HERest 重估两次 ,最后保存到 hmm9
HERest _3.4 -C config/config1 -I labels/aligned.mlf -t 250.0 150.0 1000.0 - S train.scp -H hmms/hmm 7 /macros -H hmms/hmm 7 /hmmdefs -M hmms/hmm 8 lists/monophones 0
HERest _3.4 -C config/config1 -I labels/aligned.mlf -t 250.0 150.0 1000.0 - S train.scp -H hmms/hmm 8 /macros -H hmms/hmm 8 /hmmdefs -M hmms/hmm 9 lists/monophones 0
来看看这时的识别率怎么样 :
HVite -H ./hmms/hmm 9 /macros -H ./hmms/hmm 9 /hmmdefs -S test.scp -l * -i ./results/recout_step 9 .mlf -w wdnet -p 0.0 -s 5.0 ./dict/dict 2 ./lists/monophones 0
HResults -I ./labels/testwords.mlf ./lists/monophones 0 results/recout_step 9 .mlf