見出し画像

NVIDIA/tacotron2 で日本語の音声合成を試す (2) - JSUTで学習

前回、「Japanese Single Speaker Speech Dataset」を使った音声合成を行いました。次は「つくよみちゃんコーパス」といきたいところですが、「つくよみちゃんコーパス」のサンプル数は100個と少なく、そのままだとうまく学習できなさそうなので、

(1) 英語を学習(済) (The LJ Speech Dataset, 13100個)
   ↓
(2) 日本語を学習 (JSUT, 7696個)
   ↓
(3) つくよみちゃんの声を学習(つくよみちゃんコーパス, 100個)

という転移学習な作戦をたててみました。(うまくいくか不明)

今回は「JSUT」で日本語の学習に挑戦してみたいと思います。

前回

1. 音素表記

Japanese Single Speaker Speech Dataset」にはデータセット内に「音素表記」があったのでそれを利用しましたが、「JSUT」にはないので、日本語の文章から「音素表記」に変換します。

日本語の音素

今回は、「pyopenjtalk」を使って音素表記への変換を行います。

pyopenjtalk」の使い方は、次のとおりです。

(1) 「Google Colab」でメニュー「編集→ノートブック」で「GPU」を選択。
(2) 以下のコマンドで「pyopenjtalk」をインストール。

# pyopenjtalkのインストール
!mkdir tools && cd tools && git clone https://github.com/r9y9/hts_engine_API.git
!mkdir -p tools/hts_engine_API/src/build && cd tools/hts_engine_API/src/build && \
    cmake -DCMAKE_INSTALL_PREFIX=../.. .. && make -j && make install
!cd tools && git clone https://github.com/r9y9/open_jtalk.git
!mkdir -p tools/open_jtalk/src/build && cd tools/open_jtalk/src/build && \
    cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
        -DHTS_ENGINE_LIB=../../../hts_engine_API/lib \
        -DHTS_ENGINE_INCLUDE_DIR=../../../hts_engine_API/include .. && \
    make install
!cp tools/open_jtalk/src/build/*.so* /usr/lib64-nvidia
!cd tools && git clone https://github.com/r9y9/pyopenjtalk.git
!cd tools/pyopenjtalk && pip install .

(3) pyopenjtalk.g2p()で音素表記に変換。

import pyopenjtalk
text = "システィナ礼拝堂は、1473年に、バティカン宮殿内に建立された、壮大な礼拝堂です、"
phones = pyopenjtalk.g2p(text, kana=False)
print(phones)
sh I s u t i n a r e e h a i d o o w a pau s e N y o N hy a k u n a n a j u u s a N n e N n i pau b a t I k a N ky u u d e N n a i n i k o N ry u u s a r e t a pau s o o d a i n a r e e h a i d o o d e s U

(4) 「NVIDIA/tacotron2」用の音素表記に変換。
pyopenjtalk」は、「、」「。」「!」「?」を以下のように変換します。

」→「pau」(文末では<削除>)
」→ <削除> (文末以外は「pau」)
」→ <削除>
」→ <削除>

そこで、次のような前処理を行いました。

import pyopenjtalk
text = "システィナ礼拝堂は、1473年に、バティカン宮殿内に建立された、壮大な礼拝堂です、"
phones = pyopenjtalk.g2p(text, kana=False)
#phones = phones.replace('pau',',')
#phones = phones.replace(' ','')
#phones = phones + '.'
print(phones)
shIsutinareehaidoowa,seNyoNhyakunanajuusaNneNni,batIkaNkyuudeNnainikoNryuusareta,soodainareehaidoodesU.

また、文末に終端記号があった方が収束が早いとの情報があったので、音素表記の最後に「.」を付けることにしました。

2. データセットの準備

今回は「JSUT」を利用します。

・jsut_ver1.1
 ・basic5000 - 常用漢字の音読み・訓読みを全てカバー
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・BASIC5000_XXXX.wav - wavファイル
        :
 ・utparaphrase512
- 文の一部を読み替えたもの
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・UT-PARAPHRASE-XXXXX-XXXXX.wav - wavファイル
        :
 ・onomatopee300
- 日本語オノマトペ
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・ONOMATOPEE300_XXX.wav - wavファイル
        :
 ・countersuffix26
- 助数詞
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・COUNTERSUFFIX26_XX.wav - wavファイル
        :
 ・loanword128
- 外来語由来の動詞・名詞 (e.g., ググる)
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・LOANWORD128_XXX.wav - wavファイル
        :
 ・voiceactress100
- 声優統計コーパス (プロ女性声優のフリーコーパス) とのパラ音声
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・VOICEACTRESS100_XXXX.wav - wavファイル
        :
 ・travel1000
- 旅行ドメインのフレーズ
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・TRAVEL1000_XXXX.wav - wavファイル
        :
 ・precedent130
- 判例文
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・PRECEDENT130_XXX.wav - wavファイル
        :
 ・repeat500
- 繰り返し発話された音声 (100文 * 5回)
  ・transcript_utf8.txt - wavファイル名とセリフの一覧
  ・wav - wavファイルを保持するフォルダ
   ・REPEAT500_XXXX_XXX.wav - wavファイル
        :

2-1. transcript.txt

JSUT」の「transcript.txt」の書式は、次のとおりです。

BASIC5000_0001:水をマレーシアから買わなくてはならないのです。
BASIC5000_0002:木曜日、停戦会談は、何の進展もないまま終了しました。
    :

これを「NVIDIA/tacotron2」用に変換します。

wav/BASIC5000_0001.wav|mizuomareeshiakarakawanakUtewanaranainodesU.
wav/BASIC5000_0002.wav|mokuyoobi,teeseNkaidaNwa,naninoshiNteNmonaimamashuuryooshimashIta.
    :

(1) 9個の「transcript_utf8.txt」を1個にまとめる。

import os

# パス
in_paths = [
    'jsut_ver1.1/basic5000/',
    'jsut_ver1.1/countersuffix26/',
    'jsut_ver1.1/loanword128/',
    'jsut_ver1.1/onomatopee300/',
    'jsut_ver1.1/precedent130/',
    'jsut_ver1.1/repeat500/',
    'jsut_ver1.1/travel1000/',
    'jsut_ver1.1/utparaphrase512/',
    'jsut_ver1.1/voiceactress100/']
out_path = 'filelists/'

# 出力フォルダの準備
os.makedirs(out_path, exist_ok=True)

# transcriptの変換
with open(out_path+'transcript_utf8.txt', 'w') as wf:
    for in_path in in_paths:
        with open(in_path+'transcript_utf8.txt', 'r') as rf:
            wf.write(rf.read())

(2) 「Google Colab」でメニュー「編集→ノートブック」で「GPU」を選択。
(3) 以下のコマンドで「pyopenjtalk」をインストール。

# pyopenjtalkのインストール
!mkdir tools && cd tools && git clone https://github.com/r9y9/hts_engine_API.git
!mkdir -p tools/hts_engine_API/src/build && cd tools/hts_engine_API/src/build && \
    cmake -DCMAKE_INSTALL_PREFIX=../.. .. && make -j && make install
!cd tools && git clone https://github.com/r9y9/open_jtalk.git
!mkdir -p tools/open_jtalk/src/build && cd tools/open_jtalk/src/build && \
    cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
        -DHTS_ENGINE_LIB=../../../hts_engine_API/lib \
        -DHTS_ENGINE_INCLUDE_DIR=../../../hts_engine_API/include .. && \
    make install
!cp tools/open_jtalk/src/build/*.so* /usr/lib64-nvidia
!cd tools && git clone https://github.com/r9y9/pyopenjtalk.git
!cd tools/pyopenjtalk && pip install .

(4) 「Google Colab」で「wavファイルのパス」「セパレータ(|)」「音素表記」を変換。
「in_path」に入力ファイル、「out_path」の出力ファイルのパスを指定してください。

import os
import pyopenjtalk

# transcript.txtの変換
in_path = 'filelists/transcript_utf8.txt'
out_path = 'filelists/transcript.txt'
output = []
with open(in_path) as f:
    lines = f.readlines()
    for line in lines:
        strs = line.split(':')
        strs[1] = pyopenjtalk.g2p(strs[1], kana=False)
        strs[1] = strs[1].replace('pau',',')
        strs[1] = strs[1].replace(' ','')
        strs[1] = strs[1] + '.'
        output.append('wav/'+strs[0]+'.wav|'+strs[1]+'\n')

with open(out_path, 'w') as f:
    f.writelines(output)

2-2. wav

JSUT」のwavのサンプリングレートは48KHzです。これを「NVIDIA/tacotron2」用の22KHzに変換します。

変換スクリプトは、次のとおりです。

$ pip install librosa==0.8.0
$ pip install pysoundfile==0.9.0.post1
import os
import librosa
import soundfile as sf

# パス
in_paths = [
    'jsut_ver1.1/basic5000/',
    'jsut_ver1.1/countersuffix26/',
    'jsut_ver1.1/loanword128/',
    'jsut_ver1.1/onomatopee300/',
    'jsut_ver1.1/precedent130/',
    'jsut_ver1.1/repeat500/',
    'jsut_ver1.1/travel1000/',
    'jsut_ver1.1/utparaphrase512/',
    'jsut_ver1.1/voiceactress100/']
out_path = 'wav/'

# 出力フォルダの準備
os.makedirs(out_path, exist_ok=True)

# wavの変換の関数
def convert(in_path):
    filenames = os.listdir(in_path+'wav/')
    for filename in filenames:
        print(in_path+'wav/'+filename)
        y, sr = librosa.core.load(in_path+'wav/'+filename, sr=22050, mono=True)
        sf.write(out_path+'wav/'+filename, y, sr, subtype="PCM_16")

# wavの変換
for in_path in in_paths:
    convert(in_path)

3. 学習

今回も「NVIDIA/tacotron2」を利用して、「Google Colab」で学習します。前回と同様にインストールした後、データセットを配置します。

(1) データセットの配置。

・work
 ・tacotron2
  ・filelists
   ・transcript.txt ←★ここに配置
  ・wav ←★ここに配置
   ・BASIC5000_XXXX.wav

     :

(2) データセットを学習データと検証データに分割

# 学習データと検証データの分割
!head -n 7000 filelists/transcript.txt > filelists/transcript_train.txt
!tail -n 690 filelists/transcript.txt > filelists/transcript_val.txt

(3) 「hparams.py」の編集。
前回と同じだとメモリオーバーになってしまったので、バッチサイズを減らしました。

    :
epochs=100,
   :
training_files='filelists/transcript_train.txt',
validation_files='filelists/transcript_val.txt',
text_cleaners=['basic_cleaners'],
   :
batch_size=16,
   :

(4) 学習の実行。

!python train.py --output_directory=outdir --log_directory=logdir -c tacotron2_statedict.pt --warm_start

4. 推論

前回と同様に推論します。ただし、入力の音素表記は、「pyopenjtalk」で生成します。

text = "honnjituwaseitennnari."

待ちきれず3000ステップで確認したところ、「JSUT」の声で「本日は晴天なり」を言ってくれました。

◎ JSUT 13000ステップ

次回



この記事が気に入ったらサポートをしてみませんか?