基于kaldi训练唤醒词模型的一种方法

版权声明: https://blog.csdn.net/cj1989111/article/details/88017908

0. 前言

    什么是唤醒?激活Google智能助手,你可以对手机说“Hey Google”或者“OK Google”,其他诸如阿里的天猫精灵智能音箱(天猫精灵)、京东的叮咚智能音箱(叮咚叮咚),百度语音助手(小度小度)等等,需要采用唤醒词才能激活设备,然后再对设备进行一系列控制语音输入,一方面减小了智能音箱执行错误操作的概率,另一方面也降低了整个设备的功耗。本文基于开源语音识别kaldi平台,实现一个唤醒模型的训练及解码识别。

    区别于服务器拥有庞大的算力,CPU型的嵌入式平台内存小、主频有限,这就要要求训练出的模型尽量小,且解码速度尽量快,否则即使模型很好,解码时间较长,在嵌入式平台的移植也宣告失败。本文所用嵌入式平台的CPU主频为1.3GHz,内存为64M,Flash大小为32M。

1. 模型训练

    模型是基于kaldi平台中的egs/aishell2训练脚本修改而来,语料来源于aishell公开语料。

1.1 语料准备

    选取一个唤醒词“小米小米”,原因是在语料库中“小米“出现的次数比较多,暂时定为使用它来训练我们的唤醒词,为了防止误识别,即口语噪声误识别成“小米小米”,还需添加一些额外的垃圾词汇(数量不宜过多),同时还需保持解码图路径多样性,添加这一类词“小狗”、“小伙”、“大小”等等,在语音识别时,如果没有此类路径多样性词汇,很可能一段语音只包含“小”也可能识别成“小米小米”。

    在挑选的语料中,尽量少出现或者不出现与“小米”发音类似的词,比如“小幂”、“筱敏”、“小咪”等,因为训练时不在发音字典lexicon.txt中的词训练时会分类到一个音素"spn"上,即<UNK> (参考官方文档:Note on unknown words),如果不去除与“小米”发音类似的词(抛弃发音类似的训练样本),会使得唤醒词识别率下降。

    为了更好的远场识别效果,还需录制一些远场的语料,由于条件的局限性,只有采用aishell的语料进行训练验证。

注:本文的发音字典lexicon.txt 

语料格式及组织方式:请点击 语料组织,其中有data dev test这三个目录,由于文件大小限制,需自行下载开源语料,语料只有1条。

1.2 语言模型训练

    本文采用n-gram来训练生成模型,具体的操作是从lexicon.txt中获得,代替了原本训练脚本中采用train/text文件训练语言模型,原aishell语言模型具有统计意义,此处为了减小语言模型大小,采用1-gram来训练,所有词的概率均相等,但为了减小口语噪声识别成唤醒词,同时修改了UNK的先验概率。训练语言模型的words.txt文件

训练的命令:

ngram-count -text word -order 1 -unk -map-unk "<UNK>" -interpolate -lm data/local/lm/3gram-mincount/lm_unpruned.gz

注:脚本及注释   line:46-66

1.3 GMM-HMM阶段训练

    参考aishell2\s5\local\run_gmm.sh,改动不大,略微改动。关键修改内容: mfcc特征提取时,移除了pitch特征的提取(主要原因是解码时提取pitch特征耗时且对识别率提升不是那么大),mfcc配置文件修改为mfcc_hires.conf,对13维特征做了一阶和二阶差分;

steps/make_mfcc.sh --cmd "$train_cmd" --nj $nj --mfcc-config conf/mfcc_hires.conf  data/$x exp/make_mfcc/$x mfcc

注: 参考脚本及注释

1.4 TDNN阶段训练

    在chain模型训练时,修改aishell2\s5\local\chain\tuning\run_tdnn_1b.sh神经网络训练脚本,关键修改内容:一、移除了ivector特征训练相关功能,因为在嵌入式平台中,ivector特征维度太大,会导致内存消耗太大,系统崩溃,且ivector提升识别率没有那么明显;二、DNN网络维度和隐层数量减小,如果不降低这二者,训练出的声学模型会比较大,导致解码效率下降,可以在测试过程中权衡网络层次和维度;

训练完成后生成的模型大小如下:

以上生成的模型未调整参数,要使模型最优化,还需微调相关的训练参数。

注:参考脚本及注释 

1.5 生成NNET3解码所需模型

主要命令:./steps/online/nnet3/prepare_online_decoding.sh data/lang_chain exp/chain/tdnn_1b_all_sp ./nnet3_conf  因为移除了pitch和ivector, 所以未传入这两个相关内容的参数

生成解码器文件后,拷贝到model文件夹,具体参考脚本 copy_model.sh

2. 解码

    解码器基于online2-wav-nnet3-latgen-faster.cc修改而来,可以持续在线识别(此部分代码暂不提供),识别结果如下,嘈杂时候出<UNK>几率比较大,视频请点击:识别的视频

识别效果

(待测)杂环境下(人声+蜻蜓fm说书)挂机10小时,误触发唤醒词“小米小米”次数

注: 以下为wav解码器的参数

./online2-wav-nnet3-latgen-faster --do-endpointing=false --online=false --frame-subsampling-factor=3 --config=./model/nnet3_conf/conf/online.conf --add-pitch=false --max-active=7000 --beam=15.0 --lattice-beam=6.0 --acoustic-scale=1.0 --word-symbol-table=./model/graph/words.txt ./model/nnet3_conf/final.mdl ./model/graph/HCLG.fst 'ark:echo utterance-id1 utterance-id1|' "scp:echo utterance-id1 test.wav|" 'ark:/dev/null'

3. 总结

    嘈杂环境下的识别率暂时未考虑在内,需要语音前端处理以及相关的噪音语料加入训练,此工作量比较大,仅凭个人力量难以实现,望谅解。

    如果训练出来的模型识别率不高,可能是语料当中包含相近的发音导致,也可能是语料不够。去除相近发音的语料,加入更多的唤醒词语料。

    对于章节2中所说解码器,提供一种思路,是把online2-wav-nnet3-latgen-faster.cc每次传入的是wav的文件,改写成死循环,读入语音数据,语音数据的来源可以参考onlinebin/online-gmm-decode-faster.cc中调用portaudio的接口来实现语音流的输入,关于语音流的截取需要VAD算法(参考我的github 3GPP VAD:https://github.com/xiangxyq/3gpp_vad )

以上训练脚本参考github:https://github.com/xiangxyq/kaldi/tree/master/egs/wakeup_words

后期推出博文:Kaldi平台关于识别结果置信度相关文章

猜你喜欢

转载自blog.csdn.net/cj1989111/article/details/88017908