Closed7

「OuteTTS」を試す

kun432kun432

https://huggingface.co/OuteAI/OuteTTS-0.3-1B

https://huggingface.co/OuteAI/OuteTTS-0.3-500M

OuteTTS バージョン 0.3

OuteTTSバージョン0.3では、さまざまな使用事例に合わせて調整された複数のモデルバリエーションが導入されています。このリリースでは、句読点のサポートを追加し、生成された音声の流暢性と明瞭性を向上させることで、音声合成の自然性と一貫性が大幅に強化されています。サポートされている句読点は次のとおりです:'.', '!', '?', ',', '"', '„', '¡', '¿', '…', '...', '。', '!', '?', ',', '؟'。これらは特殊トークンに変換されます。例えば、.<|period|> に変換されます。さらに、モデルは改良され拡張されたデータセットでトレーニングされ、より幅広い言語をカバーできるようになりました。このバージョンでは、新たに**ドイツ語(de)フランス語(fr)**の2言語がサポートされ、英語(en)日本語(jp)韓国語(ko)中国語(zh)フランス語(fr)、**ドイツ語(de)**の6言語に対応しています。

OuteTTSは、テキスト音声変換(TTS)と音声合成機能により、既存のあらゆる大規模言語モデル(LLM)を拡張するソリューションとして設計されています。オリジナルのアーキテクチャを維持することで、幅広いライブラリやツールとの高い互換性を確保し、柔軟性を損なうことなく音声機能の統合を容易にしています。

実験的な音声コントロール機能も含まれていますが、開発はまだ初期段階です。データが限られているため、これらの機能では一貫性のない結果が生成されることがあり、モデルによっては無視されることもあります。

このモデルのトレーニングを可能にしたGPUグラントを提供してくれたHugging Face🤗に感謝いたします!

利用可能なバリエーション

OuteTTS-0.3-500M

  • ベース:Qwen2.5-0.5B(Apache-2.0
  • TTSモデルライセンス:CC-BY-SA-4.0
  • トレーニング:10,000時間の音声オーディオ(〜約40億トークン)
  • サポートされている言語:en、jp、ko(小規模データセット)、zh、fr、de

OuteTTS-0.3-1B

  • ベース:OLMo-1B(Apache-2.0
  • TTSモデルライセンス:CC-BY-NC-SA-4.0(Emiliaデータセットを組み込み、品質を向上)
  • トレーニング:20,000時間分の音声オーディオ(〜約80億トークン)
  • サポート対象言語:en、jp、ko、zh、fr、de

GGUF版もある

https://huggingface.co/OuteAI/OuteTTS-0.3-1B-GGUF

https://huggingface.co/OuteAI/OuteTTS-0.3-500M-GGUF

ライセンスは、1BはCC-BY-NC-SA-4.0、500MはCC-BY-SA-4.0なので、注意。

kun432kun432

Colaboratory T4で。

パッケージインストール

!pip install -U outetts
!pip freeze | grep -i outetts
出力
outetts==0.3.2

使い方は以下にある

https://github.com/edwko/OuteTTS/tree/main/docs/interface_v2_usage.md

モデルの設定とロード。500Mモデルを使用。

import outetts

# モデルの設定
model_config = outetts.HFModelConfig_v2(
    model_path="OuteAI/OuteTTS-0.3-500M",
    tokenizer_path="OuteAI/OuteTTS-0.3-500M"
)

# インタフェースを初期化
interface = outetts.InterfaceHF(model_version="0.3", cfg=model_config)

利用可能な音声の一覧

# デフォルトで利用可能な発話音声を表示
interface.print_default_speakers()
出力(見やすさのため編集)
 Available default speakers v2: [
    'de_male_1',
    'de_male_2',
    'en_female_1',
    'en_male_1',
    'en_male_2',
    'en_male_3',
    'fr_female_1',
    'fr_female_2',
    'fr_male_1',
    'fr_male_2',
    'jp_female_1',
    'jp_female_2',
    'jp_male_1',
    'ko_female_1',
    'zh_female_1',
    'zh_female_2',
    'zh_male_1',
    'zh_male_2'
]

日本語は、女性音声x1、男性音声x1が用意されている様子。

一旦は英語で試してみる。

from IPython.display import Audio

speaker_name = "en_male_1"

# 発話音声をロード:英語・男性1
speaker = interface.load_default_speaker(name=speaker_name)

# 発話を生成
gen_cfg = outetts.GenerationConfig(
    text="Speech synthesis is the artificial production of human speech.",
    temperature=0.1,
    repetition_penalty=1.1,
    max_length=4096,
    speaker=speaker,
)
output = interface.generate(config=gen_cfg)

# 生成された音声をファイルに保存
output.save(f"{speaker_name}.wav")

# 再生
display(Audio(f"{speaker_name}.wav", autoplay=True))

実際に生成されたものはこちら

https://audio.com/kun432/audio/outetts-sample-en-male-1

日本語もやってみる。

speaker_name = "jp_female_1"

# 発話音声をロード:日本語・女性1
speaker = interface.load_default_speaker(name=speaker_name)

gen_cfg = outetts.GenerationConfig(
    text="音声合成とは、人間の音声を人工的に作り出すことです。",
    temperature=0.1,
    repetition_penalty=1.1,
    max_length=4096,
    speaker=speaker
)
output = interface.generate(config=gen_cfg)
output.save(f"{speaker_name}.wav")

display(Audio(f"{speaker_name}.wav", autoplay=True))

実際に生成されたもの

https://audio.com/kun432/audio/outetts-sample-jp-female-1

ついでに日本語・女性2と日本語・男性1も。

https://audio.com/kun432/audio/outetts-sample-jp-female-2

https://audio.com/kun432/audio/outetts-sample-jp-male-1

kun432kun432

VRAMはこんな感じ

500M

1B

GGUFやExLlamaV2にも対応しているようなので、そのあたりを使えばよりVRAM消費を抑えれるかもしれない。

ということでGGUFを試してみる。今回はQ4_K_Mで。

!wget --content-disposition https://huggingface.co/OuteAI/OuteTTS-0.3-500M-GGUF/resolve/main/OuteTTS-0.3-500M-Q4_K_M.gguf?download=true

llama-cpp-pythonが必要になる。ビルドはめちゃめちゃ時間がかかるので、事前ビルド済みのパッケージを使った。

!CMAKE_ARGS="-DGGML_CUDA=on" FORCE_CMAKE=1 pip install llama-cpp-python

GGUF向けにモデルの設定とロード。n_gpu_layersを指定できるってことはGPUオフロードもできるってことだよね?

import outetts

# GGUFモデルの設定
model_config = outetts.GGUFModelConfig_v2(
    model_path="OuteTTS-0.3-500M-Q4_K_M.gguf",
    tokenizer_path="OuteAI/OuteTTS-0.3-500M",
    n_gpu_layers=0,
)

# GGUFインタフェースを初期化
interface = outetts.InterfaceGGUF(model_version="0.3", cfg=model_config)

以下のようなログが延々と出るが、とりあえず気にしなくて良さそう。

出力
llm_load_vocab: control token: 153329 '<|1657|>' is not marked as EOG
llm_load_vocab: control token: 152927 '<|1255|>' is not marked as EOG
llm_load_vocab: control token: 155037 '<|3365|>' is not marked as EOG
llm_load_vocab: control token: 154228 '<|2556|>' is not marked as EOG
llm_load_vocab: control token: 155425 '<|3753|>' is not marked as EOG

あとは同じ使い方。

from IPython.display import Audio

speaker_name = "en_male_1"
speaker = interface.load_default_speaker(name=speaker_name)

gen_cfg = outetts.GenerationConfig(
    text="Speech synthesis is the artificial production of human speech.",
    temperature=0.1,
    repetition_penalty=1.1,
    max_length=4096,
    speaker=speaker
)
output = interface.generate(config=gen_cfg)

output.save(f"{speaker_name}.wav")

display(Audio(f"{speaker_name}.wav", autoplay=True))

推論時のログを見ていると25レイヤーあることがわかる。

出力
llm_load_tensors: offloading 0 repeating layers to GPU
llm_load_tensors: offloaded 0/25 layers to GPU

GPUオフロードしてみる。

import outetts

model_config = outetts.GGUFModelConfig_v2(
    model_path="OuteTTS-0.3-500M-Q4_K_M.gguf",
    tokenizer_path="OuteAI/OuteTTS-0.3-500M",
    n_gpu_layers=25,  # オフロードするレイヤー数
)

interface = outetts.InterfaceGGUF(model_version="0.3", cfg=model_config)
from IPython.display import Audio

speaker_name = "en_male_1"
speaker = interface.load_default_speaker(name=speaker_name)

gen_cfg = outetts.GenerationConfig(
    text="Speech synthesis is the artificial production of human speech.",
    temperature=0.1,
    repetition_penalty=1.1,
    max_length=4096,
    speaker=speaker
)
output = interface.generate(config=gen_cfg)

output.save(f"{speaker_name}.wav")

display(Audio(f"{speaker_name}.wav", autoplay=True))

オフロードされているのがわかる

出力
llm_load_tensors: offloading 24 repeating layers to GPU
llm_load_tensors: offloading output layer to GPU
llm_load_tensors: offloaded 25/25 layers to GPU

VRAMも使用されているが、GGUFで量子化だとやはり消費が少なめ。

kun432kun432

音声クローンもできる。まずREADMEに推奨事項が記載されている

https://github.com/edwko/OuteTTS?tab=readme-ov-file#speaker-profile-recommendations

スピーカープロファイルの推奨事項

スピーカープロファイルを作成する際に最良の結果を得るため、以下の推奨事項を考慮してください:

  1. 音声クリップの長さ:
  • 10秒間の音声クリップを使用してください。
  • この長さは、モデルが話者の特徴を学習するのに十分なデータを提供しつつ、入力を管理しやすい範囲に抑えます。
  1. 音声の品質:
  • 音声が明瞭でノイズがないことを確認してください。
  • 背景ノイズや歪みがあると、モデルが正確な声の特徴を抽出する能力が低下します。
  1. 話者の特徴:
  • モデルは、訓練時に見た声に近いものを最も得意とします。訓練データに比べて大きく異なる声(例:特異なアクセントや珍しい声の特徴)を使用すると、正確に再現されない場合があります。
  • そのような場合、対象となる話者の声に特化してモデルを微調整することで、より良い再現性を得られる可能性があります。
  1. パラメータの調整:
  • 生成機能のtemperatureなどのパラメータを調整することで、合成音声の表現力や一貫性を洗練させることができます。

なるほど、音声クリップは10秒程度でいいのだけど、元の学習データセットに近しいものを使うのが良さそうである。OuteTTSの学習データを見る限り、日本語の場合はMozilla Common Voiceが良さそう。

今回は手元のITAコーパスに準じたとある音声を使ってみる(結果は公開しない)

手順は以下。

https://github.com/edwko/OuteTTS/blob/main/docs/interface_v2_usage.md#speaker-creation-and-management

モデルとインタフェースについてはこれまでと同じ。

import outetts

# モデルの設定
model_config = outetts.HFModelConfig_v2(
    model_path="OuteAI/OuteTTS-0.3-500M",
    tokenizer_path="OuteAI/OuteTTS-0.3-500M"
)

# インタフェースを初期化
interface = outetts.InterfaceHF(model_version="0.3", cfg=model_config)

今回のWAVはITAコーパスの一部(RECITATION324_127)を発話したもので、だいたい10秒程度。これを使ってクローン音声から話者プロファイルを作成する。

speaker = interface.create_speaker(
    audio_path="RECITATION324_127.wav",
    transcript="満洲は雨季以外には雨が少ないと言われているが、わたしが満洲にあるあいだは、大戦中のせいか、ずいぶん雨が多かった。"
)

# 話者プロファイルを保存
interface.save_speaker(speaker, "sample.json")

作成した話者プロファイルを使ってTTSさせてみる。

from IPython.display import Audio

speaker = interface.load_speaker("sample.json")

gen_cfg = outetts.GenerationConfig(
    text="今日はいいお天気ですね。競馬観戦にもってこいですね。",
    temperature=0.1,
    repetition_penalty=1.1,
    max_length=4096,
    speaker=speaker,
)
output = interface.generate(config=gen_cfg)

output.save("sample.wav")

display(Audio("sample.wav", autoplay=True))

自分が試した限りだと、元の音声とはかなり音声が異なる感じになった。適当な音声データで学習できる、というわけではないように感じる。このあたりは元の学習データにあるコーパスにしたがった音声データで学習した場合にどうなるのか、が気になるところ。

また、ドキュメントにはマイクから直接入力して文字起こしはWhisperを使うやり方も記載されている。デモも用意されているので、音声クローンはそれを使って確認するのがいいかもしれない。

https://outeai-outetts-0-3-1b-demo.hf.space/?__theme=system

kun432kun432

まとめ

イントネーションは結構自然に感じた。GGUFで使えるってのもいいね。ただライセンス的にはちょっと使いにくいかもしれない。

学習に関しては以下のような最低限のドキュメントしかない。自分はこのあたりの知見がないので、これで十分かどうかはちょっとわからないな・・・

https://github.com/edwko/OuteTTS/blob/main/examples/v1/python/train.md

このスクラップは2025/01/17にクローズされました