Table of Contents
目的
- 数少ないデータセットを使用し(100個、総合で約15分)
- ESPnet TTSファインチューニングモデルを作成
学習方法
1.「テキスト→音響特徴」の変換を行う、音響モデルのファインチューニング
Pre-trained モデル:JSUTコーパスで学習した、Tacotron2モデル
2.「音響情報→音声ファイル」の変換を行う、Vocoderのファインチューニング
Pre-trained モデル:JSUTコーパスで学習した、PWG(Parallel WaveGAN)モデル
結果
つくよみちゃんコーパスでファインチューニングしたTTSモデルを貼っておきます。
- つくよみちゃんTTSモデル
- JVSコーパスでファインチューニングした、日本人男性声へのTTSも楽しめます。
ESPnet TTS Recipeの流れ
まず、ファインチューニングの仕方を説明する前に、基本的なESPnet TTS Recipeについて説明します。
前回の記事で説明したように、Recipeはステージというタスクを順番に定義したものを指しますが、TTSのRecipeは次のような流れを持ちます。
-
ステージ①:データダウンロード及び前処理
データセットをダウンロードし、Kaldiスタイルデータ形式作成などの前処理を行います。 -
ステージ②:特徴抽出
使用する音響モデルに従い、必要なデータ特徴を抽出します。 -
ステージ③:発話フィルタリング
短い発話や長い発話を除去します。 -
ステージ④:Tokenリスト作成
テキスト情報のTokenizationを行います。日本語の場合は、主に -
ステージ⑤:TTSモデルの統計量計算
ESPnetでは動的Batchを使用しており、各データのサイズを参考し、学習Batchサイズを調節します。このステージでは- 学習データの統計量を計算し、
- データのシェイプ情報や音響特徴量の平均及び分散を抽出します。
-
ステージ⑥:TTSモデルの学習
「テキスト→音響特徴」の変換を行う音響モデルの学習を行います。ESPnetでは、Tacotron2やFastSpeechなどのTTSモデルを支援しています。 -
ステージ⑦:Vocoderを用いたデコード
Vocoderで「音響特徴→音響ファイル」の変換を行います。ここでは、- 既に学習されているVocoderも使えますが、
- 新たに学習したVocoderを使うことで、音質を高めることができます。
上記Recipeの詳しい内容についてはESPnet Githubで確認できます。
今回は**「新たなデータセット」**でTTSモデルをファインチューニングしますので、いくつかの工夫が必要です。
つくよみちゃんデータセットを用いたTTSモデル
新たなデータセットを使ったファインチューニングRecipeを作成するために、次の3つタスクを行いました。
- つくよみちゃんデータセットの準備(ステージ①)
- Pre trained TTSモデルを用いた、音響モデルのファインチューニング(ステージ⑥)
- Pre trained Vocoderモデルを用いた、Vocoderファインチューニング(ステージ⑦)
ステージ②から⑤までは、既存TTS Recipeをそのまま使えます。私の場合は、ステージ④のOpenJTalkオプションを変換し、Pauseラベル(「,(コンマ)」のような記号に対応)を参考した音素分析を行うようにしました。
e.g. こ、こんにちは
pyopenjtalk_kana
-> [コ, 、, コ, ン, ニ, チ, ワ]
pyopenjtalk_accent
-> [k, 1, 0, o, 1, 0, k, 5, -4, o, 5, -4, N, 5, -3, n, 5, -2, i, 5, -2, ch, 5, -1, i, 5, -1, w, 5, 0, a, 5, 0]
pyopenjtalk_accent_with_pause
-> [k, 1, 0, o, 1, 0, pau, k, 5, -4, o, 5, -4, N, 5, -3, n, 5, -2, i, 5, -2, ch, 5, -1, i, 5, -1, w, 5, 0, a, 5, 0]
上の例は「こ、こんにちは」というテキストが、OpenJTalkオプションによって、どのように分解されるかを表しています。(参考リンク)この音素分析の結果によるTTSモデルの性能差を確認してみます。
- Pauseラベルを使用しない場合
- Pauseラベルを使用する場合
これで、文書の中のコンマなどをしっかり認識し、より人間っぽい音声合成を行うのではないかと期待します。
それでは、上記した3つのタスクについて詳しく説明します。
「ステージ①」のタスク
データセットダウンロードと前処理に関する作業を行うステージで、Recipeの「./local/data.sh」で管理されています。ダウンロードしたファイルの構成を確認し、学習に必要なファイルを取ってくる作業や、ESPnetで読み込める形式で変換する作業などが必要でした。コーパスによって、音声ファイルの形式や音質(ノイズなど)が違いますので、一番手前のかかるタスクだと思います。
- Download
つくよみちゃんコーパスのダウンロードリンクを設定し、学習に使う音声ファイル(*.wav)とテキストファイル(scripts.txt)をコピーします。 - Trim_Silence
各音声ファイルの前後にあるSilenceを除去するタスクです。発話中のPause(記号によるPauseや発話の自然なスキマ)ではないSilenceは、音響情報とテキスト情報のAlignを邪魔するので、TTSの性能向上のために必要な作業です。
ESPnetでは、thresholdデシベル以下の音を感知し、発話の始まりと終わり時間を抽出することができます。(trim_silence.sh) - Subset_Data
Train/Validate/Evaluateに分けてKaldiスタイルデータを生成します。
ESPnetのライブラリーで基本的な作業は処理できますが、データセットによって追加タスクが求められると思います。 実際に、私の場合は次のタスクも必要でした。
wavファイルの読み込み問題
trim_silence.shでは、waveモジュールを用いて、音声ファイルの読み込みを行いますが、つくよみちゃんコーパスの読み込みの祭、エラーが発生しました。音声ファイルの形式に問題がありましたので、次のような形式変換を行いました。
for wav in onlyfiles:
data, sr = sf.read(f'{path_temp}/{wav}', dtype='float32') ## Read original *.wav file with soundfile module
filepath = f'{path_temp}_new/{wav}' ## Write converted *.wav file
_format = "WAV"
subtype = 'PCM_16'
sf.write(filepath, data, sr, format=_format, subtype=subtype)
今回は、上記の作業をJupyter Notebookで行いましたが、この作業をシェルスクリプトで作成し、ステージ①に追加するとより完成度の高いRecipeになると思います。
「ステージ⑥」のタスク
音響モデルをファインチューニングするステージで、学習済みの音響モデルが必要です。ESPnetで提供するPre-trainedモデルを利用することもできますが、私は次の条件で学習したモデルをファインチューニングしました。
- データセット:JSUTコーパス
- 音素分析:pyopenjtalk_accent_with_pause
- 学習モデル:Tacotron2
ファインチューニングするためには、Pre-trainedモデルの学習情報が必要です。ステージ④と⑤から生成された「Tokenリストとデータ統計量」は、新しいデータセットの情報で、Pre-trainedモデルの学習には使用できません。従い、下の2つのファイルをPre-trainedモデルの情報に変更します。
- token.txt:Tokenリスト
- feats_stats.npz:データ統計量
上の設定が終わったら、ESPnetのTTS Recipeを使い、簡単にファインチューニングできます。次のコードを実行することで、新たなデータセットが、Pre-trainedモデルに相応しい情報に変換され、ファインチューニングが行われます。
./run.sh --stage 6 --ngpu 1 --lang jp \
--g2p pyopenjtalk_accent_with_pause \
--train_config conf/tuning/finetune_tacotron2.yaml \
--train_args "--init_param <path of pre-trained.pth> \
--tag finetune_jsut_pretrained_tacotron2
「ステージ⑦」のタスク
Vocoderモデルで生成された音響情報を音声ファイルにDocodeするステージです。 TTSのファインチューニングを通じ、「テキスト→音響情報」変換ができるようになりましたが、Vocoderの性能によってその音質が大きく変わるので、Vocoderのファインチューニングも行いました。
- Vocoder Fine Tune前の声
Pre-trained VocoderはParallel WaveGAN(PWG) Githubから、次の条件で学習されたモデルを使用しました。
- JSUTコーパス
- Parallel WaveGAN
上記のPWG学習モデルも、Kaldiスタイルデータ・Recipe構造を使っていたので、今回前処理したデータセットをそのまま使えました。前回ESPnet紹介記事で説明したように、Kalidスタイル・Recipe構造を活用することで、多様な音声処理プロセスが簡単に実装できます。
# TTSタスクで生成したデータセットのsymlinkを作る。
mkdir dump data
ln -s /<recipe_name>/dump/raw dump/
ln -s /<recipe_name>/dump/raw/train data/train
ln -s /<recipe_name>/dump/raw/dev data/dev
ln -s /<recipe_name>/dump/raw/eval1 data/eval
# PWGのパラメータを設定する。
# conf/parallel_wavegan.v1.yaml
# PWG Recipeのstage1で、ファインチューニングする。
./run.sh --stage 1 --conf conf/parallel_wavegan.v1.yaml
ファインチューニングの結果
つくよみちゃんのデータセットを使用して、ESPnetのTTSモデルを作って見ました。ESPnetのお陰で、簡単にファインチューニングできたと思います。
- オリジナルのつくよみちゃん声
- TTSで生成したつくよみちゃん声
上の音声ファイルは学習に使用したつくよみちゃんの声と、TTSモデルで生成した声です。オリジナル音声に比べると、少しノイズが乗せていますが、「100個という数少ないデータセット(約15分)」を考えると良い結果だと思います。
ぜひ皆さんもつくよみちゃんTTSモデルを使って、自分のセリフで音声合成を試してみてください。
まとめ
新たなデータセットを使ってTTSモデルをファインチューニングしてみました。ESPnetを使うことで、複雑な音声処理プロセスが簡単に実装できました。ステージ①のデータセットの用意が上手くできれば、TTSモデルだけでなく、様々な音声処理モデルが簡単に作成できると思います。
また、データセットや学習時間を増やしたり、ノイズを除去した音声ファイルを使用したりすることで、より良いTTSモデルが得られると思います。公開したつくよみちゃんTTSモデルは、これからも更新していく予定なので、楽しみにしてください!
使用したデータセットは、「つくよみちゃんコーパス」の100個の発話データであり、データの数が少なかったので、ファインチューニングを通じモデルを構成しました。
- TTSの学習には、フリー素材キャラクター「つくよみちゃん」が無料公開している音声データを使用しています。
- つくよみちゃんコーパス(CV.夢前黎)
https://tyc.rei-yumesaki.net/material/corpus/
Han Beomseok
Python, AI Engineering, Natural Language