ichou1のブログ

主に音声認識、時々、データ分析のことを書く

音声認識メモ(Kaldi)その14(特徴量変換 Dan's DNN(nnet2))

LDA変換用パラメータは教師データの統計をもとに作成する。
統計データ作成には「bin/acc-lda」コマンドを使う。

「bin/acc-lda」コマンド
Accumulate LDA statistics based on pdf-ids.
Usage:  acc-lda [options] <transition-gmm/model> <features-rspecifier> <posteriors-rspecifier> <lda-acc-out>

インプットは以下のとおり。

  • モデル(GMM-HMM)
  • 教師データとなる特徴量(正規化済み)
  • 教師データのアライメント結果から作成した事後確率
事後確率(pdf-id)
utterance_id_001 [ 206 1 ] [ 208 1 ] [ 210 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 209 1 ] [ 242 1 ] [ 244 1 ] [ 246 1 ] [ 266 1 ] [ 268 1 ] [ 270 1 ] [ 194 1 ] [ 196 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 195 1 ] [ 198 1 ] [ 218 1 ] [ 220 1 ] [ 222 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 221 1 ] [ 242 1 ] [ 244 1 ] [ 246 1 ] [ 266 1 ] [ 268 1 ] [ 270 1 ] [ 188 1 ] [ 190 1 ] [ 192 1 ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] 

[ ]内の1列目がpdf-id、2列目が事後確率(weight)を表す
[ ]内がブランクのものはsilenceを表す(weightが「0.0」)

モデルは「pdf-id」を「pdf-class」に読み替えるために使う。
「pdf-class」に読み替えたものは以下のとおり。

(参考)事後確率(pdf-class)
utterance_id_001
[ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 4 1 ] [ 4 1 ] [ 4 1 ] [ 5 1 ] [ 5 1 ] [ 5 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 3 1 ] [ 4 1 ] [ 4 1 ] [ 4 1 ] [ 5 1 ] [ 5 1 ] [ 5 1 ] [ 2 1 ] [ 2 1 ] [ 2 1 ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] 

[ ]内の1列目がpdf-id、2列目が事後確率(weight)を表す
[ ]内がブランクのものはsilenceを表す(weightが「0.0」)

今回、特徴量を2次元だけにして、パラメータの算出過程をトレースしてみる。

特徴量(198row x 13colのデータから1次元目と2次元目だけを切り出したもの、198row x 2col)
utterance_id_001  [
  16.92272 7.178926
  4.827858 0.9412766
  -3.098977 -18.89928
  -3.82908 -10.80018
  5.34936 1.858578
  12.67259 11.39851
  8.422453 -14.75593
  9.636777 -7.864816
  9.636777 -17.51817
  (snip)
  -4.976385 9.013528
  -3.93338 10.29775
  -4.976385 13.56448
  -4.767784 12.44007
  -8.559893 7.545846 ]

プロット
f:id:ichou1:20180524212516p:plain
pdf-classのindexは「0」始まり
"X"は各pdf-classごとの平均を表す(黒は全体平均)

全体の分散共分散行列
498.761   96.582
 96.582  166.250

1次元(dim_1)の平均: 0.430
2次元(dim_2)の平均: -3.985

1次元(dim_1)の標準偏差: 22.333
2次元(dim_2)の標準偏差: 12.894

1次元と2次元の相関係数: 0.335

コマンドのアウトプット

f:id:ichou1:20180520115146p:plain

  • "VECSIZE" : 特徴量の次元数
  • "NUMCLASSES" : pdf-classの個数
  • "ZERO_ACCS" : pdf-classごとのフレーム数
  • "FIRST_ACCS" : pdf-classごとにフレームの特徴量の値を足しあわせたもの
  • "SECOND_ACCS" : 分散共分散行列の途中計算結果(各次元ごとの分散と共分散)

"SECOND_ACCS"は、フレーム数で割る前の値、平均を引く前の値が格納される。

LDA統計量をもとに、「nnet2bin/nnet-get-feature-transform」コマンドを使ってLDA変換のパラメータを算出する。

「nnet2bin/nnet-get-feature-transform」コマンド
Get feature-projection transform using stats obtained with acc-lda.
Usage:  nnet-get-feature-transform [options] <matrix-out> <lda-acc-1> <lda-acc-2> ...
全体の分散共分散行列(total_covar)
498.761   96.582
 96.582  166.250

続けて、クラス間(between-class)分散共分散行列を求める。
ここで、クラスとは次元を指す。
各pdf-classの平均をもとにして、1次元(dim_1)と2次元(dim_2)に関する分散共分散行列を求め、全データに占める割合を掛けたものを足し合わせる。

クラス間の分散共分散行列(bc_covar)
14.524   26.249
26.249   59.821

これを特異値分解し、基底ベクトルu1、u2方向の軸をプロット
f:id:ichou1:20180525210309p:plain
特異値は「71.842」、「2.503」

svd_u= 
 0.416  0.909
 0.909 -0.416

u1 = (0.416, 0.909) L2ノルム: 1
u2 = (0.909, -0.416) L2ノルム: 1


続けて、クラス内(within-class)分散共分散行列を求める。
全体の分散共分散行列(total_covar)から、クラス間分散共分散行列(bc_covar)を引く。

クラス内の分散共分散行列(wc_covar)
484.237   70.333
 70.333  106.430

これをLU分解する。
対称行列なので、コレスキー分解を用いる。

分解後のLower Triangular Matrix
22.005  0  
 3.196  9.809

Lの逆行列(L^(-1))を求める。

 0.045  0
-0.015  0.102

これをクラス間(between-class)分散共分散行列に掛け合わせる(左からL^(-1)、右からLT^(-1))。

L.inverse() * bc_covar * LT.inverse()= 
0.030  0.112
0.112  0.546

これを特異値分解し、基底ベクトルu1、u2方向の軸をプロット
f:id:ichou1:20180525211309p:plain
特異値は「0.569」、「0.007」

基底ベクトル
svd_u= 
 0.203  0.979
 0.979 -0.203

u1 = (0.203, 0.979) L2ノルム: 1
u2 = (0.979, -0.203) L2ノルム: 1

ここで、特異値が大きい順に基底ベクトルをソートする。

続けて、基底ベクトルを転置したものにL^(-1)を掛ける。

svd_u= 
 0.203  0.979
 0.979 -0.203

svd_u.transpose() * L.inverse()= 
-0.005   0.100
 0.048  -0.021

u1 = (-0.005, 0.100) L2ノルム: 0.1001
u2 = ( 0.048, -0.021) L2ノルム: 0.0524

f:id:ichou1:20180526112433p:plain

続けて、Scaleを掛ける。
パラメータ「--within-class-factor」が"0.0001"(デフォルト)であるとすると、基底ベクトルu1のScaleは以下のように計算される(特異値は「0.569」)

sqrt (( 0.0001 + 0.569 ) / ( 1.0 + 0.569 ) )
= sqrt ( 0.569 / 1.569)
= sqrt (0.367)
= 0.602

u1 = (-0.003, 0.060) L2ノルム: 0.060
(補足)小数点6位で四捨五入した値
u1 = (-0.003170, 0.060114)

同様に、基底ベクトルu2のScaleを計算する(特異値は「0.00678」)

sqrt (( 0.0001 + 0.007 ) / ( 1.0 + 0.007 ) )
= sqrt ( 0.007 / 1.007)
= sqrt (0.007)
= 0.083

u2 = (0.004, -0.002) L2ノルム: 0.004
(補足)小数点6位で四捨五入した値
u2 = (0.003984, -0.001743)

続けて、全体平均(0.4296, -3.9851)について、u1、u2上に射影したものを求める。

平均ベクトルとu1の内積
( 0.4296 * -0.003170 ) +  ( -3.9851 * 0.060114 ) = -0.240922
平均ベクトルとu2内積
( 0.4296 * 0.003984 ) +  ( -3.9851 * -0.001743 ) = 0.008658
平均をu1上に射影した座標

(0.000763, -0.014482)

平均をu2上に射影した座標

(3.4e-05, -1.5e-05)

平均をu1、u2上に射影した座標をプロット

f:id:ichou1:20180526114636p:plain

平均をu1、u2上に射影した座標をプロット(拡大)

f:id:ichou1:20180526114646p:plain

平均をu1、u2上に射影した座標をプロット(さらに拡大)

f:id:ichou1:20180526114656p:plain

以下が最終的な出力結果で、LDA変換のパラメータになる。

出力結果
[  -0.003  0.060  0.241 
    0.004 -0.002 -0.009 ]

1行目は、基底ベクトルu1(第1成分と第2成分)と、全平均をu1上に射影した値にマイナス1を掛けたもの
2行目は、基底ベクトルu2(第1成分と第2成分)と、全平均をu2上に射影した値にマイナス1を掛けたもの