ASR神经网络实战

kaldi语音识别理论与实践课程学习。

之前学习了基于GMM-HMM的传统语音识别:GMM-HMM 其中也包含Kaldi架构的简介,语音数据的预处理,特征提取等过程。
今天学习基于神经网络的语音识别。

神经网络训练脚本

以TDNN为例。

Kaldi中大部分的例子egs里,都提供了训练thnn的recipe。

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能

不同recipes的内容可能有所差异,但大体都能分为3个部分。

pytorch神经网络语音情绪识别 语音识别 神经网络_初始化_02


神经网络config可以简单理解为一张图,Kaldi网络就是从这张图初始化得到的。

参数设置

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_03


stage:控制脚本运行起始位置的参数。

nnet3_affix:训练好的神经网络存放名字后缀

train_stage:如果训到第50轮断了,就把该值设置成50,就可以从第50轮开始,而不需要从头开始

common_egs_dir和remove_egs后续会再说。

再下来 . ./的是配置环境变量。其中:
utils/parse_options.sh 实现了基于shell脚本的“ --key value”的传参方式, 例如:

./run_tdnn.sh --stage 0 --gmm tri4b \
--nnet3_affix data_aug

注意: 只有定义在utils/parse_options.sh之前的参数允许以该方式传参, 图中的[dir, gmm_dir, ali_dir, graph_dir]等不能以此方式传参。

神经网络config

num_target:神经网络维度,tree的叶子节点数。

下面是个TDNN的网络结构。tdnn1,2,3只是名字,不代表是第一层、第二层等,你也可以写成a,b,c。(-1,0,2)代表context的左一右二。

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_04


configs是一组配置。可以理解为就是神经网络的画像,整体结构和内部节点之间的关系。网络初始化的时候就要按config里的定义初始化。

为了便于理解config,Kaldi提供了一个config解析器,即xconfig_to_configs。

生成以下文件:
{ final.config; init.config; init.raw; network.config; ref.config;
ref.raw; vars; xconfig; xconfig.expanded.1; xconfig.expanded.2 }

可分为四类:

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_05

xconfig:

比原始的config增加了一些定义。expend2是对1的进一步解析。

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_06

init:
注意:是只和输入相关的节点,不是初始化后的整个网络。

init.config

只包含两个节点,input node和output node

pytorch神经网络语音情绪识别 语音识别 神经网络_初始化_07

init.raw

从init.config初始化得到的,

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_08


需要init.config的目的是得到输入数据的维度相关的信息,以便于训练后面的LDA,这是一个训练的小技巧。ref

是reference的简称。顾名思义是个参考的config。

lda矩阵是”假“的(随机初始化的):还没有对输入数据进行遍历,还没有统计

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_09


ref.raw就是从ref.config得到的完整模型,为了给kaldi提供一个参考,供kaldi遍历,能够计算出整个模型的context。final

var,全程variable,存储模型上下文信息

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_10


这个左右context是根据左右context是根据ref.raw计算出来的。final.config

训练的神经网咯就是由它初始化得到的。

被解析成更小的单元 component node

pytorch神经网络语音情绪识别 语音识别 神经网络_神经网络_11

那component和component node之间是什么关系?

就是面向对象里的 类 component和 对象 component node的关系。

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_12

比如下面,

pytorch神经网络语音情绪识别 语音识别 神经网络_神经网络_13

处了刚才例子中的TDNN模型中的relu-batchnorm组件,kaldi还有哪些组件呢?
xconfig_parser支持的组件都在这个文件里: kaldi/egs/steps/libs/nnet3/xconfig/parser.py

这些组件可以分为以下几类:

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_14

  • Basic layer
  • Activation & Normalization
  • Recurrent layer
  • Convolution layer
  • Attention layer

这些组件按情况组在一起,可以DIY自己的网络。

下面介绍常见的网络模型。

Kaldi中的常见的神经网络

TDNN

一个简单的TDNN

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_15


看一下它的final.config

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_16


Append:拼接

offset:相对于当前位置的偏移,-3向历史时刻偏移3时刻,+3向未来。一个稍微复杂的TDNN

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_17


pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_18

除了拼接,实现加的操作sum
直接把tdnn3的0时刻接到tdnn5
scale对某个层的输出放大、缩小

CNN

一个简单的CNN

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_19


用了conv-relu-batchnorm的组件

height就是FBank的维数,time-offset就是卷积核kernel的大小

代码里描述的就是一个3 *3 的卷积核

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_20


这样的组件解析出的final.config:

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_21


大多数参数和之前的一样,多了个height-subsample-out,指高度上的降采样率,因为输入高度height-in和输出高度height-out都是40,所以没有降采样,所以这里等于1。

另一个要注意的,num_filters_out=64,所以后面跟的component要有 block-dim=64,不然初始化模型时候会报错。

注:这里为了方面给大家看,里面有 /的换行符号,实际中kaldi是不允许有的。

LSTM

一个简单的LSTM

就多了个lstm-layer 和 cell,delay=3就是三次循环

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_22

先回归一下LSTM的网络结构:

输入xt,,历史信息rt ,输出yt。细胞核Ct

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_23

看下final-config:

因为比较复杂,下图删除了DNN的部分

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_24


下面看看component和LSTM的公式是怎么联系起来的?

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_25


比如,以输入门为例

it 可以从图中看到有三个输入箭头,

Wix和Wir对应上面代码的第一部分(前三行)

Wic对应第二部分(中间三行),向后偏移3个时刻

第三部分就是激活函数

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_26

再看个细胞核Ct的计算过程:

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_27


pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_28


ElementwiseProduct就是点乘。

总结以下:

上面学习了如何使用Xconfig提供的组件搭建TDNN等这些网络,从component中看和公式的对应关系。等熟练了这些,就可以自己DIY网络结构。

pytorch神经网络语音情绪识别 语音识别 神经网络_pytorch神经网络语音情绪识别_29

神经网络训练流程

如何使用定义好的神经网络进行训练?

先看一个标准DNN训练的脚本:

feat-cmvn-opts:是否对参数归一化

训练前后期的jobs数,和学习率lrate,还可以用以前的egs,需不需要删掉,每多少步保存,是否用GPU,需要的文件地址,训练结束后模型存储位置

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_30


stage:描述控制训练流程

那标准的训练流程包含哪些步骤呢?

init初始化stage不控制

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_31

  • egs:表示examples,训练使用的样例。把输入数据和标签换了一种方便读取的格式,整合在一起生成的文件。
  • LDA:一般放在神经网络第一层
    计算LDA变换矩阵与pre softmax矩阵就是训练的小技巧,一般数据集小的时候用到,数据量大的时候不用(此时对数据规整起不到太大作用,甚至有反作用)
  • stage=50,从50轮开始继续训练

一个重要的步骤egs:
stage=-4
这个目录下会生成四组文件

exp/$dir/egs

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_32

  • egs相关文件
    egs.{n}.ark:训练数据易于读写的,有利于训练的形式
    {t,v}_diagnostic.egs:计算模型在训练集t上的loss和验证集v上的loss
    combine.egs:训练结束后,用来合并多个模型的egs
  • 辅助文件
    tree:输出节点的个数,从而确定egs的标签的上限
    ali_special.scp和{t,v}_uttlist用来辅助生成{t,v}_diagnostic.egs
  • info
    总共有多少egs,多少帧等信息

egs内部的具体信息:

参数信息:

左右context,每个egs中有8帧语音,每个大的egs里有383176个egs,特征维度feat_num,num_frames用来训练的羽音帧数,num_archives最后生成的egs个数

pytorch神经网络语音情绪识别 语音识别 神经网络_人工智能_33


egs内部:

每个大的egs里有383176个小的egs,下面看小的egs,是kaldi读取输入输出数据的最小单元。从上面的参数知,这个小的egs里有8帧有效帧,但下图中的input是40,是包含了context的(19+13+8)

pytorch神经网络语音情绪识别 语音识别 神经网络_初始化_34


整个训练的结果

final.raw只有神经网络的参数

final.mdl是在.raw的基础上增加了些信息

pytorch神经网络语音情绪识别 语音识别 神经网络_语音识别_35


Priors:先验向量

单纯的神经网络只是计算出来后验概率,再结合TransitionModel和priors计算似然分数,才能得到声学模型

final.mdl是声学模型,final.raw只是神经网络模型