ichou1のブログ

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

音声認識メモ(DeepSpeech)その4

前回の続き。
それなりの認識精度が出ることを確認した。

ここから、認識精度を高めること、汎化させることを考えてみる。


コーパスの音声ファイル認識

まずは、別の音声コーパスを試してみる。

「東北大‐松下 単語音声データベース (TMW)」の単語音声「さっぽろ」
http://research.nii.ac.jp/src/sample/TMW/sapporo.wav

音声ファイルフォーマットは下記のとおりなので、

  • WAV形式
  • サンプリングレートは24000Hz
  • モノラル
  • 量子化ビットは16bit

レーニングに使った音声データに合わせて、下記のとおり音声データを変換する。

音声データのフォーマットを確認するコマンド
% ffprobe sapporo.wav

出力内容。

Input #0, wav, from 'sapporo.wav':
  Duration: 00:00:00.96, bitrate: 384 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 24000 Hz, 1 channels, s16, 384 kb/s
rawデータに変換するコマンド
% sox sapporo.wav -c 1 -b 16 -r 16000 -B sapporo.raw
rawデータを再生するコマンド
% aplay -f S16_BE -c 1 -r 16000 -t raw sapporo.raw

出力内容。

Playing raw data 'sapporo.raw' : Signed 16 bit Big Endian, Rate 16000 Hz, Mono


特徴量変換

まずは、下記のサイトと同じように処理してみる。
Connectionist Temporal Classification (CTC) を用いた音素認識 - Qiita

プリエンファシスフィルタで高周波数成分を強調する。
(librosaでも「librosa.effects.preemphasis」が提供されているが、index=0の値が異なるので、一旦、使うのをやめた)

また、デルタ特徴量を利用しており、「hop_length」は短め。

def convert_raw2feature(filename):

    raw = np.fromfile(filename, dtype=">i2").astype(np.floating)
    raw /= 32768.0

    # Apply pre-emphasis
    preemp = 0.97
    raw = np.append(raw[0], raw[1:] - preemp * raw[:-1])

    # wav = librosa.effects.preemphasis(wav, coef=0.97)
    # wav[0]の結果が異なる

    mfcc = librosa.feature.mfcc(raw,
                                sr=16000,
                                n_mfcc=13,
                                n_fft=400,
                                hop_length=80)

    mfcc_d = librosa.feature.delta(mfcc)

    feature = np.hstack([mfcc.T, mfcc_d.T]).astype(np.float32)
    # --> ([time_step, n_mfcc_bin * 2 ])

    return feature

また、データセットに対して標準化を行っており、今回のケースで変換に使用される値は下記のとおりだった。
標準偏差は大きいもので万単位になっている)

print(standardScaler.mean_) 
array([-6.03137595e+02,  4.69243823e+01,  1.63922197e+00,  2.39632467e+01,
       -4.56492346e+00, -1.31808039e+01,  7.18608905e+00, -1.32614235e+01,
        3.81127013e+00, -9.26037876e+00,  1.90375874e+00, -2.03618908e+00,
       -1.84540626e+00, -3.49735385e-02, -9.00939025e-03,  1.06467587e-02,
       -2.11240141e-03,  2.24677342e-03,  1.14668469e-03,  1.97442675e-03,
        3.31492807e-03, -3.72433226e-05,  1.99914176e-04,  3.13600081e-04,
        2.29132316e-03, -5.89357647e-04])
print(standardScaler.var_) 
array([3.02913037e+04, 4.93898671e+03, 1.06912426e+03, 1.49455852e+03,
       6.42337009e+02, 4.88071033e+02, 3.17810853e+02, 4.69107250e+02,
       1.76112625e+02, 3.59232739e+02, 1.97207413e+02, 1.40350071e+02,
       1.55652514e+02, 3.08672145e+02, 6.61977674e+01, 2.02392192e+01,
       1.82274866e+01, 1.23345957e+01, 7.68737450e+00, 5.89708586e+00,
       8.50219827e+00, 4.15742956e+00, 4.68084419e+00, 3.67778480e+00,
       3.02519577e+00, 2.90401724e+00])

インプットデータに対しては下記の変換が行われる。

X_new = (X_org - standardScaler.mean_ ) / standardScaler.var_

認識結果

認識対象のデータが、トレーニングに使ったデータセットの集合に属する場合は標準化が妥当と考えるが、そうでない場合は何かしらの変換を考える必要がある。

2パターンでの結果を示す。

標準化しないと、全て'sil'になってしまう。

レーニング時のデータセットで標準化
['_', 'sil', 'sil', 'sil', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'Q', 'Q', 'h', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 's', 's', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'a', 'a', 'a', 'a', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'Q', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'p', 'p', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'r', 'r', 'r', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'o', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'sil', ... ]

冒頭に余分な音素('Q'、'h')が入ってしまっているが、認識できている。

インプットデータで標準化
['sil', 'sil', 'sil', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'r', 'r', 'h', 'h', 'sil', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'a', 'a', 'a', 'a', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'pau', 'pau', 'pau', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'b', 'b', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'r', 'r', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'o', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'sil', ... ]


さらに、別の別コーパスのデータで試してみる。
(認識結果が悪くなりそうな「子供の声」を選んだ)

「近畿大 児童の単語音声データベース (JWC)」の単語音声「ジェット機
http://research.nii.ac.jp/src/sample/JWC/2_648.wav

レーニング時のデータセットで標準化
['sil', 'sil', 'sil', 'sil', 'sil', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'h', 'I', 'I', 'I', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'r', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'k', 'I', 'I', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'sil', ... ]
インプットデータで標準化
['sil', 'sil', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'sh', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'e', 'e', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'o', 'Q', 'Q', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'o', 'o', 'o', 'o', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'k', 'k', 'k', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', 'sil', ... ]

こちらの方が想定に近しい。