Nnet3配置中的上下文和块大小
简介
本页讨论了nnet3配置中关于解码和训练的块大小以及左右上下文的某些术语。这将有助于理解一些脚本。目前,从脚本角度来看,没有任何关于nnet3的"概述"文档,所以这是nnet3唯一的文档。
基础
如果您已阅读了"nnet3"配置的以前的文档,您会发现"nnet3"不仅支持简单的前馈DNN,还可以实现在网络内层进行时间拼接(帧拼接)的时延神经网络(TDNN)并且还用于recurrent拓扑(RNN,LSTM,BLSTM等)。所以nnet3有时间轴的概念。下面我们确定一些术语。
左右上下文
假设我们想要一个网络来计算特定时间索引的输出;具体来说,假设时间t=154,在网络内部进行帧拼接(或任何其他与"t"索引无关的内容),如果没有给出当前帧的左右一定范围的帧,则可能无法计算当前帧的输出。例如,如果没有看到t = 150到t = 157这个范围内的帧,则可能无法计算输出。在这种情况下(掩饰细节),我们会说网络有一个左上下文4和右上下文3。上下文的实际计算有点复杂,因为它必须考虑到特殊情况,例如奇数和偶数"t"值的情况是不同的。
在有recurrent拓扑的情况下,除了"所需的"左右上下文外,训练或解码时,我们还要给予"额外的"上下文。对于这种拓扑,网络可以利用超出所需上下文的上下文。在脚本中,通常会看到名为extra-left-context和extra-right-context的变量,这意味着"除了需要的内容之外,我们将提供的上下文的数量"。
在某些情况下,左上下文和右上下文意味着添加到块(chunk)中的总的左上下文和总的右上下文,即
左上下文=模型左上下文+额外左上下文
右上下文=模型右上下文+额外右上下文
因此,在某些情况下,您需要搞清楚一个变量指的是模型的左右上下文还是数据块的左右上下文。
在Kaldi5.0及更早版本中,数据块中的左右上下文不受块大小在开头或结尾的影响;在最后我们用第一或最后一帧的副本填充输入。这意味着对于recurrent拓扑,我们可能会用很多帧(最多40个左右)来填充语句的开始或结束。这没有意义而且很奇怪。在版本5.1和更高版本中,您可以指定extra-left-context-initial和extra-right-context-final,允许话语的开始/结束具有不同的上下文量。如果您指定这些值,通常将它们都指定为0(即没有额外的上下文)。但是,为了与旧版本的后台兼容,它们通常默认为-1(意思是复制默认的左上方和右上方)。
块大小
块大小是我们在训练或解码中每个数据块的(输出)帧的数量。在get_egs.sh脚本和train_dnn.py中,它也被称为frames-per-eg(在某些上下文中,这与块大小不同;见下文)。在解码中,我们把它称为frame-per-chunk。
非循环,非chain模型的例子
对于使用交叉熵目标函数训练的前馈网络或TDNN等非常简单的网络类型,我们在帧级别上打乱整个数据集,并且我们一次只训练一帧。为了使大部分训练做顺序I/O,需要在帧级别上对数据进行随机化。然而,当需要10帧的左右上下文时,我们必须给出左右上下文中具体是哪些帧,当我们生成训练示例时,数据量会增加20倍左右。为了解决这个问题,我们包括一系列时间值的标签,由frame-per-eg(通常为8)控制,并包括足够的左/右上下文,我们可以在这8个帧中的任何一个上训练。然后,当我们训练模型时,任何给定的训练工作将选择其中一个8帧进行训练。
经常性或连锁案例
在RNN或LSTM模型或"Chain"模型中,我们总是训练相当大的块(通常在40到150帧的范围内)。这被称为块大小。当我们解码时,我们还通常在相当大的数据块(如30,50或100帧)上评估神经网络。这通常被称为每帧的帧。对于经常性网络,我们倾向于确保在训练和解码中大块/每帧/左右上下文和右上下文大致相同,因为这通常给出最佳结果(尽管有时最好使解码中的上下文值稍大一些)。人们可能会期望在解码时间更长的情况下总是会更好,但是并不总是这样(然而,请参见下面的循环解码,我们在这里提到一个方法)。
块大小与帧 - 子采样因子的相互作用
在输出处有帧子采样的情况下(如链模型),块大小仍然以"t"的倍数进行测量,我们确保(通过在代码中舍入),它是帧抽样因子。请记住,如果块大小为90,帧子采样因子为3,那么我们只对每个90帧的块估计30个不同的输出索引(例如t = 0,t = 3 ... t = 87)。