Published on

seed-vcをcpuで動かす

Authors

こんにちは
最近、seed-vcというものを見つけてとても驚きました。
seed-vcは、事前学習済みのモデルを使って、任意の音声Aを、任意の音声Bの声質に変換できる、最先端の音声変換技術です。 通常、音声変換モデルを学習するには大量の音声データが必要ですが、seed-vc はゼロショット学習と呼ばれる技術により、追加の学習データなしで、高い精度の音声変換を実現しています。

GitHub - Plachtaa/seed-vc: zero-shot voice conversion & singing voice conversion, with real-time supportGitHub - Plachtaa/seed-vc: zero-shot voice conversion & singing voice conversion, with real-time supportzero-shot voice conversion & singing voice conversion, with real-time support - Plachtaa/seed-vcgithub.comgithub.com

以下のサイト(huggingface)で試してみることができます。

Seed Voice Conversion - a Hugging Face Space by PlachtaSeed Voice Conversion - a Hugging Face Space by PlachtaDiscover amazing ML apps made by the communityhuggingface.cohuggingface.co

今回はこれをローカルcpuで動かしたいと思います

注意

  • 今回はseed-vcをCPUで動かすことを目的としています。GPU使ってやる人はこの記事を見ても意味がありません。たぶん
  • 情報は2015/01/17のものです。コード等が変更されている可能性があります。
  • 自分はIntelのmacで実行します。他の環境の方は違うかもしれないけどそこは許してください

まず実行

python3.10がいいらしいので、仮想環境を作成してとりあえず実行してみましょう。

git clone https://github.com/Plachtaa/seed-vc.git
cd seed-vc
pyenv install 3.10.16
pyenv local 3.10.16  
python3.10 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

ここまでで準備完了です。

READMEを見るといろいろ実行方法が書いてありますが、とりあえずhuggingfaceと同じようにWebUIで実行しましょう。

python app.py

そしたらなにやらたくさんのダウンロードが始まった後、以下のエラーで止まります。
よく見るとNumpyが1.x系じゃないと動かないみたいなことが書いてあったので1.x系にする

RuntimeError: Numpy is not available
pip install numpy==1.26.4

その後、もう一度app.pyを実行するとローカルサーバが立ち上がるところまではうまくいく。

Running on local URL: http://127.0.0.1:7860

アクセスするとwebuiが観れると思います。音声ファイルを2つ入れて、実行すると、、、

RuntimeError: "slow_conv2d_cpu" not implemented for 'Half'

エラーです。どうしたものか...

改変

先程のエラーは、CPU上で半精度浮動小数点数(Half)を使用した2次元畳み込み演算(slow_conv2d_cpu)が実装されていないために発生しているらしいです。

GPUではfloat16を使うことで高速化できる場合がありますが、CPUではfloat32(単精度浮動小数点数)を使う方が一般的です。

以下のようにapp.pyを書き換えることで動かせます

① 57行目付近に以下を追加

# whisper
from transformers import AutoFeatureExtractor, WhisperModel

whisper_name = model_params.speech_tokenizer.whisper_name if hasattr(model_params.speech_tokenizer,
                                                                     'whisper_name') else "openai/whisper-small"
whisper_model = WhisperModel.from_pretrained(whisper_name, torch_dtype=torch.float16).to(device)
del whisper_model.decoder
whisper_feature_extractor = AutoFeatureExtractor.from_pretrained(whisper_name)

whisper_model = whisper_model.float() # この行を追加

② 183行目付近に以下を追加

        while traversed_time < converted_waves_16k.size(-1):
            if buffer is None:  # first chunk
                chunk = converted_waves_16k[:, traversed_time:traversed_time + 16000 * 30]
            else:
                chunk = torch.cat([buffer, converted_waves_16k[:, traversed_time:traversed_time + 16000 * (30 - overlapping_time)]], dim=-1)
            
            chunk = chunk.float()  #この行を追加

③ 238行目付近の部分を変更

    feat2 = torchaudio.compliance.kaldi.fbank(ref_waves_16k,
                                              num_mel_bins=80,
                                              dither=0,
                                              sample_frequency=16000)
    feat2 = feat2 - feat2.mean(dim=0, keepdim=True)
    
    style2 = campplus_model(feat2.unsqueeze(0).float())  # .float() を追加する

④ 282行目付近のwithを取り壊す

before

        with torch.autocast(device_type=device.type, dtype=torch.float16):
            # Voice Conversion
            vc_target = inference_module.cfm.inference(cat_condition,
                                                   torch.LongTensor([cat_condition.size(1)]).to(mel2.device),
                                                   mel2, style2, None, diffusion_steps,
                                                   inference_cfg_rate=inference_cfg_rate)
            vc_target = vc_target[:, :, mel2.size(-1):]
        vc_wave = bigvgan_fn(vc_target.float())[0]

after

        # with torch.autocast(device_type=device.type, dtype=torch.float16):
        # Voice Conversion
        vc_target = inference_module.cfm.inference(cat_condition,
                                                   torch.LongTensor([cat_condition.size(1)]).to(mel2.device),
                                                   mel2, style2, None, diffusion_steps,
                                                   inference_cfg_rate=inference_cfg_rate)
        vc_target = vc_target[:, :, mel2.size(-1):]
        vc_wave = bigvgan_fn(vc_target.float())[0]

以上です。

これでapp.pyを実行すれば遅いですがCPUでも動作します。

ちなみに、app_vc.pyapp_svc.pyも同じ部分を変更すれば動きます。 ただ、この2つの場合は実行する際に--fp16 Falseのオプションをつけてくださいね