音声認識メモ(Kaldi)その15(活性化関数 Dan's DNN(nnet2))

活性化関数に関するメモ。

公式サイトの隠れ層に関する説明には、"tanh"(双曲線正接関数)と"p-norm"が登場する。

この”p-norm”というのは、論文によると活性化関数"maxout"からヒントを得た独自版らしい。

「egs/rm/s5/local/run_nnet2.sh」のコメントにも書かれているように、nnet2では、"p-norm"がプライマリレシピとなっている。

「egs/rm/s5/local/run_nnet2.sh」(use_gpu=false)
# This one is on top of 40-dim + fMLLR features, it's a fairly normal tanh system.
local/nnet2/run_4c.sh --use-gpu false

# **THIS IS THE PRIMARY RECIPE (40-dim + fMLLR + p-norm neural net)**
local/nnet2/run_4d.sh --use-gpu false


「local/nnet2/run_4d.sh」は内部で「steps/nnet2/train_pnorm_fast.sh」を呼び出しており、その中で「nnet2bin/nnet-train-simple」コマンドを実行する。

「nnet2bin/nnet-train-simple」コマンド
Train the neural network parameters with backprop and stochastic gradient descent using minibatches.  
Usage:  nnet-train-simple [options] <model-in> <training-examples-in> <model-out>

インプットとなる特徴量が13次元、出力となるpdf-class数が「6」のモデルの構成例は以下のとおり。
全体は7層の構成で、以下のコンポーネント

  • AffineComponentPreconditionedOnline
  • PnormComponent
  • NormalizeComponent

が隠れ層に該当する。

モデル
<Nnet>
<NumComponents> 7 
<Components>
<SpliceComponent> 
    <InputDim> 13 <Context> [ -4 -3 -2 -1 0 1 2 3 4 ]<ConstComponentDim> 0 
</SpliceComponent> 
<FixedAffineComponent> 
    <LinearParams>  [ (snip) 117row x 117col ]
    <BiasParams>  [ (snip) 1row x 117col ]
</FixedAffineComponent> 
<AffineComponentPreconditionedOnline> 
    <LearningRate> 0.02 
    <LinearParams>  [ (snip) 1000row x 117col ]
    <BiasParams>  [ (snip) 1row x 117col ]
    <RankIn> 20 <RankOut> 80 <UpdatePeriod> 4 <NumSamplesHistory> 2000 <Alpha> 4 <MaxChangePerSample> 0.075
</AffineComponentPreconditionedOnline> 
<PnormComponent> 
    <InputDim> 1000 <OutputDim> 200 <P> 2 
</PnormComponent> 
<NormalizeComponent>
     <Dim> 200 <ValueSum>  [ ]  <DerivSum>  [ ]  <Count> 0
</NormalizeComponent> 
<AffineComponentPreconditionedOnline>
    <LearningRate> 0.02 
    <LinearParams>  [ (snip) 6row x 200col ]
    <BiasParams>  [ (snip) 1row x 6col ]
    <RankIn> 20 <RankOut> 80 <UpdatePeriod> 4 <NumSamplesHistory> 2000 <Alpha> 4 <MaxChangePerSample> 0.075 
</AffineComponentPreconditionedOnline> 
<SoftmaxComponent> 
    <Dim> 6 <ValueSum>  [ (snip) 1row x 6col ]
    <DerivSum>  [ (snip) 1row x 6col ]
    <Count> 396 
</SoftmaxComponent> 
</Components> 
</Nnet>

「nnet2bin/nnet-train-simple」コマンドの内部処理の流れを確認してみる。
minibatch-sizeは「64」を指定した。
まずは、Propagateから。

コンポーネント「SpliceComponent」により、13次元から117次元にする。
続けて、コンポーネント「FixedAffineComponent」により、無相関化(117次元のまま)
続けて、コンポーネント「AffineComponentPreconditionedOnline」により、次元数を「1000」にする。

ここまでで得られたアウトプットは、64row x 1000colになる。
続いて、コンポーネント「PnormComponent」。デフォルトは「p=2」の2-norm(論文に、これが一番パフォーマンスが良かったとある)
inputが「1000」次元、outputが「200」次元なので、5次元ごとにグループ化する。

グループ化前

f:id:ichou1:20180610115640p:plain

グループ化後

f:id:ichou1:20180610120234p:plain

続けて、コンポーネント「NormalizeComponent」により正規化する。
続けて、コンポーネント「AffineComponentPreconditionedOnline」により、次元数を「6」にする。
(ここまでで得られたアウトプットは、64row x 6col)

最後に、コンポーネント「SoftmaxComponent」により各pdf-classごとの出力確率を求める。

一番目のフレームの結果
 0.1746  0.0040  0.7098  0.0007  0.0889  0.0217

小数点第5位以下は切り捨て

尚、このデータに関しては、4番目のデータ(確率が「0.0007」)が"正解"となる。

この誤差をもとに、Backpropagationによりモデルのパラメータを更新する。