日本語対応、高性能ボイスクローン
前回、かなり高性能なオープンソースのINDEX-TTSというものを紹介させていただきました。
論文は以下にあります
そこには他のやつとの比較があり、最初に読んだ当時はあまり注意を払っていなかったのですが
SSという指標
それを見るとCosyVoiceというものが高い評価得点をだしています。特にSSというのが声がどれだけ似ているかを表す指標のようなのです。なので早速それを試したお話です。
またINDEX-TTSが推論のコードしか公開されていないのに対して、まだ試せてないですが、このCosyVoiceではトレーニングもできるようです。また声の特徴を保存もできるみたいです。
ただし、INdex-TTS,CoquiTTS,Openvoice_V2が
1)クローンさせたい人の音声
2)しゃべらせたい言葉(文字列)
だけでありましたが、
CosyVoiceは最初だけ、それに加えて
3)クローンさせたい人の音声で語られている言葉の書き起こし文字
も入力しなければいけません。
ただ20-30秒ほどの音声と書き起こしのセットを入力してその特徴量を保存してもらい、次回からはその特徴を直接つかってボイスクローンで音声生成できること考えるとそれほど手間ではなさそうです。日本語も含めた多言語も対応しているので、前回紹介したINDEX-TTSよりはかなりポイント高いと感じました。
(2か月近くたって気づくのはうかつでした。💦)
インストールもめちゃくちゃシンプルでした。
論文は以下にあります
そしてコードも公開されてます
インストールはいたってシンプルでした。私はpipとcondaを混在させるのがどうも嫌いだったのでpyenvで実施してます。
# pyenv install 3.10.16
# pyenv virtualenv 3.10.16 cosyvoice
# pyenv activate cosyvoice
(cosyvoice)$ git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
(cosyvoice)$ cd CosyVoice
(cosyvoice)$ git submodule update --init --recursive
requirements.txt を入れる前に念のため先にSOXのモジュールをaptで入れておきます。そしてPIPを実施しました。
(cosyvoice)$ apt install sox libsox-dev
(cosyvoice)$ pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com
その後、モデルをダウンロードします。相当巨大で結構時間がかかりましたが気長に待ちます。以下のPYTHONを作成して実行するだけです
[model_download.py]
from modelscope import snapshot_download
snapshot_download('iic/CosyVoice2-0.5B', local_dir='pretrained_models/CosyVoice2-0.5B')
snapshot_download('iic/CosyVoice-300M', local_dir='pretrained_models/CosyVoice-300M')
snapshot_download('iic/CosyVoice-300M-SFT', local_dir='pretrained_models/CosyVoice-300M-SFT')
snapshot_download('iic/CosyVoice-300M-Instruct', local_dir='pretrained_models/CosyVoice-300M-Instruct')
snapshot_download('iic/CosyVoice-ttsfrd', local_dir='pretrained_models/CosyVoice-ttsfrd')
実行
(cosyvoice)$ python model_download.py
以下のコードで実際に音声生成をさせます。
この段階で動かす子尾ができる状態ですが、実行のたびに
failed to import ttsfrd, use wetext instead
という警告がでます。これは“wetext” と呼ばれるテキスト前処理モデルを ModelScope サーバー(www.modelscope.cn)から自動でダウンロードしていることを示しています。
以下のttsfrdをインストールする手順は不要ですが、外部からこの前処理モデルをダウンロードせずにローカルで動かすように以下の手順も実施しておきます。
(オプション)
(cosyvoice)$ pip install pretrained_models/CosyVoice-ttsfrd/ttsfrd_dependency-0.1-py3-none-any.whl
(cosyvoice)$ pip install pretrained_models/CosyVoice-ttsfrd/ttsfrd-0.4.2-cp310-cp310-linux_x86_64.whl
(cosyvoice)$ cd pretrained_models/CosyVoice-ttsfrd/
(cosyvoice)$ unzip resource.zip
さてまず単純に日本語話者の声で任意の日本語をしゃべらせる。
[test1.py]
import sys
sys.path.append("third_party/Matcha-TTS")
from cosyvoice.cli.cosyvoice import CosyVoice2
from cosyvoice.utils.file_utils import load_wav
import torchaudio
cosyvoice = CosyVoice2(
"pretrained_models/CosyVoice2-0.5B", load_jit=False, load_trt=False, fp16=False
)
#私の名前は山田太郎...としゃべった音声がtakeofuture.wav
prompt_speech_16k = load_wav(
"./asset/takeofuture.wav", 16000
)
def text_generator():
yield "この勉強会の目的は、"
yield "最新の研究論文をできるだけ迅速に"
yield "実装できるようになるための"
yield "訓練の場となることです。"
for i, j in enumerate(
cosyvoice.inference_zero_shot(
text_generator(),
"私の名前は山田太郎です。ラーメンが大好きです。カレーライスも大好きです。ゲームは嫌いです。",
prompt_speech_16k,
stream=False,
)
):
torchaudio.save("test1.wav".format(i), j["tts_speech"], cosyvoice.sample_rate)
これで音声が生成されます。
(cosyvoice)$ python test1.py
さらに、英語話者の声でも日本語も話させることができました。
[test2.py]
import sys
sys.path.append("third_party/Matcha-TTS")
from cosyvoice.cli.cosyvoice import CosyVoice2
from cosyvoice.utils.file_utils import load_wav
import torchaudio
cosyvoice = CosyVoice2(
"pretrained_models/CosyVoice2-0.5B", load_jit=False, load_trt=False, fp16=False
)
#Thanks so much to my friend.から始まる英語音声 MaryMcLeodBethune.wav
prompt_speech_16k = load_wav(
"./asset/MaryMcLeodBethune.wav", 16000
)
def text_generator():
yield "この勉強会の目的は、"
yield "最新の研究論文をできるだけ迅速に"
yield "実装できるようになるための"
yield "訓練の場となることです。"
for i, j in enumerate(
cosyvoice.inference_zero_shot(
text_generator(),
"Thanks so much to my friend. Good afternoon. My name is Mary McLeod Bethune. I was born July 10th, 1875. And some of my greatest accomplishments I feel are in education, civil rig>
prompt_speech_16k,
stream=False,
)
):
torchaudio.save("test1.wav".format(i), j["tts_speech"], cosyvoice.sample_rate)
(cosyvoice)$ python test2.py
実行は明らかにindex-ttsより遅かったです、また、バグなのかやり方が悪かったのか生成された音声の最初に、参照音声の最後の文章がそのまま音声として入ってます。(直し方わかったらまた記事、更新します。)
さて、今度は上のtest1.py, test2.pyで使った音声をあらかじめ話者IDとともにその特徴を保存させてみましょう!
[regist_voice.py]
import sys
sys.path.append("third_party/Matcha-TTS")
from cosyvoice.cli.cosyvoice import CosyVoice2
from cosyvoice.utils.file_utils import load_wav
import torchaudio
# 1) モデルのロード(過去に保存した spkinfo.pk があれば自動で読み込み)
cosyvoice = CosyVoice2(
"pretrained_models/CosyVoice2-0.5B",
load_jit=False, load_trt=False, fp16=False
)
# 2) プロンプト用 WAV と書き起こしで話者登録(英語話者)
prompt_wav = load_wav("./asset/MaryMcLeodBethune.wav", 16000)
prompt_text = (
"Thanks so much to my friend. Good afternoon. My name is Mary McLeod Bethune. "
"I was born July 10th, 1875. And some of my greatest accomplishments I feel are in education, civil rights, and women's organizations."
)
# add_zero_shot_spk が True を返せば OK
ok = cosyvoice.add_zero_shot_spk(prompt_text, prompt_wav, "mary_bethune")
assert ok, "mary_bethune:ゼロショット話者の登録に失敗しました"
# spkinfo.pk を保存(model_dir/spkinfo.pk が作成されます)
cosyvoice.save_spkinfo()
# 3) プロンプト用 WAV と書き起こしで話者登録(日本語話者)
prompt_wav = load_wav("./asset/takeofuture.wav", 16000)
prompt_text = (
"私の名前は山田太郎です。"
"ラーメンが大好きです。"
"カレーライスも大好きです。"
"ゲームはきらいです。"
)
# add_zero_shot_spk が True を返せば OK
ok = cosyvoice.add_zero_shot_spk(prompt_text, prompt_wav, "takeofuture")
assert ok, "takeofuture:ゼロショット話者の登録に失敗しました"
# spkinfo.pk を保存(model_dir/spkinfo.pk が作成されます)
cosyvoice.save_spkinfo()
これを実行すると以下に特徴を記録したファイルができあがります。
pretrained_models/[model名]/spk2info.pt
上記の場合は以下に保存されるはずです
pretrained_models/CosyVoice2-0.5B/spk2info.pt
(cosyvoice)$ python regist_voice.py
さらに確認用のコードを作成しておきます。
[voice_list.py]
import torch
# spk2info.pt のパスを指定
spkinfo_path = "pretrained_models/CosyVoice2-0.5B/spk2info.pt"
# PyTorch 形式の辞書オブジェクトをロード
spk_dict = torch.load(spkinfo_path)
# 登録されている話者ID の一覧を表示
print("登録済みの話者ID:", list(spk_dict.keys()))
(cosyvoice)$ python voice_list.py
登録済みの話者ID: ['mary_bethune', 'takeofuture']
さていよいよ今度はこの登録済の話者に何かしゃべらせます。2人の登録話者(日本語話者、英語話者)に日本語をしゃべらせます!
[voice_generate_all.py]
import sys
import torch
sys.path.append("third_party/Matcha-TTS")
from cosyvoice.cli.cosyvoice import CosyVoice2
import torchaudio
# ── 1) CosyVoice2 モデルロード ──
cosyvoice = CosyVoice2(
"pretrained_models/CosyVoice2-0.5B",
load_jit=False,
load_trt=False,
fp16=False
)
# ── 2) 登録済み話者IDの取得 ──
spkinfo_path = "pretrained_models/CosyVoice2-0.5B/spk2info.pt"
spk_dict = torch.load(spkinfo_path)
speaker_ids = list(spk_dict.keys())
print("登録済みの話者ID:", speaker_ids)
# ── 3) 合成したいテキスト
text = "ヤッホー、御嶽山にいって、温泉にはいって、カラオケ歌うぞ。"
# ── 4) 各話者でループして合成・保存 ──
for spk in speaker_ids:
for i, result in enumerate(
cosyvoice.inference_zero_shot(
text, # 合成したい文章
"", # 書き起こし不要
None, # WAV不要
zero_shot_spk_id=spk, #音声、書き起こしの代わりに登録済話者IDを!
stream=False
)
):
filename = f"{spk}_otakeonsen_{i}.wav"
torchaudio.save(filename, result["tts_speech"], cosyvoice.sample_rate)
print(f"Saved: {filename}")
実行:
(cosyvoice)$ python voice_generate_all.py
話者IDを使た方法では、入力音声の最後が混じる問題はおきませんでした。しかし、御嶽山という感じをどうも中国語読みしてました。
(更新)どうも発話させる言葉が長いと、参照に使った音声が混じるようです。
Discussion