Alignment free LF-MMI小结

Alignment free LF-MMI

==Wang Y, Lv H, Povey D, et al. Wake Word Detection with Alignment-Free Lattice-Free MMI[J]. arXiv preprint arXiv:2005.08347, 2020.==

==Wang, Yiming. WAKE WORD DETECTION AND ITS APPLICATIONS. Diss. Johns Hopkins University, 2021.==王一鸣博士论文

==github开源代码==:The code and recipes are available in Kaldi [24]: https://github.com/kaldi-asr/kaldi/tree/master/egs/{snips,mobvoi,mobvoihotwords}.

==github代码==:https://github.com/YiwenShaoStephen/pychain

==csdn 博客==:Wake Word Detection with Alignment-Free Lattice-Free MMI

思想

  • 提出alignment free LF-MMI,不需要对齐分子lattice
  • 不把唤醒词里面每个音素建模,而是把整个唤醒词建模 model the whole wake phrase ,用一个固定状态数的HMM去建模唤醒词(该数量少于唤醒词音素组成数量)
  • keyword、non-keyword、sil 都各用一个HMM建模
  • 针对唤醒任务,提出alignment free LFMMI,分子不用对齐文本得到分子lattice,由于文本就是keyword/non-keyword,文本只有一个HMM,直接遍历HMM所有可能路径,求路径和概率。(直接用文本图上添加自环,让解码更自由,前后向可选的路径更多)
  • 负样本文本一般比较长,一个HMM可能建模不了,因此把负样本切成和正常本长度差不多,每个负样本的训练文本为freetext(一个HMM),就可以去生成egs了
  • 负样本如果不segment,会严重过拟合
  • 该方法能有效改善FAR高
  • 分母图上路径权重:按正负样本比例来分配

分子图fst:用一个文本构成(一个文本就是一个单词,一个单词用一个HMM建模)

img

分母图fst:可以理解成word 并联序列,只不过添加了sil(不是loop,不能重复走)

image-20211029145733035

实验

  • 负样本进行了分块chunk,==chunk长度和正样本差不多==,
  • 负样本后继chunk重叠0.3s,使得前一个chunk被截掉的单词有机会在后继chunk全词出现
  • 声学模型:TDNN-F,分解到两个低秩矩阵,前一个矩阵是半正定的,确保高维到低维信息不会丢失
  • 前一层的输入乘上缩放比例0.66与本层输入加和(是add,而不是concatenate)
  • 拼帧结构:把本来要拼在一层的结构 分解到两层会更好,比如第一层拼(-3,0,3),第二层拼(0),更好的做法是第一层拼(-3,0),第二层拼(0,3)
  • 训练了一个alignment-free LF-MMI后,对齐lattice,重新训练一个普通的LF-MMI,效果会更好
  • alignment-free体现在:
    • (雷博)不需要GMM-HMM训练过程,不需要对齐ali文件
    • 不需要对齐训练样本然后统计得到phone-lm
    • 一个没有一点对齐能力的模型(0.mdl)也可以拿来使用的
    • nnet3-chain-e2e-get-egs分子cegs生成,直接用text构建的fst,找到所有可能的fst中的状态序列求和就是分子,普通的还要由fst构建lattice?(感觉二者差不多)
  • 博士论文中比较了不同topo结构:
    • 把sil和freetext表示在一个HMM中,该HMM有多种可走的路径,这样就能够表示当训练样本前后是非命令词,中间是静音的情况。结果是增加了训练难度,误拒率很高,只有对齐准确的初始模型可能会得到好一点的误拒率,但是还是不好,因此最好不要把sil和freetext放在一起建模
    • 用5状态建模HMM,效果比3状态好

注意

  • 雷博说:
    • 负样本切chunk后,要注意正负样本比例,不要让负样本远远多于正样本。
    • 切割负样本(长文本切到短文本)时,文本不知道对应的是sil还是freetext,不好得知文本,把静音段也视作freeetext会有问题
    • 实验效果好,可能由于数据集较小

在线解码

  • 解码FST:其实长得有点像分母图,不同之处在于是起始状态和终止状态在同一个结点,使得可以生成词串,比如生成word后还可以生成freetext,再生成word等等,文本串;而分母图要不然就走freetext,要不然就走word,不能都串行出现。

image-20211029150244872

  • 在线解码:一个chunk一个chunk解码,每次解码了一个chunk后,就去更新immortal token和prev_immortal token(在所有active tok里找公共祖先(emitting[0],或者说tokenOne),作为immortal tok,把前一次的immortal tok作为prevImmortal tok),每次在两个immortal tokens之间的路径寻找(backtrace)是否有唤醒词,实现了逐chunk搜索。

  • 每处理过一段固定长度的录音后,我们用更新不朽token算法来回溯最近两个“不朽token”中间的这些帧,检查这部分回溯是否包含唤醒词。如果发现唤醒词则停止解码,如果没有唤醒词继续解码。(不朽token是现存激活token的共同祖先)

    这个是基于这样一个假设:如果现有的存活的部分假设都是来自于前一个时刻的相同的token(不朽token),同时在这之前的所有的假设都已经压缩到了这一个token上,我们就可以从这个“不朽token”检查是否具有唤醒词 [csdn]

  • 伪代码 online decoding:

image-20211029144006785

  • 更新immortal token,用于回溯

image-20211029144433677

代码实现

The code and recipes are available in Kaldi [24]: https://github.com/kaldi-asr/kaldi/tree/master/egs/{snips,mobvoi,mobvoihotwords}.

本文中引入了一种不需要对齐(Alignment-free)、不需要词图的(Lattice-Free MMI)鉴别性准则训练的模型
相比Lattice-free MMI准则需要额外修改一下发音字典、HMM拓扑结构

1.HMM拓扑结构(KW和freetext)用的是5个状态;silence用的是2个状态,但是保持(Lattice-free MMI)的结构self-loop-pdf和forward-pdf对应两个不同的PDF-id,因此神经网络共82+21=18个pdf

2.分子图与分母图
分子图和chain的不同点在于:不需要依赖对齐结果生成label对应的图,生成一个非扩展的fst,在训练过程中通过前后向算法更加灵活的学习对齐结果
分母图和chain的不同点在于:phone级别的语言模型不再需要通过训练数据训练得到,直接手动生成一个语言模型fst,一共3条路径,关键词路径、freetext、silence,其中关键词和freetext前后都可加silence。每一条路径上的权重受训练数据中正负样本的占比因素影响
3.声学模型
使用TDNN-F模型(因式分解的TDNN),将一层的参数矩阵分解成两个低秩矩阵、第一个矩阵强制限制为半正定矩阵
模型(20层每层80节点)存在跨层连接,前一层的输入乘上缩放比例0.66与本层输入加和。
4.数据预处理和增强
对于负样本(存在很多样本时长较长)会按照正样本的时长分布,对负样本进行切段,每一段分配一个负样本标签。
增强:尽管训练数据很多是在实际场景中录制的,增强后效果仍然后提升
5.解码
手动构造词级别的解码网络FST,每条路径上的权重生成和分母图的LM-fst图方式是一样的。在开始token和结束token上增加从结束token到开始token的空边,原因是音频中可能存在唤醒词和其他可能的音频交叉现象。
在线解码的过程中:每处理过一段固定长度的录音后,我们用更新不朽token算法来回溯最近两个“不朽token”中间的这些帧,检查这部分回溯是否包含唤醒词。如果发现唤醒词则停止解码,如果没有唤醒词继续解码。(不朽token是现存激活token的共同祖先)

这个是基于这样一个假设:如果现有的存活的部分假设都是来自于前一个时刻的相同的token(不朽token),同时在这之前的所有的假设都已经压缩到了这一个token上,我们就可以从这个“不朽token”检查是否具有唤醒词

实验

  • 由于freetext只用一个HMM,因此不支持于自定义唤醒词,可应用于小模型的需求。

  • 路径:24.3:/home/data/yelong/kaldi/egs/mobvoihotwords/v1

  • 命令词:sil freetext 上一曲 下一曲 减小音量 增大音量 小源小源 播放 暂停 静音

数据准备

  • 不用run_e2e.sh脚本里的随机切割得到负样本,而是用对齐信息,得到边界,可以避免把静音对成freetext
  • ==把带有关键词的负样本删掉==

切割长负样本到短负样本

1
2
work_dir=/home/storage/speech/kaldi/egs/keyword/s5
bash +x steps/get_train_ctm.sh --print_silence true $work_dir/data/mfcc/train_12000 data_hua/lang_normal/ $work_dir/exp_sil/mfcc_pitch/nnet3_tdnn6layers_8b_relu_ali_train_12000 data_hua/ali_12000

去掉存在长静音段的负样本,然后按与正样本长度差不多的随机切割,这是因为正样本有前后静音,如果负样本只有发音段,不太好,因此把存在小的前后静音段考虑进负样本中

把静音区域大于1s的负样本丢弃:

1
2
python local/phone2word.py data_hua/ali_12000/ctm > data_hua/ali_12000/output_ctm
sed -i '/yelong/d' data_hua/ali_12000/output_ctm

筛选出neg_segments:

1
utils/filter_scp.pl data_hua/ali_12000/output_ctm data_hua/data_all_sub2_Xiaoyuan_12000_whole/segments > data_hua/data_all_sub2_Xiaoyuan_12000_whole/neg_segments

筛选出正样本(开头SY、Xiaoyuan、sp的)

按照正样本长度范围切割负样本:

1
2
srcdir=data_hua/data_all_sub2_Xiaoyuan_12000
local/get_random_subsegments.py --overlap-duration=0.3 --max-remaining-duration=0.3 ${srcdir}_whole/neg_segments ${srcdir}_whole/pos_utt2dur | cat ${srcdir}_whole/pos_segments - | sort >${srcdir}_whole/sub_segments

把长度太短的(小于0.5s)、太长的删掉(大于5.05s)

data_hua/data_all_sub2_Xiaoyuan_12000_segmented_e2e_cut:正样本正负样本比例:正样本433万条,负样本1635万条,正负样本比例1:3.7(接近1:4)(不好,应该减少正样本的比例)

2021.11.23新:正样本233w,负样本1635万条,正负样本1:7

2021.11.27新:发现split5测试集的唤醒率不高,原来是没有把9w条Xiaoyuan数据都用了,只用了4.5万条,把9w条需要都加入进去才行,正样本237万,负样本1635万,正负样本1:7【训练出来效果很差,不知道为什么】

模型

  • tdnnf结构,13层,dim=80,bottleneck dim=20,左拼27帧,右拼27帧,参数量 111388(113k)

  • 74个分类状态(2* (9* 4+1) =74),sil:1状态,freetext、keyword:4状态

  • 训练很快

实验测试结果

-

实验结果分析

  • 正负样本1:4时:
    • 声学模型输出在同一帧中有很多分类的概率都挺高,说明声学模型效果不好,但是还能得到测试集唤醒率高、误唤醒率低的唤醒词,说明后面接的G还是挺关键的
    • 其他唤醒词误唤醒率很高,不是喊该命令词时,也会唤醒,比如喊小源没唤醒,但是会误唤醒其他唤醒词,因此不能把很多命令词都当作唤醒词,就是即使把命令词放在唤醒词后面唤醒,也很容易出现喊命令词却识别成另一个命令词的情况,我们希望的是即使不唤醒,也别唤醒成别的。对多唤醒词任务不友好。
  • 正负样本1:7时:
    • 其他唤醒词误唤醒率相较于正负样本1:4的模型下降许多
    • 唤醒率低,容易识别成freetext,考虑通过增加每个HMM的topo状态数来缓解[TODO]
  • 过拟合比较严重,对未见过的样本识别率很低,可能是因为建模单元颗粒度大(词),建模topo结构状态数少
  • freetext后接keyword的输出很少见,应该是和训练相关。
  • Alignment-Free当模型为tdnnf,13layer,80_20,参数量100K,状态数30时,很容易过拟合,说明模型太小时,不具备大建模单元(一个词用4状态表示)的建模能力;

TODO

  1. 增加topo建模状态数
  2. alignment free LF-MMI对齐lattice训练regular LF-MMI