MSの音声処理フレームワーク「SpeechT5」を試す(TTSだけ)
初出は2022年と少し古いのだけども、RedditあたりでTTSについてのコメント見ている限り、まだちょいちょいオススメで挙げられることがあるようなので、軽く試してみる。
GitHubレポジトリ
SpeechT5
音声言語処理のための統一モーダル音声・テキスト事前学習:
SpeechT5(
ACL 2022
):SpeechT5: 統一モーダルのエンコーダ・デコーダによる音声言語処理のための事前学習Speech2C(
INTERSPEECH 2022
):未ペア音声データによるエンドツーエンドASRモデルのためのトランスフォーマーデコーダ事前学習YiTrans(
IWSLT 2022
):IWSLT 2022 オフライン共有タスクのためのYiTransエンドツーエンド音声翻訳システムSpeechUT(
EMNLP 2022
):SpeechUT: エンコーダ・デコーダベースの音声・テキスト事前学習のための隠れ単位を用いた音声とテキストの橋渡しSpeechLM(
IEEE/ACM TASLP
):SpeechLM: 未ペアテキストデータを用いた強化音声事前学習Speech2S(
ICASSP 2023
):直接的な音声から音声翻訳のための音声とバイリンガルテキストによる共同事前学習Prosody-SpeechT5(
ICASSP 2023
):表現豊かなニューラルTTSのためのプロソディ認識型SpeechT5VATLM(
IEEE Transactions on Multimedia
):VATLM: 音声表現学習のための統一マスク予測による視覚・音声・テキスト事前学習VALL-E X(
Arxiv 2023
):あなた自身の声で外国語を話す:クロスリンガルニューラルコーデック言語モデリングVioLA(
Arxiv 2023
):VioLA: 音声認識、音声合成、翻訳のための統一コーデック言語モデルWavLLM(
Arxiv 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システム YiTrans が IWSLT 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 ファイルに記載されたライセンスの下で提供されています。
ふむ、自分はTTSのコンテキストで調べ始めたけど、ASRや音声変換なども含むフレームワークなんだね。昔試したVALL-E Xなんかもリストには含まれている。
論文についてはalphaXivのまとめを参照。
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", )
生成されたもの
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 |
+-----------------------------------------+------------------------+----------------------+
シンプル・軽量に使える感じなんだけども、生成された音声は感情の起伏に乏しい感じ。
音声については、以下のデータセットを使用している。
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)
日本語はこちら
なのだが、すでに古くなっていることもあって、今の環境だとそのまま実行してもエラーになる。以下あたりを参考に。
ただ、色々やってみたが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
このファイルを修正する。
(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,
}
あとはモデルカードにあるコードを実行するだけ。
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
生成した音声はこんな感じ
参考にさせてもらったページのやり方を組み合わせたような感じだね。
他のタスク向けもあるので興味があれば
今となってはもっと生成品質の良いものもあるとは思うけど、軽量で使いやすいってのは環境によっては必要になる場合もあるのかもね。
TTSのファインチューニング用のnotebookが用意されている。