統計的声質変換 (4) パラレルデータの作成
統計的声質変換 (3) メルケプストラムの抽出(2015/3/4)の続き。
前回は変換元のclbさんと変換先のsltさんのメルケプストラムを一括抽出した。前回の最後の結果を見ると、二人のしゃべる速さが違うためメルケプストラムが時間方向にずれていることがわかった。たとえば、下の図は青色がclbさんのメルケプストラム系列、緑色がsltさんのメルケプストラム系列を表している。赤の矢印の場所で形状が似ているが位置がずれていることがわかる。
このずれはメルケプストラム間の変換モデルを学習するときに問題になるため時間同期を取る。この時間同期を取ったデータをパラレルデータと呼ぶ。
DTW (Dynamic Time Warping: 動的時間伸縮法)
この二つの時系列データの時間同期を取るアルゴリズムにDTWというのがあるので使ってみる。DTWは、二つの時系列データがなるべく重なりあうように伸ばしたり、縮めたりして、二つの時系列の最小距離を求めるアルゴリズムである。二つの時系列の長さが異なっていても距離を求められるので大変便利。
DTWは、本来、最小距離を求める手法であるが、伸縮した二つの時系列のどことどこが対応するかを表す経路情報(path)も返してくれる。今回はこの経路情報を使ってアラインメントを取った時系列データを得ている。距離は使わない。DTWを求めるPythonライブラリdtwがあるので使ってみよう。pipで簡単にインストールできる。
pip install dtw
今回の問題は26次元メルケプストラムの2つの時系列なので、DTWで距離を求める際には26次元ベクトル同士の距離を最小化する必要がある。Pythonのdtwライブラリはここら辺もよく考えられていて行方向に時間、列方向に特徴量がある2つの行列を入れてもまったく問題なく動作する。デフォルトの距離尺度はL1ノルム(マンハッタン距離)である。
# オリジナルのmcepを読み込み mcep1 = np.loadtxt(os.path.join(mcep_dir1, mcep_file)) mcep2 = np.loadtxt(os.path.join(mcep_dir2, mcep_file)) # DTWで同期を取る dist, cost, path = dtw(mcep1,mcep2) aligned_mcep1 = mcep1[path[0]] aligned_mcep2 = mcep2[path[1]]
pathには二つのメルケプストラム時系列においてDTWで対応のとれたインデックス列が入っているためこれをインデックスとして元の配列に当てはめればアラインメントされた二つの時系列が得られる。DTWを取ったあとのメルケプストラム系列は同じ長さになる。
パラレルデータの作成
時間同期のとれたパラレルデータを作成するスクリプトは下のような感じ。
元の時間同期がとれていない二つのメルケプストラムのディレクトリと時間同期を取ったあとのメルケプストラムのディレクトリを指定してコマンドを実行すればよい。
python align_mcep.py mcep/clb mcep/slt aligned_mcep_clb_slt/clb aligned_mcep_clb_slt/slt
いくつか可視化してずれていたのが本当にきっちりそろうか確かめよう。左側がDTWする前のメルケプストラム系列(0次、1次、2次の係数)、右側がDTWした後のメルケプストラム系列(0次、1次、2次の係数)である。
まあ対応が取れなくて苦しい箇所(300フレームより後ろ)もあるけど山、谷の位置はそろっていることが確認できた。対応が取れない箇所は声質の個人差による違いなんだろうと理解している。もう一個別の例(チュートリアルと同じarctic_a0028
)
ちゃんと対応が取れていることがわかる。
次回はいよいよこのパラレルデータを使って、GMMの声質変換モデルを学習するところをやってみたい。
おまけ
上のグラフは下のようなコードで描いた。