一、DNN序列鉴别性训练
传统的用DNN语音识别,在逐帧训练中,使用了交叉熵(CE)准则来最小化期望帧错误。但是,语音识别本质上是一个序列分类问题,更关心序列的准确性。所以我们需要引入一些更契合这种问题的序列鉴别性训练方法(sequence-discriminative training,SDT),比如常用的最大互信息准则(MMI)、增强型最大互信息准则(BMMI)、最小音素错误准则(MPE)和状态级最小贝叶斯风险准则(sMBR)等。根据实验结果表明,序列鉴别性训练方法相比CE训练的模型可以获得大约3%到17%的相对错误率下降。
1、最大化互信息准则(MMI)
语音识别中使用的MMI准则旨在最大化单词序列分布和观察序列分布的互信息,这和最小化期望句错误有很大的相关性。
2、增强型最大互信息准则(BMMI)
BMMI准则是MMI准则的一个变种,它增强了错误较多的路径的似然度。
3、最小音素错误准则(MPE)和状态级最小贝叶斯风险准则(sMBR)
最小贝叶斯风险(MBR)目标函数族的目标方程都旨在最小化不同颗粒度标注下的期望错误。比如,最小音素错误准则(MPE)旨在最小化期望音素错误;而状态级最小贝叶斯风险准则(sMBR)旨在最小化状态错误的统计期望。
如果上面的文字看不太懂,可以简单的理解MMI/BMMI/MPE/sMBR是类似于神经网络训练过程中的损失函数。简单总结起来,如下面的表格:
准则 | 目标函数 |
CE | 帧错误率 |
MMI/BMMI | 句子正确率 |
MPE | 音素错误率 |
sMBR | 状态错误率 |
4、鉴别性训练技巧
(1)词图生成
DNN系统的鉴别性训练的第一步是产生分子和分母词图。研究发现,词图质量以及种子模型优劣对最终识别结果准确率有较大影响,最好是使用已有最佳的模型来生成词图。
(2)词图补偿
如果词图产生的不合理的话,会导致计算出来的梯度异常,比如分子的标注路径没有在分母中的词图出现,这种情况对于静音帧尤其常见,因为静音经常出现在分子的词图,但是很容易被分母的词图忽略。有一些方法可以解决这种问题:
(a)帧拒绝(fame rejection),直接删除这些帧。
(b)根据reference hypothesis修正词图,比如在词图中人为地添加一下静音弧。
(3)帧平滑
鉴别性训练很容易出现overfitting,两方面原因:
(a)稀疏的词图导致了过拟合。
(b)序列相比帧处在更高的维度。因此,从训练集估计出的后验概率很可能是不同于测试集的。
可以修改训练准则来减弱overfitting,如用帧平滑技术,最小化序列和帧的训练准则函数的加权和:
其中H成为平滑因子,经验值设为4/5到10/11
(4)学习率调整
SDT的学习率相比于CE要小,因为:
(a)SDT的起点一般基于CE训练出来的种子模型
(b)SDT训练容易出现overfitting
(5)训练准则选择
sMBR效果相比其他会好一点,MMI比较容易理解和实现。
(6)噪声对比估计
噪声对比估计算法(NCE)可以用于加速训练。
二、kaldi中的相关代码
1、kaldi项目中序列鉴别性训练相关的脚本
steps/nnet/train_mpe.sh
steps/nnet/train_mmi.sh
2、执行脚本与参数示例
sMBR准则训练示例指令:
steps/nnet/align.sh --nj 8 --cmd run.pl --mem 2G data/fbank/train data/lang exp/tri7b_DFSMN_L exp/tri7b_DFSMN_L_ali
steps/nnet/make_denlats.sh --nj 8 --cmd run.pl --mem 4G --acwt 0.08 data/fbank/train data/lang exp/tri7b_DFSMN_L exp/tri7b_DFSMN_L_denlats
steps/nnet/train_mpe.sh --cmd run.pl --mem 4G --gpu 1 --num-iters 2 --learn-rate 0.000001 --acwt 0.08 --do-smbr true \
data/fbank/train data/lang exp/tri7b_DFSMN_L exp/tri7b_DFSMN_L_ali exp/tri7b_DFSMN_L_denlats exp/tri7b_DFSMN_L_smbr
注意:
(1)如果要用MPE训练,上面最后一个指令中--do-smbr改为false。
(2)如果要用MMI训练,也是最后一个中将脚本train_mpe.sh改成train_mmi.sh,并修改一下差异的参数即可;默认是用MMI训练,要用BMMI训练,加“--boost <float>”参数即可。
3、align.sh说明
steps/nnet/align.sh --nj ${nj} --cmd "${train_cmd}" ${data_fbk}/train data/lang ${dir} ${dir}_ali
使用基于神经网络的声学模型将数据与转换ID序列对齐。可选地以点阵格式生成对齐,这对于获取单词对齐非常方便。
4、make_denlats.sh说明
steps/nnet/make_denlats.sh --nj ${nj} --cmd "${decode_cmd}" --acwt ${acwt} ${data_fbk}/train data/lang ${dir} ${dir}_denlats
为MMI/MPE/sMBR训练创建分母词图。输出的文件名为:$dir/lat.*.ark,$dir/lat.scp。词图是非压缩的,需要随机存取来进行DNN训练。
5、train_mpe.sh说明
(1)运行指令示例:
steps/nnet/train_mpe.sh --cmd "${cuda_cmd}" --num-iters 2 --learn-rate 0.000001 --acwt ${acwt} --do-smbr true \
${data} ${lang} ${src_dir} ${ali_dir} ${denlats_dir} ${out_dir}
steps/nnet/train_mpe.sh --cmd "${cuda_cmd}" --num-iters 2 --learn-rate 0.000001 --acwt ${acwt} --do-smbr true \
${数据路径} ${语音模型路径} ${语音模型路径} ${对齐数据路径} ${词图数据路径} ${输出目录}
(2)主要参数说明:
do_smbr=true # true表示用sMBR准则,false表示用MPE准则。
one_silence_class=true # 如果为true:所有的“静音”都映射到sMBR/MPE的前向后的单个类
#(这可以防止sMBR发生WER爆炸,这是由一些数据引起的)。
# 如果为false:在近似精度的计算中,静音帧总是被认为是“错误的”。
silphonelist= # 这将覆盖默认的静音列表(用于选择静音因素的子集)
(3)该脚本主要的是调用C编译出来的接口nnet-train-mpe-sequential进行训练:
$cmd $dir/log/mpe.$x.log \
nnet-train-mpe-sequential \
--feature-transform=$feature_transform \
--class-frame-counts=$class_frame_counts \
--acoustic-scale=$acwt \
--lm-scale=$lmwt \
--learn-rate=$learn_rate \
--momentum=$momentum \
--do-smbr=$do_smbr \
--verbose=$verbose \
--one-silence-class=$one_silence_class \
${silphonelist:+ --silence-phones=$silphonelist} \
$cur_mdl $alidir/final.mdl "$feats" "$lats" "$ali" $dir/$x.nnet
6、train_mmi.sh说明
(1)运行指令示例:
steps/nnet/train_mmi.sh --cmd "${cuda_cmd}" --num-iters 2 --learn-rate 0.000001 --acwt ${acwt} \
${data} ${lang} ${src_dir} ${ali_dir} ${denlats_dir} ${out_dir}
steps/nnet/train_mmi.sh --cmd "${cuda_cmd}" --num-iters 2 --learn-rate 0.000001 --acwt ${acwt} \
${数据路径} ${语音模型路径} ${语音模型路径} ${对齐数据路径} ${词图数据路径} ${输出目录}
(2)主要参数说明:
boost=0.0 # 通过“--boost<float>”选项激活增强型最大互信息准则(BMMI)。
drop-frames=true # 默认开启丢帧
$cmd $dir/log/mmi.$x.log \
(3) 该脚本主要的是调用C编译出来的接口nnet-train-mmi-sequential进行训练:
$cmd $dir/log/mmi.$x.log \
nnet-train-mmi-sequential \
--feature-transform=$feature_transform \
--class-frame-counts=$class_frame_counts \
--acoustic-scale=$acwt \
--lm-scale=$lmwt \
--learn-rate=$learn_rate \
--drop-frames=$drop_frames \
--verbose=$verbose \
$cur_mdl $alidir/final.mdl "$feats" "$lats" "$ali" $dir/$x.nnet