Bert-VITS2の学習環境の構築および学習を行う

初めに

TTSライブラリのBert-VITS2学習がうまくいったので、その際に詰まった部分が今後 同じことをされる方が楽になりそうなメモを残しておきたいと思います!

少しでもお役に立てれば幸いです

以下の記事を参考にさせていただいています

zenn.dev

環境

特定のhash値のリポジトリのclone

特定のcommit hash値でしか学習がうまくいかなかったので、この記事では c2fcc02 のcommit hash値で学習を行います

まずは、リポジトリをcloneします

git clone https://github.com/fishaudio/Bert-VITS2.git

次にhash値のcommitに切り替えます

git checkout c2fcc02984bd7184c03b486c794c348d849146ac

仮想環境の構築

Pythonを使った開発でライブラリ等のversionが混合しない等にversion管理の方法はいくつかありますが、今回はすぐに使える venvを使っていきます

新しい環境の構築

新しい環境を作る際には、以下のコマンドを使用します python -m venv 環境名

python -m venv env

環境の有効化

作成した環境に切り替えるためには、以下のコマンドを使用します source venvまでのパス/bin/activate

source env/bin/activate

以下のようなエラーが出たときは、作成した環境名の指定もしくはパスが間違えている可能性があるので再度確認をします

bash: env/bin/activate: No such file or directory

ライブラリのインストール

参考の記事のようにライブラリを入れていきます

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -r requirements.txt
pip uninstall openjtalk
pip install pyopenjtalk-prebuilt

こちらの環境では、最終的に以下のライブラリが入っていました

absl-py==2.0.0
annotated-types==0.6.0
audioread==3.0.1
cachetools==5.3.2
certifi==2022.12.7
cffi==1.16.0
charset-normalizer==2.1.1
click==8.1.7
cn2an==0.5.22
Cython==3.0.6
decorator==5.1.1
Distance==0.1.3
docopt==0.6.2
einops==0.7.0
filelock==3.9.0
fsspec==2023.12.1
fugashi==1.3.0
g2p-en==2.1.0
google-auth==2.25.2
google-auth-oauthlib==1.1.0
grpcio==1.60.0
huggingface-hub==0.19.4
idna==3.4
inflect==7.0.0
jaconv==0.3.4
jieba==0.42.1
Jinja2==3.1.2
joblib==1.3.2
lazy_loader==0.3
librosa==0.10.1
llvmlite==0.41.1
loguru==0.7.2
Markdown==3.5.1
MarkupSafe==2.1.3
mecab-python3==1.0.8
mpmath==1.3.0
msgpack==1.0.7
networkx==3.0
nltk==3.8.1
num2words==0.5.13
numba==0.58.1
numpy==1.24.1
oauthlib==3.2.2
packaging==23.2
Pillow==9.3.0
platformdirs==4.1.0
pooch==1.8.0
proces==0.1.7
protobuf==4.23.4
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycparser==2.21
pydantic==2.5.2
pydantic_core==2.14.5
pyopenjtalk-prebuilt==0.3.0
pypinyin==0.49.0
PyYAML==6.0.1
regex==2023.10.3
requests==2.28.1
requests-oauthlib==1.3.1
rsa==4.9
safetensors==0.4.1
scikit-learn==1.3.2
scipy==1.11.4
sentencepiece==0.1.99
six==1.16.0
soundfile==0.12.1
soxr==0.3.7
sympy==1.12
tensorboard==2.15.1
tensorboard-data-server==0.7.2
threadpoolctl==3.2.0
tokenizers==0.15.0
torch==2.1.1+cu121
torchaudio==2.1.1+cu121
torchvision==0.16.1+cu121
tqdm==4.66.1
transformers==4.35.2
triton==2.1.0
typing_extensions==4.8.0
unidic-lite==1.0.8
urllib3==1.26.13
vector-quantize-pytorch==1.12.0
Werkzeug==3.0.1

フォルダ及びファイルの作成

必要なフォルダの作成を行います.

今回は学習した後のモデルの名前を test とします

音声ファイルを入れるためのフォルダを作ります

mkdir -p  Data/test/audios/raw

config.jsonを入れるためのフォルダを作ります

mkdir -p Data/test/configs

モデルを入れるためのフォルダを作ります

mkdir -p Data/test/models

書き起こしファイルを入れるフォルダを作ります

mkdir -p Data/test/filelists

書き起こしファイルを作成します

touch Data/test/filelists/text.list

設定ファイルの変更

config.ymlを編集します

以下の箇所を自分のモデル名及び~.list名に沿って変更します

dataset_path: "Data/model_name"
preprocess_text:
  transcription_path: "filelists/text.list"

またconfigs/config.jsonを、Data/model_name/configs/config.jsonにコピーします

cp configs/config.json Data/test/configs/config.json

モデルのダウンロード

以下のHFから G_0.pth D_0.pth DUR_0.pth の3つのモデルをダウンロードします

huggingface.co

またこちらのモデルは Data/test/models のパスに入れておきます

音声ファイルのアップロード及び書き起こしファイルの準備

.wavに変換した音声ファイルを Data/test/audios/raw にアップロードします。

また音声ファイルの書き起こしした内容を以下のフォーマットに沿って作成して、Data/test/filelists/text.list に記載します

フォーマットは以下です

Data/test/audios/wavs/audio1.wav|model_name|JP|こんにちは、お元気ですか?
Data/test/audios/wavs/audio2.wav|model_name|JP|私は元気かなー。
...

configの作成とモデルのダウンロード

こちらの環境では、以下の手順が終わっていないとうまくいきませんでした

  1. HFにあるモデルを models にアップロード
  2. 音声ファイルのアップロード
  3. text.listの作成
  4. config.yamlの変更

以下のコマンドを2回実行します。 1. config.yamlを作成

python preprocess_text.py
  1. モデルのダウンロード
python preprocess_text.py

音声ファイルのリサンプリング

wavsにアップロードした音声を学習するために変換をします。以下のコマンドを実行してリサンプリングを行います

python resample.py

学習の準備

configの変更

学習に向けてbatch sizeを設定します.
Data/test/config.json にある batch_sizeを4くらいに設定します

以下のコマンドを実行して準備用のデータ等を作成します

python preprocess_text.py
python bert_gen.py
python emo_gen.py

これらの実行後に Data/test/filelists/train.listData/test/filelists/val.list の中に文字が入っていれば成功です

スクリプトの修正

一部スクリプトを修正します

emo_gen.py の 112行目を

np.expand_dims(wav, 0).astype(np.float),

から

np.expand_dims(wav, 0).astype(float),

に変更します

推論

学習が終わった後は、学習済みのモデルを使って

modelのところを以下のように G_~.pth で使用したい学習済みモデルを指定します

webui:
  # 推理设备
  device: "cuda"
  # 模型路径
  model: "models/G_4000.pth"

備考

cudaのver確認方法

nvidia-smi -q -u | grep "CUDA Version" | cut -d":" -f2 | tr -d "[:blank:]"

qiita.com

複数のPythonのversionをインストールする

以下のコマンドで特定のversionをインストールします

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 10

以下で、インストールしたversionを定義します

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 130

以下でインストールしたversionに切り替えします

sudo update-alternatives --set python /usr/bin/python3.10

qiita.com

フォルダの中にある.wavファイルを日付順にソートしてCLIで表示

音声ファイルの一覧を取得する際に使用したスクリプトです

list_mp3_by_date.py

import os
import sys

def list_mp3_files(directory):
    # ファイルの一覧を取得し、更新日時でソートする
    files = [f for f in os.listdir(directory) if f.endswith('.mp3')]
    sorted_files = sorted(files, key=lambda x: os.path.getmtime(os.path.join(directory, x)))

    # ファイル名のみを表示
    for file in sorted_files:
        print(file)

if __name__ == "__main__":
    # コマンドライン引数を取得(引数がない場合は現在のディレクトリ)
    input_path = sys.argv[1] if len(sys.argv) > 1 else ''

    # 実行中のスクリプトのディレクトリを取得し、入力パスを追加
    current_directory = os.path.dirname(os.path.realpath(__file__))
    target_directory = os.path.join(current_directory, input_path)

    list_mp3_files(target_directory)

フォルダ内のmp3ファイルの再生時間合計取得

学習データはどのくらいあるのかを知るために使用

cal_sum_mp3.py

import os
import eyed3

def calculate_total_duration(directory):
    total_duration = 0
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".mp3"):
                audiofile = eyed3.load(os.path.join(root, file))
                if audiofile is not None and audiofile.info is not None:
                    total_duration += audiofile.info.time_secs
    return total_duration

def format_duration(seconds):
    minutes = seconds // 60
    seconds = seconds % 60
    return f"{minutes} m {seconds} s"

current_directory = os.path.dirname(os.path.realpath(__file__))
total_duration = calculate_total_duration(current_directory)
formatted_duration = format_duration(total_duration)

print(formatted_duration)

フォルダ内のmp3をffmpegを使ってwavに変換

convert_to_wav.sh

for file in *.mp3; do
    ffmpeg -i "$file" -ar 44100 "${file%.mp3}.wav"
done

TypeError: mel() takes 0 positional arguments but 5 were givenが出る

Pythonのverが3.10以外だとエラーが出るみたいです。
3.11で起動確認したところ、以下のエラーが出たのでpythonのversionを変更してみてください

User
Traceback (most recent call last):
  File "/home/test/Bert-VITS2/train_ms.py", line 700, in <module>
    run()
  File "/home/test/Bert-VITS2/train_ms.py", line 299, in run
    train_and_evaluate(
  File "/home/test/Bert-VITS2/train_ms.py", line 422, in train_and_evaluate
    mel = spec_to_mel_torch(
          ^^^^^^^^^^^^^^^^^^
  File "/home/test/Bert-VITS2/mel_processing.py", line 86, in spec_to_mel_torch
    mel = librosa_mel_fn(sampling_rate, n_fft, num_mels, fmin, fmax)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: mel() takes 0 positional arguments but 5 were given