ChatTTS 実践ガイド:対話向け音声合成モデルの導入から話者サンプリング・細粒度プロソディ制御まで
【免费下载链接】ChatTTSA generative speech model for daily dialogue.项目地址: https://gitcode.com/GitHub_Trending/ch/ChatTTS
ChatTTS は、LLM アシスタントのような「対話シナリオ」に特化して設計された生成型テキスト読み上げ(TTS)モデルです。本ガイドでは、日本語版 README を骨格に、モデルの特徴・環境構築・基本/上級の推論コード・話者と韻律の制御手法を、ChatTTS/core.py をはじめとする実際のソースコードを照合しながら詳解します。読み終えると、ChatTTS を使って自然な対話音声を合成し、笑い声・休止・間投詞などを文レベル/単語レベルで意図どおり制御できるようになります。
[!NOTE] 本記事の対象ドキュメントである 日本語版 README 自身が「最新情報ではない可能性があり、全ての内容は英語版に基準する」と明記しています。本記事もその前提を踏まえつつ、リポジトリ内の実際のソースコード(このリポジトリのスナップショット)で検証できる内容を併記します。公式の最新情報は README(英語版) を基準としてください。対応言語は英語版同様、简体中文、Русский、Español、Français、한국어 の各ドキュメントでも確認できます。
ChatTTS とは:対話型タスクに最適化された生成音声モデル
ChatTTS は「A generative speech model for daily dialogue(日常対話のための生成型音声モデル)」を標榜するオープンソースの TTS モデルです。日本語版 README によれば、以下の特徴を持ちます。
- 会話型 TTS:対話ベースのタスク向けに最適化されており、自然で表現豊かな音声合成が可能。複数の話者をサポートし、対話形式の音声生成を容易にします。
- 細かい制御:笑い、一時停止、間投詞といった細かい韻律特徴の予測・制御が可能です。
- より良い韻律:韻律の面で多くのオープンソース TTS モデルを上回ることを目指しており、研究開発用に事前学習済みモデルを提供しています(公式ドキュメントでの説明による記述です)。
データセットとモデルに関する公式説明は以下のとおりです。
- 本体モデルは中国語と英語で構成される100,000 時間以上の音声データで学習されています。
- HuggingFace で公開されているオープンソース版は40,000 時間の事前学習モデルであり、SFT(教師ありファインチューニング)は未実施です。
モデルアーキテクチャの観点では、本リポジトリは「テキスト →(リファイン)→ 意味トークン →(自己回帰 LLM)→ 音声コード →(DVAE/Vocos デコーダ)→ 波形」という生成パイプラインを持ちます。中核クラスChatは ChatTTS/core.py に、各モデル部品(DVAE・Embed・GPT・Tokenizer・Speaker)は ChatTTS/model/ 以下に実装されています。
インストールとモデル資産の準備
インストール方法
プロジェクトのルート README.md および requirements.txt に基づくインストール手段は主に 3 通りです。
- PyPI の安定版を利用する場合:
pip install ChatTTS - リポジトリをクローンして最新版を利用する場合:
git clone <このリポジトリのURL> cd ChatTTS pip install --upgrade -r requirements.txt依存関係には
torch>=2.1.0、torchaudio、transformers>=4.41.1、vocos、vector_quantize_pytorch、pybase16384などが含まれています。Linux ではテキスト正規化用にpynini==2.1.5・WeTextProcessing・nemo_text_processingが追加で必要になります(いずれも requirements.txt に記載)。 - 開発モードでローカルインストールする場合:
pip install -e .
再現性のある環境が欲しい場合は conda を利用することもできます。
conda create -n chattts python=3.11 conda activate chattts pip install -r requirements.txtモデルのロードと資産チェック
ChatTTS.Chat()を生成したあとchat.load(...)を呼ぶと、モデルチェックポイントが自動的にダウンロード・検証されます。ソースコード上、Chat.loadのsourceパラメータは"local"/"huggingface"/"custom"の 3 種を受け付けます(ChatTTS/core.py)。
source="local"(既定値):作業ディレクトリ直下のasset/にチェックポイントが保存されていなければ、一時ディレクトリにダウンロードしてから展開します。source="huggingface":HuggingFace の2Noise/ChatTTSリポジトリから*.yaml/*.json/*.safetensorsを取得します。source="custom":custom_pathに指定した任意ディレクトリから読み込みます。
ダウンロード時には ChatTTS/utils/dl.py の sha256 検証を経て、Decoder.safetensors・DVAE.safetensors・Embed.safetensors・Vocos.safetensors・gpt/配下のファイル・tokenizer/配下のファイルが揃っているかがチェックされます。loadの主なオプションは以下のとおりです。
| 引数 | 既定値 | 説明 |
|---|---|---|
compile | False | Trueにすると推論性能が向上する可能性があります(CUDA 時のみコンパイル実行、ChatTTS/core.py 参照) |
device | 自動選択 | GPU が無い場合は CPU にフォールバック |
use_flash_attn | False | FlashAttention-2 の使用有無 |
use_vllm | False | vLLM バックエンド利用時はTrue |
coef | None | DVAE の係数(WebUI の「DVAE Coefficient」欄に対応) |
custom_path | None | source="custom"時のモデルディレクトリ |
_load内では Vocos(ボコーダ)→ DVAE → Embed → GPT → Speaker → Decoder → Tokenizer の順に各モジュールが初期化されます(ChatTTS/core.py)。
基本的な使用方法:最小限のコードで音声を合成する
日本語版 README の「基本的な使用方法」を、動作を補足する形でまとめます。
import ChatTTS from IPython.display import Audio import torch import torchaudio chat = ChatTTS.Chat() chat.load(compile=False) # より良いパフォーマンスのため True に設定可能 texts = ["ここにテキストを入力してください",] wavs = chat.infer(texts) torchaudio.save("output1.wav", torch.from_numpy(wavs[0]), 24000)ポイントを整理します。
chat.load(compile=False):compile=Trueは GPU 環境向けの高速化オプションですが、初回のコンパイル時間がかかるため、まずはFalseで動作確認するのが安全です。chat.infer(texts):textsにはstrまたはstrのリストを渡せます。出力wavsはnp.ndarray(numpy 配列)のリストで、各要素が 1 テキスト分の波形です。- 保存時のサンプルレートは24000 Hzです(ChatTTS/config/config.py の
FeatureExtractorInitArgs.sample_rate = 24000と一致)。 inferはデフォルトでテキスト分割(改行や句点で自動分割)を行い、分割したテキストごとに推論して最後に連結して返します。挙動はinferのsplit_text・max_split_batch引数で制御できます(ChatTTS/core.py)。
wavsのインデックスは入力テキストの並びに対応するため、複数文を同時に合成した場合は以下のようにループで保存できます。
for i in range(len(wavs)): try: torchaudio.save(f"basic_output{i}.wav", torch.from_numpy(wavs[i]).unsqueeze(0), 24000) except: torchaudio.save(f"basic_output{i}.wav", torch.from_numpy(wavs[i]), 24000)torchaudio のバージョンによっては
.unsqueeze(0)の有無で保存に成功する場合が異なるため、公式 README でも try/except の二段構えが推奨されています。
高度な使用方法(1):話者をサンプリングして音色を固定する
同じテキストでも話者(音色)が変わると印象が大きく変わります。ChatTTS ではガウス分布から話者ベクトルをサンプリングし、そのベクトルをテキスト文字列として保存・再利用できます。
################################### # ガウス分布から話者をサンプリングします。 rand_spk = chat.sample_random_speaker() print(rand_spk) # save it for later timbre recovery(音色再現用に保存) params_infer_code = { 'spk_emb': rand_spk, # サンプリングされた話者を追加 'temperature': .3, # カスタム温度を使用 'top_P': 0.7, # top P デコード 'top_K': 20, # top K デコード }出力されたrand_spkは一見すると意味不明な長い文字列に見えますが、これは内部実装上、話者ベクトルをpybase16384 + LZMA 圧縮で可逆エンコードした文字列です(ChatTTS/model/speaker.py のencode_prompt)。つまりこの文字列さえ保存しておけば、別のセッションでも同じ話者の音色を完全に復元できます。
話者サンプリングの仕組みをソースコードで見てみましょう。ChatTTS/model/speaker.py のSpeaker.sample_random()は、spk_statsファイル(設定上は ChatTTS/config/config.py のspk_stat)から読み込んだ平均・標準偏差をもとに、
torch.randn(dim).mul_(std).add_(mean)という形でランダムな話者ベクトルを生成しています(ChatTTS/model/speaker.py)。dimは GPT のhidden_size(既定 768)とは別にspk_emb_dim = 192が設定されています(ChatTTS/config/config.py)。
spk_embを渡した場合、推論時にはテキストの先頭に[Stts][spk_emb]...という特殊トークン列が付与され、埋め込みテーブルの該当位置に話者ベクトルが注入されます(ChatTTS/model/speaker.py)。
参考:params_infer_codeの主要パラメータ
inferの第 2 引数params_infer_codeは、ChatTTS.Chat.InferCodeParamsという dataclass で定義されており(ChatTTS/core.py)、デフォルト値は以下のとおりです。上級サンプルのように辞書で渡すことも、クラスで渡すこともできます。
| パラメータ | 既定値 | 意味 |
|---|---|---|
prompt | "[speed_5]" | 音声コード生成時のプロンプト接頭辞 |
spk_emb | None | サンプリングした話者文字列(上記のrand_spk) |
temperature | 0.3 | サンプリング温度(低いほど安定、高いほど多様) |
top_P | 0.7 | top-P(nucleus)サンプリング |
top_K | 20 | top-K サンプリング |
repetition_penalty | 1.05 | 繰り返しペナルティ |
max_new_token | 2048 | 生成する最大トークン数 |
stream_batch | 24 | ストリーム時の 1 バッチあたり生成トークン数 |
stream_speed | 12000 | ストリーム時のサンプル送出量 |
pass_first_n_batches | 2 | ストリーム時に先頭からスキップするバッチ数 |
温度はリストで渡すこともでき、その場合は 4 つの VQ レベル(num_vq=4)ごとに別々の温度を指定できます(ChatTTS/core.py)。
高度な使用方法(2):文レベルの手動制御(リファイン)
ChatTTS の生成パイプラインは「まずテキストをリファイン(発話用の整形)し、その結果をもとに音声コードを生成する」という 2 段階構成です。リファイン段階でテキストに特殊トークンを埋め込むと、文レベルの韻律を手動制御できます。
################################### # 文レベルの手動制御のために。 # テキスト内に特殊トークンを生成するには oral_(0-9)、laugh_(0-2)、break_(0-7) を使用します。 params_refine_text = { 'prompt': '[oral_2][laugh_0][break_6]' } wav = chat.infer(texts, params_refine_text=params_refine_text, params_infer_code=params_infer_code)このとき使える制御トークンの意味は以下のとおりです。
| トークン | 範囲 | 意味 |
|---|---|---|
oral_(0-9) | 0〜9 | 口語的な言い回し(間投詞的な挿入)の度合い |
laugh_(0-2) | 0〜2 | 笑いの強さ |
break_(0-7) | 0〜7 | ポーズ(休止)の長さ |
リファイン処理の本体は ChatTTS/core.py の_refine_textです。そこでは ChatTTS/model/speaker.py のdecorate_text_promptsにより、各テキストが[Sbreak]{本文}[Pbreak]{prompt}という形に装飾されてからトークナイズされ、GPT(テキストモード)で生成されます。生成されたリファイン済みテキストから[break_0]などの特殊トークンは除去され(ChatTTS/core.py)、音声コード生成段階へ渡ります。
RefineTextParamsのデフォルト値(ChatTTS/core.py)も併せて整理しておきます。
| パラメータ | 既定値 |
|---|---|
prompt | ""(空文字) |
temperature | 0.7 |
top_P | 0.7 |
top_K | 20 |
repetition_penalty | 1.0 |
max_new_token | 384 |
min_new_token | 0 |
高度な使用方法(3):単語レベルの手動制御(リファインスキップ)
単語単位で韻律トークンを直接埋め込みたい場合は、skip_refine_text=Trueにしてリファイン段階をスキップし、そのまま音声コード生成へ進みます。
################################### # 単語レベルの手動制御のために。 text = 'あなたの好きな英語の食べ物は何ですか?[uv_break][laugh][lbreak]' wav = chat.infer(text, skip_refine_text=True, params_refine_text=params_refine_text, params_infer_code=params_infer_code) torchaudio.save("output2.wav", torch.from_numpy(wavs[0]), 24000)現在リリースされているモデルでトークンレベルに直接使える制御ユニットは次の 3 つです(公式 FAQ より)。つまり「テキストのどこで笑うか/どこで短く区切るか/どこで長く切るか」を自分で指定できます。
| トークン | 意味 |
|---|---|
[laugh] | 笑い |
[uv_break] | 短い休止(単語間の区切り) |
[lbreak] | 長い休止(文を跨ぐ大きめの区切り) |
たとえば上記の例では「何ですか?」の直後に[uv_break]で軽く間を取り、[laugh]で笑いを入れ、文末の[lbreak]で長く間を置く、というニュアンスを指定しています。感情制御に関しては、FAQ のとおり「現行モデルでは上記 3 種のみ。追加の感情制御を備えたモデルは将来バージョンでオープンソース化される可能性がある」という位置づけです。
なお、リファインをスキップした場合は通常の句読点による整形や特殊トークン補完が行われないため、
[uv_break]等を自分で適切に配置する必要があります。逆に、リファイン処理に任せたい文レベルの制御(例:prompt='[oral_2][laugh_0][break_4]')はスキップせずに使うのが基本です。
実践例:日本語テキストでの自己紹介文の合成
日本語版 README には、日本語テキストで自己紹介文を合成する例が収録されています(replace('\n', '')で改行を除去している点に注意)。音声データの観点では英語はまだ実験的とされつつ、日本語テキストを中国語話者風に読み上げさせるデモとして動作します。
inputs_jp = """ ChatTTSは、対話アプリケーション用に設計されたテキストから音声へのモデルです。 [uv_break]混合言語入力をサポートし[uv_break]、韻律要素[laugh]の正確な制御を提供します [uv_break]笑い[laugh]、[uv_break]一時停止、[uv_break]およびイントネーション。[uv_break]自然で表現豊かな音声を提供します [uv_break]したがって、自己責任でプロジェクトを責任を持って使用してください。[uv_break] """.replace('\n', '') # 英語はまだ実験的です。 params_refine_text = { 'prompt': '[oral_2][laugh_0][break_4]' } audio_array_jp = chat.infer(inputs_jp, params_refine_text=params_refine_text) torchaudio.save("output3.wav", torch.from_numpy(audio_array_jp[0]), 24000)ここでは文レベルのprompt='[oral_2][laugh_0][break_4]'(口語感・控えめな笑い・中程度の休止)に加え、本文中の[uv_break]と[laugh]で単語レベルの抑揚を演出しています。
推論パイプラインの全体像(ソースコードで追う)
高度な制御がなぜ機能するのかを理解するため、chat.infer(...)内部の処理をソースコードに沿って整理します(ChatTTS/core.py)。
- 正規化:入力テキストは ChatTTS/norm.py の
Normalizerを通り、テキスト正規化・同音異義語置換(ChatTTS/res/homophones_map.json を使用)が適用されます。do_text_normalization・do_homophone_replacement引数で有効/無効を切り替え可能です。 - リファイン(省略可):
skip_refine_text=Falseなら_refine_textにより文レベルのプロンプト([oral_n]など)が処理されます。refine_text_only=Trueにするとリファイン結果のテキストだけを返すこともできます。 - 音声コード生成:
_infer_codeで、話者埋め込みと音声プロンプトを付与した入力列を GPT に与え、自己回帰的に 4 つの VQ レベル(num_vq=4、ChatTTS/config/config.py)の音声トークンを生成します。サンプリングにはtemperature・top_P・top_K・repetition_penaltyが適用され、ロジットの加工は ChatTTS/model/gpt.py のgen_logitsが担当します。 - デコード:
_decode_to_wavsで音声トークンを DVAE のデコーダ(use_decoder=Trueなら専用デコーダ)でメルスペクトログラムに変換し、最後にVocosボコーダで波形へ変換します(ChatTTS/core.py)。Vocos は ChatTTS/config/config.py で MelSpectrogram 特徴量 + VocosBackbone + ISTFTHead として構成されています。
ストリーム(逐次)生成と話者抽出について
現行のソースコードにはストリーム生成の実装も含まれています。infer(..., stream=True)とするとジェネレータが返り、InferCodeParamsのstream_batch・stream_speed・pass_first_n_batchesに従って音声チャンクを逐次受け取れます。実際のストリーム推論デモは examples/cmd/stream.py に収録されており、ChatStreamerクラスがバッファリング・再生(pyaudio、24kHz モノラル)を行います。
また、日本語版 README のロードマップには「DVAE エンコーダ/ゼロショット推論コード」や「ストリーミング音声生成」が未完了項目として並んでいますが、これは同 README が古い情報に基づくためです。このリポジトリのスナップショットでは、既にchat.sample_audio_speaker(wav)による音声サンプルからの話者抽出(ゼロショット)(ChatTTS/core.py)や、examples/cmd/stream.py・examples/web/webui.py のStream Modeが実装済みであることを確認できます。WebUI では「Sample Audio」タブで音声をアップロードすると話者コードが自動生成され、それを「Sample Audio Code」欄に貼り付けて同じ音色を再現できます。
コマンドラインと WebUI ですぐ試す
コマンドライン推論
プロジェクトルートで以下を実行すると、入力テキストごとに./output_audio_n.mp3が保存されます(examples/cmd/run.py)。
python examples/cmd/run.py "Your text 1." "Your text 2."run.pyは以下のオプションをサポートしています。
python examples/cmd/run.py \ --spk <話者文字列> \ --stream \ --source local|custom|huggingface \ --custom_path <モデルディレクトリ> \ "合成したいテキスト"--spkを省略するとランダムな話者がサンプリングされ、その話者文字列がログに表示されます(後で--spkに渡すと音色を再現できます)。--source custom --custom_path ../../models/2Noise/ChatTTSのようにすれば、任意の場所に置いたモデル資産から読み込めます。- 実行前に音素正規化用パッケージが無い場合は、examples/cmd/run.py の
load_normalizerが警告を出します(pynini=2.1.5とnemo_text_processing/WeTextProcessingの導入が必要)。
WebUI の起動
python examples/web/webui.pyブラウザ上でテキスト入力・温度/top_P/top_K スライダー・話者選択・シード指定・ストリームモードなどを操作できる Gradio 製 UI が起動します(examples/web/webui.py)。
FAQ:公式ドキュメントが示す実運用上の注意点
日本語版 README の FAQ から、実運用で重要となる 3 点を引用します。
必要 VRAM と推論速度は?
30 秒のオーディオクリップには、少なくとも4GB の GPU メモリが必要です。4090 GPU の場合、約7 つの意味トークンに相当するオーディオを 1 秒あたり生成できます。リアルタイムファクター(RTF)は約0.3です。
つまり 4090 クラスの GPU なら、生成速度は再生速度の約 3 倍(実時間の約 1/3 で合成が完了)という目安です。CPU のみの環境ではかなり遅くなるため、ストリーム再生を試す際は examples/cmd/stream.py のように一定量をプリフィルしてから再生を始めると途切れにくくなります。
モデルの安定性(複数話者・音質ムラ)が気になる場合
これは自己回帰モデル(bark および valle の場合)で一般的に発生する問題です。一般的に避けるのは難しいです。複数のサンプルを試して、適切な結果を見つけることができます。
ChatTTS も自己回帰方式の LLM ベース TTS であるため、同じテキストでも実行ごとに微妙に結果が揺れます。実務的にはmanual_seedを指定して再現性を確保する(RefineTextParams/InferCodeParamsにmanual_seedフィールドあり)か、複数回サンプリングして良いものを選ぶ運用が推奨されます。
笑い以外に感情制御はできる?
現在リリースされているモデルでは、トークンレベルの制御ユニットは
[laugh]、[uv_break]、および[lbreak]のみです。将来のバージョンでは、追加の感情制御機能を備えたモデルをオープンソース化する可能性があります。
ロードマップ(日本語版 README 記載時点)
日本語版 README に記載されたロードマップは以下のとおりです(冒頭の注記どおり、項目の進捗は英語版 README.md を基準に確認してください)。
- 40k 時間のベースモデルと spk_stats ファイルをオープンソース化
- VQ エンコーダーと Lora トレーニングコードをオープンソース化
- テキストをリファインせずにストリーミングオーディオ生成
- 複数の感情制御を備えた 40k 時間バージョンをオープンソース化
- ChatTTS.cpp(PR や新しいリポジトリが歓迎されます)
繰り返しになりますが、このリポジトリのスナップショットでは音声サンプルからの話者抽出(ゼロショット)とストリーム生成のコードが既に実装・公開されていることをソースコード上で確認できます。最新の進捗確認には英語版 README を参照してください。
免責事項と利用上の注意
日本語版 README は本リポジトリを学術目的限定と位置づけています。
- 教育・研究用途にのみ使用でき、商業的または法的な目的には使用できません。
- 著者は情報の正確性・完全性・信頼性を保証しません。
- モデルの不正利用を防ぐため、40,000 時間モデルの訓練時には少量の高周波ノイズを追加し、MP3 形式で音質を可能な限り圧縮しています。あわせて検出モデルを内部で訓練しており、将来オープンソース化を予定しています。
また技術的な背景として、本プロジェクトは bark・XTTSv2・valle(自己回帰型 TTS の成果)、fish-speech(オーディオトークナイザとしての GVQ の活用)、vocos(事前学習ボコーダとして使用)などの研究成果に基づいています(日本語版 README の謝辞より)。
まとめ
本ガイドでは 日本語版 README の内容を土台に、ChatTTS の基本合成・話者サンプリング・文レベル/単語レベルの韻律制御・ストリーム/ゼロショットといった応用を、ChatTTS/core.py・ChatTTS/model/speaker.py・ChatTTS/config/config.py などの実装と照合しながら解説しました。要点は以下の 4 つです。
chat.infer()にテキストを渡すだけで、24kHz の自然な音声波形を取得できる。sample_random_speaker()で得た話者文字列を保存すれば、音色を完全に再現できる。- リファイン段階の
promptに[oral_n][laugh_n][break_n]を指定すると文レベル、skip_refine_text=Trueと[uv_break]/[laugh]/[lbreak]で単語レベルの韻律制御が可能。 - リソースの目安(30 秒音声で約 4GB VRAM、RTF 約 0.3)を理解し、自己回帰モデル特有の揺らぎには複数サンプリングや
manual_seedで対処する。
対話音声のプロトタイプ作成や LLM アシスタントの音声応答を試す際には、examples/cmd/run.py や examples/web/webui.py のデモを起点に、上記の制御パラメータを調整しながら活用してください。
【免费下载链接】ChatTTSA generative speech model for daily dialogue.项目地址: https://gitcode.com/GitHub_Trending/ch/ChatTTS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考