概要
自分の声で音声合成をやってみます。
先人に倣って簡単にやっていきます。
内容としては、tacotron2を用いた転移学習によって自分の声を用いて音声を生成します。
英語の学習済みデータから一度大きな日本語のデータセットで転移学習し、次に自分の声のデータセットで転移学習するといいみたいなので、自分もその二段階で学習を行いました。
データセットを用いた学習は、用意されている音声コーパスを用いればできますが、一から音声合成をしたい場合には音声コーパスを作成する必要があります。
(コーパスとは、言語学において、自然言語処理の研究に用いるため、自然言語の文章を構造化し大規模に集積したもの。)
今回は自分の声で音声コーパスを作成して音声を合成します。
今回工夫した(と思っている)点は、コーパスを音声認識によって作った点です。
コーパスを作るとなると、自分で何かを読み上げるだけでなく、①データを整理し、②何を読んだか台詞を記録し、③さらに学習するデータセットの体裁に整える手間がかかります。
音声認識等を用いてこの工程を自動化し、誰でも簡単にコーパスを作成することができます。(精度は多少悪いかもしれません)
それでは手順ごとに説明していきます。
コーパスの作成
冒頭で書いた、①データを整理し、②何を読んだか台詞を記録し、③さらに学習するデータセットの体裁に整える、の手順を実行します。
イメージとしては下の図のような感じです。
まず最初に適当に日本語を読み上げて録音します。
夏目漱石の「こころ」の冒頭15分くらいを朗読しました。
次に無音区間や雑音を取り除き、音声部分のみを分割して抽出します。
そして、各音声データに対して音声認識を実行し、対応するセリフを認識します。
最後に学習用のフォーマット(今回はアルファベット)に変換して、音声コーパスは作成完了です。
コメントで処理を解説しています。
使っているライブラリは以下の通り。
soundfileとlibrosa:音声の読み込み、書き出し(どちらかに統一した方がいいですね)
inaSpeechSegmenter:音を分割して分類する
speech_recognition:音声認識
pyopenjtalk:漢字とかを含む文字列をアルファベットに変換する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import soundfile as sf from inaSpeechSegmenter import Segmenter import speech_recognition as sr import glob import pyopenjtalk import librosa def wav_read(path): wave, fs = librosa.core.load(path, sr=22050, mono=True) return wave, fs if __name__ == "__main__": source_file_path = "source_file_folder/*" seg_model = Segmenter() r = sr.Recognizer() surp = 0.2 num = 0 f = open('corpusfilepath', 'w') for source in glob.glob(source_file_path): wave, fs = wav_read(source) #ソースファイルを読み込む seg_data = seg_model(source) #ソースファイルを音によって分割 for cat, start, end in seg_data: #segmodelはcategory, start, endのリストを返します if cat == "male": #音が男の声だった場合(著者は男性、女性だったら=="female") wave_trimed = wave[round((start - surp) * fs):round((end + surp) * fs)] save_file = "save_path/" + str(num).zfill(4) + ".wav" sf.write(save_file, wave_trimed, fs, subtype="PCM_16") #保存します try: with sr.AudioFile(save_file) as audiosource: audio = r.record(audiosource) txt = r.recognize_google(audio, language='ja-JP') #保存した音ファイルについて、音声認識を行います f.write(save_file + "|" + pyopenjtalk.g2p(txt, kana=False).replace('pau',',').replace(' ','') + '.' + "\n") #tacotron2の学習するデータフォーマットに合わせて文字列を変換 num += 1 except: pass f.close() |
例えば、「その時海岸には掛茶屋が二軒あった。」、という文章は30個目のファイルに分割されていて、下記文書としてコーパスに記されています。
15分程度の文書の読み上げだけで、120サンプルの音声コーパスが作成できました。
学習
hparams.pyを変更します。
ここらへんの変更は参考にした記事と同じです。
学習に用いるデータを変更してあげて、モデルの保存先も指定してあげます。
- 英語の学習済みモデルから日本語を学習する。(半日くらいしました)
python train.py –output_directory=outdir –log_directory=logdir -c tacotron2_statedict.pt –warm_start - 日本語の学習済みモデルから自分の声を学習する。(2時間くらいしました)
python train.py –output_directory=outdir2 –log_directory=logdir -c outdir/checkpoint_12000 –warm_start
結果
著者の声で実際に音声を生成したのが以下の音声です。
「この音声は、もちおのブログの著者の声です。」
微妙かな?
大体言葉を話せているし、声質も自分と似ているような気がします。
日本語を学習するときのデータセットの選択も良くなかった気がするし、まだまだ改善すると思います。
取りあえずできたので良かったです。
参考
主に参考にしたのは下記サイトです。
Google Colabでやろうとしたのですが、「GPUバックエンドに接続できません」というエラーが出たので諦めてローカル環境でやりました。
NVIDIA/tacotron2 で日本語の音声合成を試す
コメント
はじめまして、私もこちらの記事の様に自分の声を用いて音声合成をしたいのですが、
5000文字〜1万文字までのテキストを音声合成させたい場合、合成された音声が生成されるまで結構な処理時間がかかるものでしょうか?
私はサーバーに置いてテキストを入力したら音声合成されたものが後程メールで届く様なサービスとして稼働させたいのですが、調べている範囲ではNVIDIA製のGPUでしか動かないとの事でかなりハイスペックなGPUでないと処理出来ない様な負荷でしょうか?
自分はローカル環境でGeForce GTX 1080 Tiを使っています。
音声の生成は文章(日本語で~100字程度)ごとに行っていて、例えば100字程度の文章に対して測定したところ2.8秒かかりました。
これはモデルの読み込み等の時間を除いた生成部分のみにかかる時間になります。
10000字となると100倍の5分程度かかると思います。
tacotron2のような深層学習ベースの音声合成は、サービスとして多数のユーザーが利用するものとしては少し計算量は大きいなと思います。
少し調べたところ、「VOICEVOX」等、市販でCPU動作する音声合成ソフトもあるみたいなので、もっと計算量を少ない技術を使えばより現実的だと思います!
[…] pythonで自分の声を使って音声合成する […]
[…] https://heartstat.net/2022/04/10/python_speech-synthesis_myvoice/ […]