Closed6

MSの音声処理フレームワーク「SpeechT5」を試す(TTSだけ)

kun432kun432

初出は2022年と少し古いのだけども、RedditあたりでTTSについてのコメント見ている限り、まだちょいちょいオススメで挙げられることがあるようなので、軽く試してみる。

GitHubレポジトリ

https://github.com/microsoft/SpeechT5/

SpeechT5

音声言語処理のための統一モーダル音声・テキスト事前学習:

SpeechT5ACL 2022):SpeechT5: 統一モーダルのエンコーダ・デコーダによる音声言語処理のための事前学習

Speech2CINTERSPEECH 2022):未ペア音声データによるエンドツーエンドASRモデルのためのトランスフォーマーデコーダ事前学習

YiTransIWSLT 2022):IWSLT 2022 オフライン共有タスクのためのYiTransエンドツーエンド音声翻訳システム

SpeechUTEMNLP 2022):SpeechUT: エンコーダ・デコーダベースの音声・テキスト事前学習のための隠れ単位を用いた音声とテキストの橋渡し

SpeechLMIEEE/ACM TASLP):SpeechLM: 未ペアテキストデータを用いた強化音声事前学習

Speech2SICASSP 2023):直接的な音声から音声翻訳のための音声とバイリンガルテキストによる共同事前学習

Prosody-SpeechT5ICASSP 2023):表現豊かなニューラルTTSのためのプロソディ認識型SpeechT5

VATLMIEEE Transactions on Multimedia):VATLM: 音声表現学習のための統一マスク予測による視覚・音声・テキスト事前学習

VALL-E XArxiv 2023):あなた自身の声で外国語を話す:クロスリンガルニューラルコーデック言語モデリング

VioLAArxiv 2023):VioLA: 音声認識、音声合成、翻訳のための統一コーデック言語モデル

WavLLMArxiv 2024):WavLLM: 頑健かつ適応的な音声大規模言語モデルを目指して

更新情報

  • 2024年4月:WavLLM Arxiv
  • 2024年3月:SpeechLM が IEEE/ACM Transactions on Audio, Speech, and Language Processing に採録
  • 2023年5月:VioLA Arxiv
  • 2023年5月:VATLM が IEEE Transactions on Multimedia に採録
  • 2023年3月:VALL-E X Arxiv および Demo
  • 2023年2月:Speech2S および Prosody-SpeechT5 が ICASSP 2023 に採録
  • [HuggingFace 統合] 2023年2月:SpeechT5 モデルが HuggingFace に公開
  • [モデル公開] 2022年11月:VATLM モデル公開
  • 2022年11月:VATLM Arxiv
  • 2022年11月:Speech2S Arxiv
  • [モデル公開] 2022年10月:SpeechUT モデル公開
  • 2022年10月:SpeechUT が EMNLP 2022 に採録
  • [モデル公開] 2022年10月:SpeechLM モデル公開
  • 2022年9月:SpeechLM Arxiv
  • [評価] 2022年6月:エンドツーエンドSTシステム YiTransIWSLT 2022 共有タスクで上位を獲得
  • 2022年6月:Speech2C が InterSpeech 2022 に採録
  • [モデル公開] 2022年5月:Speech2C モデル公開
  • [モデル公開] 2022年4月:SpeechT5 モデル公開
  • 2022年3月:Speech2C Arxiv
  • 2022年2月:SpeechT5 が ACL 2022 に採録
  • 2021年10月:SpeechT5 Arxiv

SpeechT5の紹介

T5(Text-To-Text Transfer Transformer)が事前学習済み自然言語処理モデルとして成功を収めたことに動機づけられ、我々は自己教師ありの音声/テキスト表現学習のためのエンコーダ・デコーダ事前学習を探求する統一モーダルフレームワーク「SpeechT5」を提案する。

SpeechT5フレームワークは、共有のエンコーダ・デコーダネットワークと、6種類のモダリティ特化型(音声/テキスト)のプレ/ポストネットから構成されている。

入力された音声/テキストは、プレネットを通じて前処理され、その後共有のエンコーダ・デコーダネットワークによりシーケンス変換が行われ、最後にポストネットによってデコーダ出力に基づいて音声またはテキストとして出力が生成される。


referred from https://github.com/microsoft/SpeechT5/

大規模なラベルなし音声およびテキストデータを活用して、SpeechT5を事前学習し、音声とテキストの両方に対応する統一モーダル表現を学習させることで、両モダリティのモデリング能力を高めることを目指している。

音声情報とテキスト情報を統一された意味空間に整列させるために、我々はクロスモーダルなベクトル量子化手法を提案する。この手法では、エンコーダとデコーダのインターフェースとして、潜在単位で音声/テキスト状態をランダムに混合する。

広範な評価により、本提案するSpeechT5フレームワークが、音声認識、音声合成、音声翻訳、音声変換、音声強調、話者識別など多様な音声言語処理タスクにおいて優れた性能を発揮することが示された。

ライセンス

本プロジェクトは、ソースツリーのルートディレクトリにある LICENSE ファイルに記載されたライセンスの下で提供されています。

ソースコードの一部は FAIRSEQ および ESPnet プロジェクトに基づいています。

Microsoft オープンソース行動規範

ふむ、自分はTTSのコンテキストで調べ始めたけど、ASRや音声変換なども含むフレームワークなんだね。昔試したVALL-E Xなんかもリストには含まれている。

論文についてはalphaXivのまとめを参照。

https://www.alphaxiv.org/ja/overview/2110.07205

kun432kun432

TTSのモデル

https://huggingface.co/microsoft/speecht5_tts

Colaboratory T4で試す

パッケージインストール

!pip install --upgrade pip
!pip install --upgrade transformers sentencepiece datasets[audio]

transformersのpipelineを使う場合。モデルロードには少しだけ時間がかかる。

from transformers import pipeline
from datasets import load_dataset
import soundfile as sf
import torch

synthesiser = pipeline("text-to-speech", "microsoft/speecht5_tts")
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
speaker_embedding = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
# この埋め込みは、ご自身のものに置き換えることもできます。

speech = synthesiser(
    "Hello, my dog is cooler than you!",
    forward_params={"speaker_embeddings": speaker_embedding}
)
sf.write(
    "speech.wav",
    speech["audio"],
    samplerate=speech["sampling_rate"]
)

Colaboratoryで再生する場合

from IPython.display import Audio

Audio("speech.wav", )

生成されたもの

https://audio.com/kun432/audio/speecht5-sample-1

VRAM消費は微増レベル

出力
Sat May 17 17:01:05 2025       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.15              Driver Version: 550.54.15      CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  Tesla T4                       Off |   00000000:00:04.0 Off |                    0 |
| N/A   43C    P0             26W /   70W |     886MiB /  15360MiB |     16%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

シンプル・軽量に使える感じなんだけども、生成された音声は感情の起伏に乏しい感じ。

音声については、以下のデータセットを使用している。

https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors

CMU ARCTIC から抽出されたスピーカー埋め込み

データセットには、発話ごとに 1 つの .npy ファイルがあり、合計 7931 ファイルがあります。スピーカー埋め込みは 512 要素の X ベクトルです。

CMU ARCTIC データセットは、発話を以下のスピーカーに分類しています。

  • bdl (米国男性)
  • slt (米国女性)
  • jmk (カナダ男性)
  • awb(スコットランド男性)
  • rms(米国男性)
  • clb(米国女性)
  • ksp(インド男性)
embeddings_dataset
出力
Dataset({
    features: ['filename', 'xvector'],
    num_rows: 7931
})

雑だけどこんな感じで各音声のインデックスは取れるかな

voices = {}

for idx, fn in enumerate(embeddings_dataset["filename"]):
    if fn[:-6] not in voices:
        print(idx, ":", fn[:-6])
        voices[fn[:-6]] = idx
出力
0 : cmu_us_awb_arctic-wav-arctic
1138 : cmu_us_bdl_arctic-wav-arctic
2270 : cmu_us_bdl_arctic-wav-
2271 : cmu_us_clb_arctic-wav-arctic
3403 : cmu_us_jmk_arctic-wav-arctic
4535 : cmu_us_ksp_arctic-wav-arctic
5667 : cmu_us_rms_arctic-wav-arctic
6799 : cmu_us_slt_arctic-wav-arctic

音声のインデックスを指定して生成すれば良い

speaker_embedding = torch.tensor(embeddings_dataset[2271]["xvector"]).unsqueeze(0)
speech = synthesiser(
    "Good morning. It's a beautiful day today. On days like this, I feel like going to the horse races.",
    forward_params={"speaker_embeddings": speaker_embedding}
)
sf.write(
    "speech.wav",
    speech["audio"],
    samplerate=speech["sampling_rate"]
)
Audio("speech.wav", autoplay=True)

pipelineを使わない書き方も

from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
from datasets import load_dataset
import torch
import soundfile as sf
from datasets import load_dataset
from IPython.display import Audio

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

inputs = processor(text="Hello, my dog is cute.", return_tensors="pt")

embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)

speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)

sf.write("speech.wav", speech.numpy(), samplerate=16000)
Audio("speech.wav", autoplay=True)
kun432kun432

日本語はこちら

https://huggingface.co/esnya/japanese_speecht5_tts

なのだが、すでに古くなっていることもあって、今の環境だとそのまま実行してもエラーになる。以下あたりを参考に。

https://huggingface.co/esnya/japanese_speecht5_tts/discussions/2

https://ayousanz.hatenadiary.jp/entry/2025/02/19/165137

ただ、色々やってみたがColaboratoryでは動かせなかった。多分いろいろ事前にインストールされているものが合わないのだろうと思う。ローカルのUbuntu-22.04(RTX4090)では動かせたので、一応記録。

uvで仮想環境作成。Python-3.11じゃないと動かせなかった。

uv init -p 3.11 speech-t5-ja && cd speech-t5-ja
uv venv

パッケージインストール。

uv pip install transformers==4.29.2 sentencepiece torch soundfile accelerate pyopenjtalk-plus[onnxruntime]

トークナイザーの修正コードをダウンロード

curl -O https://huggingface.co/esnya/japanese_speecht5_tts/resolve/main/speecht5_openjtalk_tokenizer.py

このファイルを修正する。

speecht5_openjtalk_tokenizer.py
(snip)
#from transformers.models.speecht5.tokenization_speecht5 import (
#    PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES,
#)
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
    "microsoft/speecht5_asr": 1024,
    "microsoft/speecht5_tts": 1024,
    "microsoft/speecht5_vc": 1024,
}

あとはモデルカードにあるコードを実行するだけ。

sample.py
import numpy as np
from transformers import (
    SpeechT5ForTextToSpeech,
    SpeechT5HifiGan,
    SpeechT5FeatureExtractor,
    SpeechT5Processor,
)
from speecht5_openjtalk_tokenizer import SpeechT5OpenjtalkTokenizer
import soundfile
import torch

model_name = "esnya/japanese_speecht5_tts"
with torch.no_grad():

    model = SpeechT5ForTextToSpeech.from_pretrained(
        model_name, device_map="cuda", torch_dtype=torch.bfloat16
    )

    tokenizer = SpeechT5OpenjtalkTokenizer.from_pretrained(model_name)
    feature_extractor = SpeechT5FeatureExtractor.from_pretrained(model_name)
    processor = SpeechT5Processor(feature_extractor, tokenizer)
    vocoder = SpeechT5HifiGan.from_pretrained(
        "microsoft/speecht5_hifigan", device_map="cuda", torch_dtype=torch.bfloat16
    )

    input = "吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。"
    input_ids = processor(text=input, return_tensors="pt").input_ids.to(model.device)

    speaker_embeddings = np.random.uniform(
        -1, 1, (1, 16)
    )  # (batch_size, speaker_embedding_dim = 16), first dimension means male (-1.0) / female (1.0)
    speaker_embeddings = torch.FloatTensor(speaker_embeddings).to(
        device=model.device, dtype=model.dtype
    )

    waveform = model.generate_speech(
        input_ids,
        speaker_embeddings,
        vocoder=vocoder,
    )

    waveform = waveform / waveform.abs().max()  # normalize
    waveform = waveform.reshape(-1).cpu().float().numpy()

    soundfile.write(
        "output.wav",
        waveform,
        vocoder.config.sampling_rate,
    )
uv run sample.py

生成した音声はこんな感じ

https://audio.com/kun432/audio/speecht5-ja-sample-1

参考にさせてもらったページのやり方を組み合わせたような感じだね。

kun432kun432

今となってはもっと生成品質の良いものもあるとは思うけど、軽量で使いやすいってのは環境によっては必要になる場合もあるのかもね。

このスクラップは4ヶ月前にクローズされました