🔥

GPT-SoVITS ver2を学習する【WebUI使わない】

2024/08/15に公開

はじめに

高品質なzero-shot TTSモデルであるGPT-SoVITSにVersion 2がリリースされています。
デモ動画などを確認する限り、品質も非常に向上しているようですので、今回も、このGPT-SoVITSのVersion 2を試していきたいと思います。

https://github.com/RVC-Boss/GPT-SoVITS

以前、GPT-SoVITSのVersion 2のZero-shot TTSをWebUIを使わずに、モジュールとして実行する方法について記事を書きました。
https://zenn.dev/asap/articles/964a7d863d8896

今回も同様にWebUIを使わない形で、GPT-SoVITSのVersion 2を学習(Few-shot TTS)できるようにしたいと思います。

参考

なお、今回の記事は、下記のノートブックのコードを利用させていただきました。
https://colab.research.google.com/drive/1rb0ZsoC1diyCzmFO2b49jIu_oDsEz77T#scrollTo=7GzgZE4hZGjf

私は、このノードブックの利用方法がよくわからなかったため、自分なりに試行錯誤して、改めて作成しましたが、上記のノートブックからコードを大量に流用しています。
(リンク元のノートブックで学習可能かどうかは、試していないためわかりません。ver1の時代に作成してくださったノートブックのため、ver2で学習するためには一部修正が必要だと思います)

(当初は、こちらのノートブックで実施している処理が理解できず、自分で作ろうと思っていたのですが、GPT-SoVITSの学習コードを勉強するにつれて、上記のノートブックで実装されているコードの必要性に気づき、とても勉強になりました)

元のノートブックとの違いとしては、毎回リポジトリや重みをクローンしてくるのではなく、Driveに格納したリポジトリと重みファイルを利用して学習を行うようにしたことでしょうか。

事前準備

前回の記事と被るところがあるため、そちらは前回の記事をご確認ください。
https://zenn.dev/asap/articles/964a7d863d8896

リポジトリのクローン

前回の記事をご覧ください。

事前学習モデルのダウンロード

前回の記事をご覧ください。

必要ファイルのダウンロード

下記のリポジトリに、Google colabで利用するノートブックを用意しています。
https://github.com/personabb/colab_AI_sample/tree/main/colab_GPT-soVITS_sample

上記のリポジトリ内のノートブックcolab_GPT-SoVITS_prepare.ipynbcolab_GPT-SoVITS_train.ipynbをダウンロードしておいてください。

また加えて下記のファイルをダウンロードしてください。
(後で、同ファイルをGoogle Driveの同じフォルダ箇所にアップロードすることになるため、どのフォルダに保存されていたファイルであるかは覚えておいてください)

  • ./GPT_SoVITS/AR/data/bucket_sampler_simple.py
  • ./GPT_SoVITS/AR/data/data_module_simple.py
  • ./GPT_SoVITS/s1_train_simple.py
  • ./GPT_SoVITS/s2_train_simple.py
  • ./slice.py
  • ./transcribe.py
変更の詳細

./GPT_SoVITS/AR/data/bucket_sampler_simple.py

45−46行目

#num_replicas = dist.get_world_size() if torch.cuda.is_available() else 1****
num_replicas = 1

50−51行目

#rank = dist.get_rank() if torch.cuda.is_available() else 0
rank = 0



./GPT_SoVITS/AR/data/data_module_simple.py
48-58行目

        return DataLoader(
            self._train_dataset,
            batch_size=batch_size,
            sampler=sampler,
            collate_fn=self._train_dataset.collate,
            num_workers= 0, ##self.num_workers,
            persistent_workers=False, ##True,
            prefetch_factor=None, ##16,
        )

    def val_dataloader(self):
        return DataLoader(
            self._dev_dataset,
            batch_size=1,
            shuffle=False,
            collate_fn=self._train_dataset.collate,
            num_workers=0, ##max(self.num_workers, 12),
            persistent_workers=False, ##True,
            prefetch_factor=None, ##16,
        )



./GPT_SoVITS/s1_train_simple.py

130-133行目

strategy="auto",
#strategy = DDPStrategy(
#    process_group_backend="nccl" if platform.system() != "Windows" else "gloo"
#) if torch.cuda.is_available() else "auto",



./GPT_SoVITS/s2_train_simple.py

116−125行目

train_loader = DataLoader(
    train_dataset,
    num_workers=0, ##6
    shuffle=False,
    pin_memory=True,
    collate_fn=collate_fn,
    batch_sampler=train_sampler,
    persistent_workers=False, ##True,
    prefetch_factor=None, ##4,
)



の通りに変更しました。
(変更前はコメントアウトしています)


また、./slice.py./transcribe.pyに関しては、Style-Bert-VITS2のリポジトリ内のコードを一部インポートしていたため、その該当のコードを./slice.py./transcribe.pyにくっつけただけです。

また、Style-Bert-VITS2のconfigを読む部分は、argparseで受け取るように変更しました。
(合わせて型の変換なども実施)

Google Driveへのアップロード

必要なフォルダをGoogle Driveにアップロードします。
まずは、Google Driveの「マイドライブ」直下TTS-testの空フォルダを作成してください。

続いて、先ほどcloneしたGPT-SoVITSもしくはGPT-SoVITS-mainフォルダの中にあるconfig.pyファイルとrequirements.txtファイルとGPT_SoVITSフォルダとtoolsフォルダの4つを、TTS-testフォルダの中にアップロードしてください。

さらに、TTS-test/GPT_SoVITSフォルダの中に、「必要ファイルのダウンロード」の章でダウンロードした下記のファイルを、TTS-test/GPT_SoVITSフォルダの同じ場所にアップロードしてください。

  • ./GPT_SoVITS/AR/data/bucket_sampler_simple.py
  • ./GPT_SoVITS/AR/data/data_module_simple.py
  • ./GPT_SoVITS/s1_train_simple.py
  • ./GPT_SoVITS/s2_train_simple.py
  • ./slice.py
  • ./transcribe.py

その後、TTS-test/GPT-SoVITS/GPT_SoVITS/pretrained_modelsフォルダの中に、chinese-hubert-basechinese-roberta-wwm-ext-largegsv-v2final-pretrainedフォルダを、フォルダごとアップロードしてください。

続いて、学習用のデータを保存したり、学習済みモデルが保存されるtrain_inputsフォルダとDataフォルダもGoogle DriveのTTS-testフォルダの中に作成してください。

最後に、colab_GPT-SoVITS_prepare.ipynbcolab_GPT-SoVITS_train.ipynbTTS-testフォルダの直下にアップロードしてください。

実行

学習データの準備

GPT-SoVITSをFew-shot TTSとして学習する場合は、下記の3つのデータが必要です。

  • 学習する話者の音声データ
    • 1ファイルは2-13秒ほどの音声ファイルである必要があります
      • 無音箇所で分割してくれるツールを利用できます。
    • 全音声データで1分以上必要です。
    • 上限はないと思いますが、多ければ多いほど良いのかは実験不足のためわかりません。
  • 学習する音声の書き起こしデータ
    • 各音声に対して、何と言っているのかを書き起こしたファイルが必要です。
      • 音声認識AIを利用して、音声から書き起こしてくれるツールを利用できます。

学習音声だけを用意している場合は、その音声をTTS-test/train_inputsフォルダにおいてください。
本記事内では、学習音声のパスは"TTS-test/train_inputs/train_audio1.wav"を想定します。

この時点で、下記のようなフォルダ構成になっているはずです。

MyDrive/
    └ TTS-test/
          ├ GPT-SoVITS/
          |        ├ pretrained_models/
          |        |    ├ chinese-hubert-base/
      |     |    |         └ ・・・
          |        |    ├ chinese-roberta-wwm-ext-large/
      |     |    |         └ ・・・
          |        |    └ gsv-v2final-pretrained/
      |     |              └ ・・・
          |        ├ AR/
          |        |  ├ data/
      |     |  |  ├ bucket_sampler_simple.py
      |     |  |  ├ data_module_simple.py
      |     |  |  └ ・・・
      |     |  └ ・・・
          |        ├ s1_train_simple.py
          |        ├ s2_train_simple.py
          |        └ ・・・・
          ├ tools/       
          |   └ ・・・
          ├ train_inputs/
          |   └ train_audio2.wav
          ├ Data/
          ├ inputs/
          ├ outputs/
          ├ requirements.txt
          ├ slice.py
          ├ transcribe.py
          ├ colab_GPT-SoVITS_prepare.ipynb
          ├ colab_GPT-SoVITS_train.ipynb
          └ colab_GPT-SoVITS_sample.ipynb

今回の記事では、下記のサイトから学習音声をお借りしました。
https://amitaro.net/voice/livevoice/

毎度毎度、使わせていただいております。
あみたろ様ありがとうございます。

上記サイトの
「04_対談・元気にパズル」の音声のうち、一つの音声をそのままtrain_inputsフォルダに格納して進めました。

学習ファイルの前処理の実行

学習ファイルの前処理の実行を行います。
この処理は、学習ファイルを正しく保持している場合は、スキップが可能な処理になります。
colab_GPT-SoVITS_prepare.ipynbのノートブックを実行します。

こちらを実行することで、Dataフォルダの中に学習に利用できる形に整形された学習データが保管されます。

TTS-testのフォルダの名前を変更している場合や、MyDrive直下にTTS-testフォルダを作成していない場合は、1セル目の下記のPATHを正しいパスに変更してください。

main_dir = os.path.dirname(glob.glob('/content/drive/MyDrive/TTS-test/colab_GPT-SoVITS_prepare.ipynb', recursive=True)[0])

また、3セル目には設定を記載します

## 設定

# 学習データを格納するフォルダ
dataset_root = "Data"
model_name = "amitaro_live"
# 元となる音声ファイル(wav形式)を入れるディレクトリ
input_dir = "./train_inputs"

os.makedirs(f"{dataset_root}/{model_name}", exist_ok=True)

特にmodel_nameは今回学習により作成するモデル名であり、一連の学習の中で全て同一のものを利用することに注意してください。

4セル目では、音声を、最大十数秒単位で分割するスクリプトを実行しています。
分割した後、Data/{model_name}/rawフォルダに格納されます、

5セル目では、Data/{model_name}/rawに格納されている分割された音声に対して、各音声ごとに文字起こしをするスクリプトを実行します。
実行後、Data/{model_name}/esd.listファイルに文字起こしが格納されます。

文字起こしの形式は下記のようになっているはずです。

./MyDrive/TTS-test/Data/amitaro_live/esd.list
・・・
2024-05-19_Q-101.wav|amitaro_live|JP|あんまり弾を大きくしてもつっかえる……やっぱそうかー
2024-05-19_Q-102.wav|amitaro_live|JP|倒せない、倒せない、倒せない!
2024-05-19_Q-103.wav|amitaro_live|JP|なんで?何が……違う角度?
2024-05-19_Q-104.wav|amitaro_live|JP|最初の坂を上に……
2024-05-19_Q-105.wav|amitaro_live|JP|こう書いた感じ……え、なになになになに
・・・

上記のように下記のようなルールで記載されています

ファイル名|モデル名|言語|書き起こしテキスト

その中でも、ファイル名は、Data/{model_name}/rawからの相対パスになっているはずです。

学習の実行

colab_GPT-SoVITS_train.ipynbのノートブックを実行します。

こちらのノートブックで変更が必要な箇所は下記の2つです。

まずは1セル目です。
colab_GPT-SoVITS_prepare.ipynbの場合と同様に、
TTS-testのフォルダの名前を変更している場合や、MyDrive直下にTTS-testフォルダを作成していない場合は、1セル目の下記のPATHを正しいパスに変更してください。

main_dir = os.path.dirname(glob.glob('/content/drive/MyDrive/TTS-test/colab_GPT-SoVITS_train.ipynb', recursive=True)[0])

続いて5セル目です。

## 前提条件の設定
## "./{exp_root}/{model_name}/raw"に2−13秒ほどにスライスされた音声データを格納
## "./{exp_root}/{model_name}/{text_list}"に音声データの書き起こしを格納。
    ##PATHは"./{exp_root}/{model_name}/raw"からの相対パスで記入
## "./{exp_root}/{model_name}/{abs_text_list}"に音声データの書き起こしを格納
    ##PATHは絶対パスで記入
    ##[6]セル目にて、{text_list}から{abs_text_list}に変換する処理を用意しているが、あらかじめ{abs_text_list}を用意している場合は実行する必要はない

exp_root = "Data" ##整理済み学習データを格納するフォルダ
model_name = "amitaro_live" ##学習するモデルの名前。
text_list = "esd.list" ##音声データの書き起こしファイル(相対パス)
abs_text_list = "esd_absolute.list" ##音声データの書き起こしファイル(絶対パス)


## 事前学習モデル
pretrained_s1 = "./GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt"
pretrained_s2G = "./GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth"
pretrained_s2D = "./GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2D2333k.pth"

roberta_path = "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large"
hubert_path = "GPT_SoVITS/pretrained_models/chinese-hubert-base"

## soVITS modeの学習パラメータ
batch_size = 4
total_epoch = 20
text_learning_rate = 0.4
save_frequency = 5
save_latest = True
save_every_weights = True
seve_weight_in_drive = True

## gpt modelの学習パラメータ
batch_size = 2
total_epoch = 20
dpo_training = False
save_frequency = 5
save_latest = True
save_every_weights = True
seve_weight_in_drive = True

特に変更が必要なのは、model_nameです。前処理の段階と同様のモデル名を指定してください。
使い所としてはDataフォルダの下のどのフォルダの中身を利用するかに使います。

また、学習では2つのモデルを学習します。それぞれに対して、状況に応じてパラメータの変更をしてください。
さらに、無料版のGoogle Driveを利用しているなどで、重みデータを保存する容量がない場合などはseve_weight_in_driveをFalseに設定してください。
(2つのモデルでそれぞれ指定できます)

Falseに指定すると、Google colabのインスタンス内に保存されるため、Google Driveの容量を圧迫しません。
その代わり、実行後に明示的にダウンロードしないまま、放置すると、時間経過で切断させられて、モデルのデータが失われてしまうため、注意してください。

ノートブックを実行する際は、一番上のセルから順番に実行してください。

6セル目は書き起こしテキストであるesd.listのファイル名の部分を絶対パスに書き換える処理です。最初から絶対パスでファイル名が入っているesd.listを持っている方は、そのファイルをData/{model_name}フォルダに格納後、4セル目のabs_text_listのファイル名を変更して実行してください。

7−9セル目は、データの前処理です。
書き起こしテキストの音素変換やアクセント記号の追加、学習音声のリサンプリングなどを行い、該当のフォルダに格納されます。

10-11セル目は、モデルの学習です。
モデルは設定したパラメータに応じて学習されます。
学習された重みはそれぞれ、
Data/{model_name}/soVITS_model
Data/{model_name}/GPT_model
に保存されます。

推論の実行

下記の記事をご覧ください。
https://zenn.dev/asap/articles/964a7d863d8896

なお、上記の記事における下記の部分を今回学習した重みデータに変更します。

gpt_model = "./GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt"
sovits_model = "./GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth"

例えば下記のように変更すると良いです。

gpt_model = "./Data/amitaro_live/GPT_model/amitaro_live-e20.ckpt"
sovits_model = "./Data/amitaro_live/soVITS_model/amitaro_live_e20_s9200.pth"

また推論には参照用音声が必要です。
今回は2パターン用意しました。

1つ目は、学習に利用したライブ音声のうちの一つを引っ張ってきました。
みなさんと同じようになっているかはわかりませんが、ファイル名は下記のものでした。

ref_audio_path = "inputs/2024-05-19_Q-40.wav"

書き起こしテキストは下記です。

わりと、全体的に・・・大きさより位置エネルギー使う方が重要。位置エネルギー、なるほどー?

2つ目の参照用音声は、こちらのるんるんスタイルを持ってきました。
https://amitaro.net/voice/corpus-list/ita/

書き起こしテキストは下記です

イタリア旅行で彼は、いくつか景勝の地として有名な都市、例えば、ナポリやフィレンツェを訪れた。

実行結果

上記の方法で学習を行い、その上で推論した結果が下記になります。

参照音声1つ目(ライブ音声)

Few-shot TTSです。
https://youtu.be/OKRHSRB_6zU

同じ参照用音声で作成したZero-shot TTS(元の重みをそのまま利用)は下記です。
https://youtu.be/RhiwQdIy9W8

あれ?なんか音声が変な感じになってしまった・・・
どちらのモデルでも声が変というのは、参照用音声の質の問題なのか?もしくは文字起こしが良くないのか?

参照音声2つ目(コーパス音声)

Few-shot TTSです。
https://youtu.be/sNsyU7zKKto

同じ参照用音声で作成したZero-shot TTS(元の重みをそのまま利用)は下記です。
https://youtu.be/LOiradkPtc0

なるほど。こちらはどちらもある程度ちゃんと発話されました。

正直、日本語としての全体の質はZero-shot TTSの方が質が高いような気がしますね。
ただ、話し方とか語尾の発音が甘い部分などの話者特有の情報みたいなものは、Few-shot TTSの方が再現されている気がします。

まとめ

今回は、先人が作成してくださったコードを参考(ほぼ流用)して、WebUIを使わない形でGPT-SoVITSを学習してみました。(勉強させていただきました。)

Google colabはWebUIの利用に厳しいため、WebUIを利用しない方法で学習できるようになって良かったです。
ただ、正直現時点試した結果だと、Zero-shot TTSで十分な場面が多そうだなと思いました。
(それとも学習音声を数分程度にしたら多少良くなるのか?今回1時間半くらいの音声をそのまま学習させて、かつ文字起こしもwhisperに任せっきりだったのが良くなかったのかも)

その他少しだけ色々試した感じだと、学習音声の質や参照音声の質によって、生成される音声が非常に左右される感覚があり、かなり敏感なモデルなのかなと感じました。
Style-Bert-VITS2とかだと、もう少し雑にデータを投げてもいい感じに学習してくれていたので、その点は意識しないといけなさそうですね。

皆様も色々試してみて、こういう設定で学習させたら、音声の質がすごく良かったみたいなのがありましたら、ぜひ教えてください!

以上、ここまで読んでくださってありがとうございました!

Discussion