lispmeetup #45 common lispで音声合成

22
Common Lispで音声合成 Satoshi Imai / 今井 悟士 Twitter: @masatoi 0 Github: masatoi

Upload: satoshi-imai

Post on 15-Apr-2017

869 views

Category:

Software


1 download

TRANSCRIPT

Common Lispで音声合成

Satoshi Imai / 今井 悟士

Twitter: @masatoi0 Github: masatoi

これまでの発表

● #29: 線形分類器cl-online-learningの実装

– http://www.slideshare.net/masatoi0/lispmeetup29-c

lonlinelearning

● #39: ディープラーニング用ライブラリMGLの紹介

– http://www.slideshare.net/masatoi0/lispmeetup-39

-mgl

今回の目標

● ディープラーニングの応用として音声合成(テキスト読

み上げ)を試みる → 未完!

– ここまでの成果物: https://github.com/masatoi/cljtalk

● DNN音声合成の全体の流れを把握する

– Common Lispで実装するために必要な道具を揃える

● 音素アライメント → Julius、segmentation-kit

● 音声分析合成 → WORLD、cl-libworld

● メル周波数ケプストラム(MFCC) → libfftw3

色々なTTSシステム

● 波形接続型音声合成 (VOICEROID (結月ゆかり etc))

– 小さい音声の素片を連結して合成する

● 統計的音声合成

– HMM (CeVIO (さとうささら etc)、 Open JTalk)

● HMM(隠れマルコフモデル)を使うもの

– DNN

● 単純なFFNNを音声に適用 (簡単!)

– LSTM-RNN (Googleテキスト読み上げ)

● 再帰型ニューラルネット

– Wavenet (DeepMind) ← new!

色々なTTSシステム

● 統計的音声合成

– HMM

– DNN

– LSTM-RNN

– Wavenet

● ボコーダーを介さず直接音声を予測する

● 畳み込みニューラルネットで自己回帰(自分の予測を入力の一

部として与える)

● ボコーダーを使う

生の音声ではなく、音声を少数のパラメータに変換してそれを予測する

再合成時に劣化する

ボコーダー(音声分析合成)

● 生の音声からパラメータを取り出したり再合成したりする

● WORLD

– C++の音声分析合成ライブラリ

● cl-libworld

– https://github.com/masatoi/cl-libworld

– Common Lisp用のラッパーをCFFIで実装した

– WORLDのコードを丸抱えして、require時にLakeでビルドする

基本周波数(F0)

音の高さ

パワースペクトル

周波数毎の強さ 声道(口の形)を表す

非周期性指標

声のかすれ具合

1フレームは5ms

メル周波数ケプストラム

● まだパラメータ数が多いのでもっと圧縮したい

● メルフィルタバンク

– 人間の耳にとって重要な周波数帯のスペクトルを重点的に

取るためのフィルタ

メル周波数ケプストラム

● まだパラメータ数が多いのでもっと圧縮したい

● メルフィルタバンク

● スペクトルにメルフィルタバンクを掛けて対数変換する

かけてから対数変換

メル周波数ケプストラム

● 離散コサイン変換(DCT)する

– 低周波帯に情報が集まる

● 上の方は切ってもいい! → 13次元でカット

● ここまでやったもの: メル周波数ケプストラム係数(MFCC)

– DCTはCのライブラリFFTWを使う(CFFIでラップ)

DCT DCTの逆変換

MFCCから音声まで戻す

● DCTの逆変換は無劣化でできる (上を切らなければ)

● それからexpをかける

● 元のスケールに戻して、スプライン補間をかける

スケール変換スプライン補間

exp

MFCCから音声まで戻す

● スプライン補間

– データ点の間を三次曲線で滑らかに繋ぐ

– データ数のサイズの逆行列を計算する必要があるが、三重対角行

列なのでO(N)でできる

DNNの出力データを作る

● 非周期性指標はDCTで5次元まで圧縮する

● F0が1次元、スペクトルが13次元、非周期性指標が5次元で1フレーム当たり19

次元の特徴量になる

入力データを作る

● 音素アライメント

– テキストデータと音声から音素の開始時間と終了時間を

推定する

– Juliusのsegmentation-kitが使える

0.0000000 0.0925000 silB0.0925000 0.2625000 a0.2625000 0.4125000 i0.4125000 0.5225000 u0.5225000 0.5825000 e0.5825000 0.7525000 o0.7525000 0.7825000 silE

あいうえお

入力データを作る

● 音素アライメント

– テキストデータと音声から音素の開始時間と終了時間を

推定する

0.0000000 0.0925000 silB0.0925000 0.2625000 a0.2625000 0.4125000 i0.4125000 0.5225000 u0.5225000 0.5825000 e0.5825000 0.7525000 o0.7525000 0.7825000 silE

入力データを作る

● 音素をフレームに割り当てる

– 一つのフレーム毎の特徴量

● どの音素に属しているか? → 38次元のバイナリ特徴

● その音素の継続時間(duration) 1→ 次元の実数

● その音素が割り当てられているフレームの中で何番目か

→ 1次元の整数

DNNの構造

“Deep Learning in Speech Synthesis” [H.Zen, 2013]

T個のフレームの特徴量を一列に並べてDNNの入出力とする

MGLとは

● Common Lisp用の機械学習ライブラリ

● ディープラーニングの割と最近の手法までカバー

● MGL-MATという行列演算ライブラリを使う

– cl-cuda、LLA(Lisp Linear Algebra)によって高速化

● cl-cudaがQuicklispに入ったことによりMGL-MATもQuicklispから入

るようになった!

MGLで回帰問題を解く

● 回帰のやり方はドキュメントが無いのでMGLのソースと格闘する

● まず簡単な2次元→1次元の関数を近似する

元の関数 近似結果

(defun rastrigin (x­list)  (let ((n (length x­list)))    (+ (* 10 n)       (loop for xi in x­list summing

 (­ (* xi xi) (* 10 (cos (* 2 pi xi))))))))

MGLで回帰問題を解く

● build-fnnマクロでネットワークの構造を指定してオブジェクトを生成

– 入力層2次元、1200次元の隠れ層が3層、出力層1次元

– 隠れ層の活性化関数はReLU、出力層の活性化関数は恒等写像、誤差関数は

二乗誤差

(defparameter fnn­regression  (build­fnn (:class 'regression­fnn :max­n­stripes 100) ; バッチサイズ100    ;; Input Layer 2次元    (inputs (­>input :size 2))    (f1­activations (­>activation inputs :name 'f1 :size 1200))    (f1 (­>relu f1­activations))    (f2­activations (­>activation f1 :name 'f2 :size 1200))    (f2 (­>relu f2­activations))    (f3­activations (­>activation f2 :name 'f3 :size 1200))    (f3 (­>relu f3­activations))    (prediction­activations (­>activation f3 :name 'prediction :size 1))    ;; Output Lump:  squared­difference 1→ 次元    (prediction (­>loss (­>squared­difference (activations­output prediction­activations)                                              (­>input :name 'targets :size 1))                        :name 'prediction))))

DNN音声合成のためのモデルを作る

● 一度にDNNに与えるフレーム数Tを20とする

● 入力40*20=800次元、出力19*20=380次元

● しかしこれで学習してみると数値計算エラー!

(defparameter fnn  (build­fnn (:class 'regression­fnn :max­n­stripes 100)    ;; Input Layer    (inputs (­>input :size 800))    (f1­activations (­>activation inputs :name 'f1 :size 512))    (f1 (­>relu f1­activations))    (f2­activations (­>activation f1 :name 'f2 :size 512))    (f2 (­>relu f2­activations))    (f3­activations (­>activation f2 :name 'f3 :size 512))    (f3 (­>relu f3­activations))    (prediction­activations (­>activation f3 :name 'prediction :size 380))    ;; Output Lump: ­>squared­difference    (prediction (­>loss (­>squared­difference (activations­output prediction­activations)                                              (­>input :name 'targets :size 380))                        :name 'prediction))))

まとめ

● 音声合成のための特徴量を揃えたが肝心のDNNの学習に失敗

– 出力が多次元のより単純な回帰問題で学習の進行を観察する

● 入力の特徴量もアクセントやイントネーションを無視しているので、テキ

ストを分析してこれらの情報を付与するようにしたい

– さらにユーザが簡単にアクセントなどを調整するためのGUIを用意

● CFFIでCのライブラリが簡単に呼べるのでライブラリ不足は感じない

– 今回はWORLDとFFTWのラッパーを書いた