Closed8

音声合成 Style-Bert-VITS2 をWSL2でためす

moriokamorioka

範囲

使えるようにしておく必要に迫られたので、

とくに変わったことをせず

  • WSL2/Ubuntu22.04 (RAM 128GB, 3060-12G) に
  • ローカルで動作するよう
  • 学習までは追体験。スタイル調整とマージは後回し。
  • proxy/certに悩まされないよう、個人環境で

https://github.com/litagin02/Style-Bert-VITS2
https://note.com/nike_cha_n/n/n843bf0b21725#f48e0011-c547-42b2-b4e3-6c5329d4c7df

サーバにデプロイしたり、サーバレス運用もできたりするのだな。工夫すれば。

moriokamorioka

とにかく動かす

pythonバージョンは適当。すでにあったので。

apt で ffmpeg や av関係のdebian系パッケージをインストールする必要が生じるかもしれない。

# 仮想環境を用意。今回は pyenv + pyenv-virtualenv
pyenv virtualenv 3.11.8 stylebertbits2
git clone https://github.com/litagin02/Style-Bert-VITS2
cd Style-Bert-VITS2
pyenv local stylebertbits2
# 必要なパッケージをインストール
pip install "torch<2.4" "torchaudio<2.4"
pip install -r requirements.txt
# 必要なモデルとデフォルトTTSモデルをダウンロード
python initialize.py
# 音声合成エディターを起動
python server_editor.py  # http://0.0.0.0:8000

動く。VRAM 3GBほどを占有している?

エディタ上で、適当な上記記事から抜き出してしゃべらせてみる

INFO:     127.0.0.1:53264 - "GET /api/version HTTP/1.1" 200 OK
INFO:     127.0.0.1:53270 - "POST /api/g2p HTTP/1.1" 200 OK
02-08 15:18:49 |  INFO  | tts_model.py:259 | Start generating audio data from text:
Style-Bert-VITS2と言えば、高品質で生成が早い合成音声技術(TTS: Text to Speech)として有名ですね。
02-08 15:18:50 |  INFO  | tts_model.py:324 | Audio data generated successfully
INFO:     127.0.0.1:53270 - "POST /api/synthesis HTTP/1.1" 200 OK
INFO:     127.0.0.1:53270 - "GET /favicon.ico HTTP/1.1" 404 Not Found
INFO:     127.0.0.1:53286 - "POST /api/g2p HTTP/1.1" 200 OK
INFO:     127.0.0.1:53286 - "POST /api/g2p HTTP/1.1" 200 OK
INFO:     127.0.0.1:53286 - "POST /api/g2p HTTP/1.1" 200 OK
02-08 15:19:01 |  INFO  | tts_model.py:259 | Start generating audio data from text:
こんにちは、ニケです。
02-08 15:19:01 |  INFO  | tts_model.py:324 | Audio data generated successfully
02-08 15:19:01 |  INFO  | tts_model.py:259 | Start generating audio data from text:
皆さん、Style-Bert-VITS2は使っていますでしょうか?
02-08 15:19:02 |  INFO  | tts_model.py:324 | Audio data generated successfully
02-08 15:19:02 |  INFO  | tts_model.py:259 | Start generating audio data from text:
Style-Bert-VITS2と言えば、高品質で生成が早い合成音声技術(TTS: Text to Speech)として有名ですね。
02-08 15:19:02 |  INFO  | tts_model.py:324 | Audio data generated successfully
INFO:     127.0.0.1:53286 - "POST /api/multi_synthesis HTTP/1.1" 200 OK
INFO:     127.0.0.1:57284 - "GET /_next/static/media/2dba46bfc14ba3f6-s.woff2 HTTP/1.1" 200 OK
INFO:     127.0.0.1:57284 - "GET /_next/static/media/5640c99d8abfdde6-s.woff2 HTTP/1.1" 200 OK
INFO:     127.0.0.1:57284 - "GET /_next/static/media/8793d1fe514485a8-s.woff2 HTTP/1.1" 200 OK
INFO:     127.0.0.1:57294 - "POST /api/g2p HTTP/1.1" 200 OK
02-08 15:19:51 |  INFO  | tts_model.py:259 | Start generating audio data from text:
Style-Bert-VITS2と言えば、高品質で生成が早い合成音声技術(TTS: テキスト トゥー スピーチ)として有名ですね。
02-08 15:19:51 |  INFO  | tts_model.py:324 | Audio data generated successfully
INFO:     127.0.0.1:57294 - "POST /api/synthesis HTTP/1.1" 200 OK
INFO:     127.0.0.1:37862 - "GET /docs HTTP/1.1" 200 OK
INFO:     127.0.0.1:37862 - "GET /openapi.json HTTP/1.1" 200 OK
INFO:     127.0.0.1:56868 - "POST /api/g2p HTTP/1.1" 200 OK
INFO:     127.0.0.1:56876 - "GET /api/models_info HTTP/1.1" 200 OK
02-08 15:40:23 | ERROR  | server_editor.py:287 | Model `string` is not found
INFO:     127.0.0.1:37962 - "POST /api/synthesis HTTP/1.1" 500 Internal Server Error
^CINFO:     Shutting down
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
INFO:     Finished server process [13216]
02-08 15:40:48 | DEBUG  | __init__.py:147 | pyopenjtalk worker server terminated
(bertvits) morioka@legion:~/temp/Style-Bert-VITS2$

FastAPIなので、 http://localhost:8000/docs でAPIを確認できる。例は、適当なものを用意してやる必要があるだろう。

moriokamorioka

ダウンロードするモデル

モデルとしてダウンロードしているもの

deberta-v2-large-japanese-char-wwm pytorch_model.bin| 1.32G/1.32G [00:16<00:00, chinese-roberta-wwm-ext-large pytorch_model.bin| 1.31G/1.31G [00:17<00:00, 74.7MB/s]
deberta-v3-large spm.model| 2.46M/2.46M [00:00<00:00, 91.8MB/s]
deberta-v3-large pytorch_model.bin| 874M/874M [00:10<00:00, 86.3MB/s]
jvnv-F1-jp/config.json| 2.14k/2.14k [00:00<00:00, 5.06MB/s]
jvnv-F1-jp/jvnv-F1-jp_e160_s14000.safetensors| 251M/251M [00:05<00:00, 42.4MB/s]
jvnv-F1-jp/style_vectors.npy| 7.30k/7.30k [00:00<00:00, 67.7MB/s]
jvnv-F2-jp/config.json| 2.22k/2.22k [00:00<00:00, 22.1MB/s]
jvnv-F2-jp/jvnv-F2_e166_s20000.safetensors| 251M/251M [00:06<00:00, 39.0MB/s]
jvnv-F2-jp/style_vectors.npy| 7.30k/7.30k [00:00<00:00, 73.7MB/s]
jvnv-M1-jp/config.json| 2.14k/2.14k [00:00<00:00, 23.7MB/s]
jvnv-M1-jp/jvnv-M1-jp_e158_s14000.safetensors| 251M/251M [00:05<00:00, 42.3MB/s]
jvnv-M1-jp/style_vectors.npy| 7.30k/7.30k [00:00<00:00, 29.2MB/s]
jvnv-M2-jp/config.json| 2.14k/2.14k [00:00<00:00, 15.8MB/s]
jvnv-M2-jp/jvnv-M2-jp_e159_s17000.safetensors| 251M/251M [00:05<00:00, 42.4MB/s]
jvnv-M2-jp/style_vectors.npy| 7.30k/7.30k [00:00<00:00, 25.3MB/s]
koharune-ami/config.json| 2.33k/2.33k [00:00<00:00, 8.18MB/s]
koharune-ami/style_vectors.npy| 6.27k/6.27k [00:00<00:00, 29.4MB/s]
koharune-ami/koharune-ami.safetensors| 251M/251M [00:05<00:00, 42.7MB/s]
amitaro/config.json| 2.21k/2.21k [00:00<00:00, 10.9MB/s]
amitaro/style_vectors.npy| 5.25k/5.25k [00:00<00:00, 21.5MB/s]
amitaro/amitaro.safetensors| 251M/251M [00:06<00:00, 38.1MB/s]
wavlm-base-plus pytorch_model.bin| 378M/378M [00:05<00:00, 70.3MB/s]
pretrained G_0.safetensors| 234M/234M [00:05<00:00, 42.4MB/s]
pretrained D_0.safetensors| 187M/187M [00:04<00:00, 42.6MB/s]
pretrained DUR_0.safetensors| 2.42M/2.42M [00:00<00:00, 46.6MB/s]
JP-Extra pretrained G_0.safetensors| 293M/293M [00:06<00:00, 42.2MB/s]
JP-Extra pretrained D_0.safetensors| 187M/187M [00:04<00:00, 41.4MB/s]
JP-Extra pretrained WD_0.safetensors| 4.70M/4.70M [00:00<00:00, 43.8MB/s]

moriokamorioka

このあと

  • API経由での音声合成
  • 学習データの作成と、学習
moriokamorioka

学習

python app.py  # http://localhost:7860

学習データの準備は、音声データを所定の時間間隔?で区切って、音声認識で仮の読みを与えて、それを修正させていく感じらしい。

よくはわからんが、webui に従っていくとよい感じ。

CLIでも同じか。

https://github.com/litagin02/Style-Bert-VITS2/blob/master/docs/CLI.md

↓これをなぞる。画面に違いはあるが気にならない。学習用WebUIでは音声合成/データセット作成/学習/スタイル作成/マージの5つのタブがあり、それを切り替えて手順を進めていく。動画との大きな違いはWindows上でなく、WSL2上であることだけ。

https://www.youtube.com/watch?v=aTUSzgDl1iY&t=709s

ずんだもんデータセットのライセンス同意と取得にtwitterでログインする必要があるので、企業だと、その点だけハードルが高いかもしれない。

https://zunko.jp/multimodal_dev/login.php

tensorboardは http://localhost:6006

とりあえず、数時間放っておく。5hほどで完了。VRAM 8から9GB程度。たしかに、ずんだもんっぽい。

↓(追記) WebUIベースの学習手順は、これにならえばよかった

https://www.youtube.com/watch?v=zRirNw_AKIM

https://www.youtube.com/watch?v=H2ybcFx2v3g

moriokamorioka

API利用

API利用...といっても、編集(8000), 学習(7860), 音声合成のみ(5000) と、コードが別々でAPIも異なる。

音声合成APIについていえば、

https://note.com/yuki_tech/n/nca6ecb57469a

を丸ごとまねる。(モデル名を修正。非推奨のGETメソッドからPOSTメソッドに変更)

# 必要なライブラリをインポートします
import requests
import io
import soundfile
import argparse
import sounddevice as sd

# Sbv2Adapterというクラスを定義します
class Sbv2Adapter:
    URL = "http://127.0.0.1:5000/voice"

    def __init__(self) -> None:
        pass

    # 音声を取得するためのクエリを作成するメソッドです
    def _create_audio_query(self, text: str) -> dict:
        # パラメータを定義します
        params = {
            "text": text,
            "speaker_id": 0,
            #"model_name": "shirohana",
            "model_name": "koharune-ami",
            "length": 1, #音声の話速(1.0=標準、2.0=2倍遅く、0.5=2倍速く)
            "sdp_ratio": 0.2,
            "noise": 0.6,
            "noisew": 0.8,
            "auto_split": True,
            "split_interval": 1,
            "language": "JP",
            "style": "Neutral",
            "style_weight": 5,
        }
        return params

    # 音声をリクエストするメソッドです
    def _create_request_audio(self, query_data: dict) -> bytes:
        headers = {"accept": "audio/wav"}
        #response = requests.get(self.URL, params=query_data, headers=headers)
        response = requests.post(self.URL, params=query_data, headers=headers)
        # エラーハンドリング
        if response.status_code != 200:
            raise Exception(f"Error: {response.status_code}")
        return response.content

    # 音声を取得するメソッドです
    def get_voice(self, text: str):
        query_data = self._create_audio_query(text)
        audio_bytes = self._create_request_audio(query_data)
        audio_stream = io.BytesIO(audio_bytes)
        data, sample_rate = soundfile.read(audio_stream)
        return data, sample_rate

def main(text: str):
    adapter = Sbv2Adapter()
    data, sample_rate = adapter.get_voice(text)
    sd.play(data, sample_rate)
    sd.wait()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Text to Speech")
    parser.add_argument("text", type=str, help="The text to be converted to speech")
    args = parser.parse_args()
    main(args.text)
pip install sounddevice
python sbv2.py "こんにちは、世界!"
$ python server_fastapi.py
02-08 16:57:26 | DEBUG  | __init__.py:92 | try starting pyopenjtalk worker server
02-08 16:57:27 | DEBUG  | __init__.py:130 | pyopenjtalk worker server started
02-08 16:57:47 |  INFO  | bert_models.py:92 | Loaded the Languages.JP BERT model from /home/morioka/temp/Style-Bert-VITS2/bert/deberta-v2-large-japanese-char-wwm
02-08 16:57:47 |  INFO  | bert_models.py:154 | Loaded the Languages.JP BERT tokenizer from /home/morioka/temp/Style-Bert-VITS2/bert/deberta-v2-large-japanese-char-wwm
02-08 16:58:00 |  INFO  | bert_models.py:92 | Loaded the Languages.EN BERT model from /home/morioka/temp/Style-Bert-VITS2/bert/deberta-v3-large
02-08 16:58:00 |  INFO  | bert_models.py:154 | Loaded the Languages.EN BERT tokenizer from /home/morioka/temp/Style-Bert-VITS2/bert/deberta-v3-large
Some weights of the model checkpoint at /home/morioka/temp/Style-Bert-VITS2/bert/chinese-roberta-wwm-ext-large were not used when initializing BertForMaskedLM: ['bert.pooler.dense.bias', 'bert.pooler.dense.weight', 'cls.seq_relationship.bias', 'cls.seq_relationship.weight']
- This IS expected if you are initializing BertForMaskedLM from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing BertForMaskedLM from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
02-08 16:58:13 |  INFO  | bert_models.py:92 | Loaded the Languages.ZH BERT model from /home/morioka/temp/Style-Bert-VITS2/bert/chinese-roberta-wwm-ext-large
02-08 16:58:13 |  INFO  | bert_models.py:154 | Loaded the Languages.ZH BERT tokenizer from /home/morioka/temp/Style-Bert-VITS2/bert/chinese-roberta-wwm-ext-large
02-08 16:58:13 |WARNING | tts_model.py:397 | No model files found in model_assets/.cache, so skip it
02-08 16:58:13 |  INFO  | server_fastapi.py:113 | Loading models...
02-08 16:58:13 |  INFO  | server_fastapi.py:120 | The maximum length of the text is 100. If you want to change it, modify config.yml. Set limit to -1 to remove the limit.
02-08 16:58:13 |WARNING | server_fastapi.py:126 | CORS allow_origins=['*']. If you don't want, modify config.yml
02-08 16:58:13 |  INFO  | server_fastapi.py:335 | server listen: http://127.0.0.1:5000
02-08 16:58:13 |  INFO  | server_fastapi.py:336 | API docs: http://127.0.0.1:5000/docs
02-08 16:58:13 |  INFO  | server_fastapi.py:337 | Input text length limit: 100. You can change it in server.limit in config.yml
02-08 16:58:39 |  INFO  | server_fastapi.py:193 | 127.0.0.1:56044/voice  text=こんにちは、世界!&speaker_id=0&model_name=koharune-ami&length=1&sdp_ratio=0.2&noise=0.6&noisew=0.8&auto_split=True&split_interval=1&language=JP&style=Neutral&style_weight=5
02-08 16:58:39 |WARNING | server_fastapi.py:197 | The GET method is not recommended for this endpoint due to various restrictions. Please use the POST method.
02-08 16:58:39 |  INFO  | tts_model.py:259 | Start generating audio data from text:
こんにちは、世界!
02-08 16:58:39 |  INFO  | infer.py:24 | Using JP-Extra model
/home/morioka/.pyenv/versions/bertvits/lib/python3.11/site-packages/torch/nn/utils/weight_norm.py:28: UserWarning: torch.nn.utils.weight_norm is deprecated in favor of torch.nn.utils.parametrizations.weight_norm.
  warnings.warn("torch.nn.utils.weight_norm is deprecated in favor of torch.nn.utils.parametrizations.weight_norm.")
02-08 16:58:43 |  INFO  | safetensors.py:50 | Loaded 'model_assets/koharune-ami/koharune-ami.safetensors' (iteration 60)
02-08 16:58:45 |  INFO  | tts_model.py:324 | Audio data generated successfully
02-08 16:58:45 |SUCCESS | server_fastapi.py:253 | Audio data generated and sent successfully
02-08 17:07:38 |  INFO  | server_fastapi.py:193 | 127.0.0.1:34462/voice  text=こんにちは、世界!&speaker_id=0&model_name=koharune-ami&length=1&sdp_ratio=0.2&noise=0.6&noisew=0.8&auto_split=True&split_interval=1&language=JP&style=Neutral&style_weight=5
02-08 17:07:38 |  INFO  | tts_model.py:259 | Start generating audio data from text:
こんにちは、世界!
02-08 17:07:39 |  INFO  | tts_model.py:324 | Audio data generated successfully
02-08 17:07:39 |SUCCESS | server_fastapi.py:253 | Audio data generated and sent successfully
moriokamorioka

調整は Style-Bert-VITS2 の環境のままでよいとして、実利用はどうするか。

AvisSpeech向けに変換すると、model Hubに間違って登録してしまいそう+ライセンスがオープンになる?懸念があるので、onnxに直すくらいで、ローカルでホストかな。APIは何がよいだろうか。

style-bert-vits2
https://note.com/1namine/n/n25ef5dda972f
https://note.com/ai_hakase/n/n787302e7a61d
https://note.com/yuki_tech/n/n5bdbbc95b61b#5d500b21-e543-4dac-8673-23de1284e792
https://lib.rs/crates/sbv2_core

このスクラップは2025/02/08にクローズされました