技術 約4分で読めます

Pocket TTS - CPUで動く軽量テキスト音声合成

Pocket TTSとは

Kyutai Labsが公開したオープンソースのテキスト音声合成(TTS)モデル。特徴は以下の通り。

  • 100Mパラメータと軽量
  • CPUでリアルタイムより高速に動作(GPUなしでOK)
  • ボイスクローニング対応(WAVファイルを渡せば任意の声で合成可能)
  • MITライセンス

論文「Continuous Audio Language Models」(arXiv:2509.06926)の実装として公開された。

CALMのアプローチ

従来の音声言語モデル(ALM)は音声を離散的なトークン列として扱っていた。音声波形をニューラルネットで圧縮し、「コードブック」と呼ばれる辞書から最も近いパターンのIDを選んで並べる方式。MP3のような非可逆圧縮に近い。

この方式には課題がある。

  • トークンは非可逆圧縮から生成されるため、ビットレートに制限がある
  • 音質を上げるにはトークン数を増やす必要があり、計算コストが増大する

CALM(Continuous Audio Language Model)は連続的なアプローチを採用。

  1. Transformerバックボーンが各時刻の文脈埋め込みを生成
  2. MLPが音声VAEの次フレームを連続的に生成

非可逆圧縮を回避することで、低い計算コストで高品質な音声生成を実現した。

損失関数

VAEの訓練には以下の損失関数を使用。

LVAE=λtLt+λfLf+λadvLadv+λfeatLfeat+λKLLKL+λdistillLdistill\mathcal{L}_{\text{VAE}} = \lambda_t \mathcal{L}_t + \lambda_f \mathcal{L}_f + \lambda_{\text{adv}} \mathcal{L}_{\text{adv}} + \lambda_{\text{feat}} \mathcal{L}_{\text{feat}} + \lambda_{\text{KL}} \mathcal{L}_{\text{KL}} + \lambda_{\text{distill}} \mathcal{L}_{\text{distill}}

λ\lambdaは各項の重み係数。L\mathcal{L}が損失(小さいほど良い)。

  • Lt\mathcal{L}_t: 時間領域の再構成損失(波形がどれだけ元に近いか)
  • Lf\mathcal{L}_f: 周波数領域の再構成損失(スペクトルがどれだけ元に近いか)
  • Ladv\mathcal{L}_{\text{adv}}: 敵対的損失(GANの「本物っぽさ」判定)
  • Lfeat\mathcal{L}_{\text{feat}}: 特徴マッチング損失(中間層の特徴が似ているか)
  • LKL\mathcal{L}_{\text{KL}}: KL正則化(潜在空間が正規分布に近いか)
  • Ldistill\mathcal{L}_{\text{distill}}: WavLM蒸留損失(音声認識モデルから意味情報を学ぶ)

特に Ldistill\mathcal{L}_{\text{distill}} が面白い。波形やスペクトルの一致だけを見ると「数値的には似てるけど人間には違って聞こえる」ケースが出てくる。逆に「波形は違うけど人間には同じに聞こえる」こともある。WavLM蒸留では、音声認識モデル(WavLM)が「同じ内容として認識するか」を損失に組み込むことで、人間の知覚に近い「似てる」を学習させている。

従来のRVQ(Residual Vector Quantization)をガウス分布強制のVAEボトルネックに置き換えることで、量子化損失を排除。さらに一貫性モデル(Consistency Model) による1ステップ推論で高速化している。

音声解析の基礎(FFTや相関係数)についてはカラオケ採点の記事も参照。

インストール

pip install pocket-tts

要件:

  • Python 3.10〜3.14
  • PyTorch 2.5以上

使い方

CLI

# プリセット音声で生成
pocket-tts generate --voice alba --text "Hello, world!"

# カスタム音声(ボイスクローニング)
pocket-tts generate --voice /path/to/voice.wav --text "Hello, world!"

プリセット音声は8種類: alba, marius, javert, jean, fantine, cosette, eponine, azelma

Python API

from pocket_tts import TTSModel

# モデル読み込み
tts = TTSModel.load_model()

# プリセット音声で生成
voice_state = tts.get_state_for_voice("alba")
audio = tts.generate_audio(voice_state, "Hello, world!")

# カスタム音声で生成
voice_state = tts.get_state_for_audio_prompt("/path/to/voice.wav")
audio = tts.generate_audio(voice_state, "Hello, world!")

ローカルWebサーバー

pocket-tts serve
# http://localhost:8000 でアクセス

ボイスクローニングの注意

WAVファイルを指定すれば任意の声で音声合成ができるが、利用規約で以下が禁止されている。

  • 本人の明示的な同意なしでのボイスクローニング
  • 音声詐称・偽造目的での使用

自分の声や許可を得た相手の声で使う分にはOK。

リンク