单一唤醒词识别模型

单一唤醒词识别模型

思路

  • 与DNN-HMM的ASR任务相同,逐帧分类,按音素建模,不同的是KWS任务分类数量比ASR任务分类数量更少,只有唤醒词包含的音素,其他通用音素都视为非唤醒词音素,采用一个非唤醒词音素建模(gbg);音频经过声学模型输出后采用beam search解码,最优路径上判断是否是唤醒词路径。

目标

唤醒Recall高,FAR低

  • 提高Recall方法:唤醒数据增广,增加唤醒样本的丰富性,其他未有正向结论;
  • 降低FAR方法:参考Sigtia, Siddharth, et al. “Efficient Voice Trigger Detection for Low Resource Hardware.” INTERSPEECH. 2018. 文章通过加入状态持续时间的约束minimum duration constraint,最小状态帧长的约束,也就是每个状态至少持续n帧,增大帧移,来减少误唤醒。因此实验中在解码过程中进行下采样,以及声学模型的拼帧采用较长拼帧,来减少误唤醒。

声学模型

  • 输出分类标签:唤醒词“小源小源”对应的音素组成“x、iao、vv、van”、静音“sil”、其他音“gbg”,共6个分类数;
  • 声学模型网络结构为TDNN,结构特点为拼帧较长:
1
2
3
4
5
6
7
8
9
10
11
    cat <<EOF > $dir/configs/network.xconfig
input dim=50 name=input
fixed-affine-layer name=lda input=Append(-6,-3,0,3,6) affine-transform-file=$dir/configs/lda.mat
relu-renorm-layer name=tdnn1 dim=256
relu-renorm-layer name=tdnn2 dim=256 input=Append(-3,6)
relu-renorm-layer name=tdnn3 dim=256 input=Append(-6,3)
relu-renorm-layer name=tdnn4 dim=256 input=Append(-9,9)
relu-renorm-layer name=tdnn5 dim=256 input=Append(-15,3)
relu-renorm-layer name=tdnn6 dim=256 input=Append(0)
output-layer name=output dim=$num_targets max-change=1.5
EOF

词典

  • lexicon.txt

语言模型

  • words.txt

  • 2gram,srilm.o3g.kn.gz:

  • 语言模型训练通过很多的sil和gbg和几条小源小源、xiao、yuan、xiaoyuan等训练得到,观察测试集中没识别出唤醒词识别成什么文本,观察测试集中误唤醒成什么文本,调节该文本相关语言模型权重;

  • 根据recall和far值,不断微调唤醒词和非唤醒词语言模型权重,使得recall较高下也有较低的far;

声学模型训练过程

训练集

  • 用6w原始数据,5种噪声,加上原来没有加噪的数据,6*6=36w条;路径:data/train_xiaoyuan
  • 速度扰动 36*3=108w条,路径:data/train_xiaoyuan_sp(727小时)
  • 108w条提取16维mfcc特征,train_xiaoyuan_sp_mfcc(steps/make_mfcc_pitch.sh),做对齐,对齐路径:exp/nnet3/tdnn_lei/ali_train_xiaoyuan_sp
  • 提取50维plp特征
  • 108w条对齐文件 + Xiaoyuan 9w条对齐文件 = 117w条,作为小源命令词数据(正样本)
  • 4000小时ASR通用数据,360万条作为非唤醒词数据(负样本)

训练标签准备

  • 将对齐标签转为6分类(可参考kaldi脚本hi_mia/w1/run_kws_kf.sh)

    1. 构建phone映射表

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      #转换,使得只保留命令词的phone,其他无关phone都用garbage这个phone表示
      awk -v hotword_phone=data/dict/phones.txt \
      'BEGIN {
      while (getline < hotword_phone) {
      map[$1] = $2-1
      }
      }
      {
      if(!match($1, "#") && !match($1, "<")) {
      if(match($1, "sil"))
      {
      printf("%s %s\n", $2, 0)
      }
      else
      {
      printf("%s %s\n", $2, map[$1] != "" ? map[$1] : 1)
      }
      }
      }
      ' data/lang/phones.txt > data/phone.map
    2. 构建6分类的alignment文件

      1
      2
      3
      4
      5
      6
      7
      8
      mkdir -p $dir_temp
      cur=$(cat $ali/num_jobs)
      for x in $(seq 1 $cur);do
      gunzip -c $ali/ali.$x.gz |
      ali-to-phones --per-frame=true exp_sil_ftv/mfcc_pitch/nnet3_tdnn6layers_8b_relu_ali_train_ftv/final.mdl ark:- t,ark:- |
      utils/apply_map.pl -f 2- data/phone.map |
      copy-int-vector t,ark:- ark,scp:$dir_temp/ali.$x.ark,$dir_temp/ali.$x.scp
      done

声学模型训练

  • steps/nnet3/train_raw_dnn.py,没有转移概率,生成声学模型final.raw

生成final.mdl

  • 生成tree:
    • gmm-init-mono –shared-phones=data/lang_xyxy/phones/sets.int “–train-feats=ark,s,cs:apply-cmvn –utt2spk=ark:data/train/split10/1/utt2spk scp:data/train/split10/1/cmvn.scp scp:data/train/split10/1/feats.scp ark:- | add-deltas ark:- ark:- | subset-feats –n=10 ark:- ark:-|” data/lang_xiaoyuan/topo 39 0.mdl tree
  • final.raw生成final.mdl
    • nnet3-am-init exp/nnet3/tdnn_1/tree data/lang_xyxy/topo exp/nnet3/tdnn_1/final.raw exp/nnet3/tdnn_1/final.mdl

解码过程

  • 与普通识别模型相同,输出声学模型分数,在事先构建好的解码网络HCLG.fst中搜索最优路径,最优路径有唤醒词则唤醒;
  • 解码长度与触发VAD长度相关;
  • 解码时“–frame-subsampling-factor=3”,(即在keyword_lib改为chain model网络结构),跳帧输入解码器/cmvn后特征跳帧输入DNN;

训练小结

  1. 对比负样本音素用一个音素gbg表示与保留唤醒词音素的模型,用一个音素表示造成声学特征下输出gbg的概率和唤醒词音素概率都高,造成区分性不明显,混淆,因此不能将负样本音素用一个音素表示,需要在负样本中保留唤醒词音素;
  2. 数据增广的效果:
    1. 对比不同唤醒数据量训练的模型,加噪后用上所有唤醒数据,与加噪后没用上所有唤醒数据相比,没有改善;因此在样本数据有一定数量条件下,单纯只用上所有噪声未带来更加丰富的样本信息。
    2. 加噪后用上所有唤醒数据,再加入速度扰动,与加噪后没用上所有唤醒数据相比,能有一些改善;因此速度扰动在该样本集条件下能带来更加丰富的样本信息。
  3. asr和kws联合训练的多任务学习、用训好的asr除最后一层作为初始kws模型,未取得正向结论;训练时asr的accuracy在60%,猜想asr的loss较大可能影响了kws任务。
  4. 更改模型结构,crnn、attention结构,未取得正向结论;应该还是没有训练好。

实验结果

  • 结果从decode.log获取,不通过lattice得到