YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

BlueMagpie-TTS

OpenFormosa Blue Magpie TTS

BlueMagpie-TTS是一套文字轉語音(TTS)模型,能把文字合成為自然的語音。它支援三種使用情境:

  • 一般語音合成 —— 直接把文字唸出來。
  • 聲音複製 —— 提供一段參考音檔,讓輸出模仿該語者的音色。
  • 指定語者 —— 用事先準備好的語者向量來控制音色。

同時也提供串流輸出,適合需要邊合成邊播放的應用。

🔊 線上試玩BlueMagpie-TTS Demo(Hugging Face Space)

命名由來

專案全名是 OpenFormosa Blue Magpie TTS。「藍鵲」取自台灣藍鵲(Taiwan Blue Magpie,學名 Urocissa caerulea)。選牠作為 TTS 的識別有幾層用意:

  • 會發聲、辨識度高:台灣藍鵲本來就是叫聲響亮、容易辨認的鳥,恰好呼應 TTS「把文字變成聲音」的核心。
  • 長尾的動態感:標誌性的長尾巴帶來流動、延展的視覺意象,比一般的喇叭 icon 更有記憶點與品牌個性。
  • 立足台灣:OpenFormosa(福爾摩沙)點出專案面向台灣華語、在地化語音的定位。

安裝

先把專案 clone 下來,再以可編輯模式安裝:

git clone https://github.com/OpenFormosa/BlueMagpie-TTS
cd BlueMagpie-TTS
pip install -e .

安裝過程會自動從 GitHub 取得相依的 barbet 套件(負責文字語意的語言模型)。語音合成所需的聲學模組已內含於專案中(位於 bluemagpie/_vendor/,原始碼取自 VoxCPM,採 Apache-2.0 授權),不需另外安裝。

若要儲存合成出來的音檔,建議另外安裝 soundfile

pip install soundfile

載入模型

從 Hugging Face 下載

import os
from huggingface_hub import snapshot_download
from transformers import PreTrainedTokenizerFast
from bluemagpie import BlueMagpieModel

model_dir = snapshot_download("OpenFormosa/BlueMagpie-TTS", token=True)
# 直接從 tokenizer.json 載入 tokenizer,相容較新版 transformers(5.x)
tokenizer = PreTrainedTokenizerFast(tokenizer_file=os.path.join(model_dir, "tokenizer.json"))
model = BlueMagpieModel.from_local(model_dir, tokenizer=tokenizer, training=False, device="cuda")

從本機目錄載入

如果你已經有一份模型檔案,直接指向該目錄即可:

import os
from transformers import PreTrainedTokenizerFast
from bluemagpie import BlueMagpieModel

model_dir = "checkpoints/bluemagpie"
tokenizer = PreTrainedTokenizerFast(tokenizer_file=os.path.join(model_dir, "tokenizer.json"))
model = BlueMagpieModel.from_local(model_dir, tokenizer=tokenizer, training=False, device="cuda")
  • device 可填 "cuda""cpu",不指定時會自動選擇。
  • 推論時請固定使用 training=False

基本使用:文字轉語音

generate 會回傳一段語音波形(torch.Tensor),搭配 soundfile 即可存成 .wav。輸出的取樣率可由 model.sample_rate 取得:

import soundfile as sf

audio = model.generate(
    target_text="今天天氣真好。",
    cfg_value=2.0,
)

sf.write("output.wav", audio.squeeze().cpu().numpy(), model.sample_rate)

聲音複製:模仿參考語者的音色

有兩種做法。

A. 語者向量(speaker_centroid —— 從參考音檔抽出語者向量再合成(免逐字稿):

pip install -e ".[clone]"   # 抽取需要 speechbrain(ECAPA-TDNN)
python scripts/extract_speaker_centroid.py --audio reference.wav --out my_voice.pt
# 多段同一語者更穩定:--audio a.wav b.wav c.wav
import torch

centroid = torch.load("my_voice.pt", weights_only=True)   # [192] 語者向量
audio = model.generate(
    target_text="今天天氣真好。",
    speaker_centroid=centroid,
    cfg_value=2.8,
)

# 也可以在程式中直接抽取(不寫檔):
from bluemagpie import extract_speaker_centroid
centroid = extract_speaker_centroid("reference.wav")      # [192]

B. 參考音檔(reference_wav_path —— 直接提供一段參考音檔:

audio = model.generate(
    target_text="今天天氣真好。",
    reference_wav_path="reference.wav",
    cfg_value=2.8,
)

指定語者:以語者向量控制音色

模型自帶一個多語者向量表 checkpoints/speaker_centroids.pt,目前內含兩個語者:

語者 ID 說明 建議 cfg_value
hung_yi_lee 李宏毅(Hung-yi Lee)老師的語者向量(已取得本人授權;官方最佳參數即針對此語者調校) 2.0–2.8
female_voice 一個通用女聲語者向量 2.0–2.8

向量表的格式為 {"speaker_ids": [...], "centroids": tensor[N, 192], "dim": 192}。以 torch.load 載入後,依語者 ID 取出該語者的 [192] 向量,再透過 speaker_centroid 指定音色:

import os
import torch

table = torch.load(
    os.path.join(model_dir, "checkpoints", "speaker_centroids.pt"),
    map_location="cpu",
    weights_only=True,
)
print(table["speaker_ids"])          # ['hung_yi_lee', 'female_voice']

# 切換語者只要改這一行("hung_yi_lee" 或 "female_voice")
speaker_id = "female_voice"
speaker_centroid = table["centroids"][table["speaker_ids"].index(speaker_id)]   # [192]

audio = model.generate(
    target_text="今天天氣真好。",
    speaker_centroid=speaker_centroid,   # 也可以直接傳入你自己已取得授權的語者向量
    cfg_value=2.0,
)

只用模型 ID(尚未先 snapshot_download 整個模型)時,可單獨抓向量表這一個檔:

from huggingface_hub import hf_hub_download

path = hf_hub_download("OpenFormosa/BlueMagpie-TTS", "checkpoints/speaker_centroids.pt")
table = torch.load(path, map_location="cpu", weights_only=True)

想新增更多語者,用上方〈聲音複製〉的 extract_speaker_centroid 抽出你自己(已取得授權)的 [192] 向量即可,傳法完全相同。早期僅含李宏毅單一語者的 checkpoints/hung_yi_lee_speaker_centroids.pt(格式相同)仍保留可用。

串流輸出

需要邊合成邊播放時,改用 generate_streaming。它是一個產生器,會一段一段地回傳音訊區塊:

chunks = []
for chunk in model.generate_streaming(target_text="今天天氣真好。"):
    chunks.append(chunk)
    # 這裡可以即時播放或寫出 chunk

注意:串流模式下不支援自動重試(retry_badcase)。

四種輸入模式

模型支援四種輸入組合,皆透過同一個 generate 介面切換:

模式 需要的參數 用途
一般合成 target_text 直接把文字唸出來
語音接續 target_textprompt_textprompt_wav_path 從一段已有的語音與其文字接著往下唸
參考音檔 target_textreference_wav_path 模仿參考音檔的語者音色
語者向量 target_textspeaker_centroid 以語者向量複製音色

generate 常用參數

參數 預設值 說明
target_text (必填) 要合成的文字
prompt_text "" 提示文字,搭配 prompt_wav_path 做語音接續
prompt_wav_path "" 提示音檔路徑,用於語音接續
reference_wav_path "" 參考音檔路徑,用於聲音複製
speaker_centroid None 語者向量,用於指定音色
cfg_value 2.0 引導強度,數值越大越貼合條件、但可能較不自然
inference_timesteps 10 取樣步數,越多通常品質越好、速度越慢
min_len / max_len 2 / 2000 輸出長度的下限與上限
retry_badcase False 偵測到異常輸出時自動重試(串流模式不支援)

批次推論引擎(多請求加速)

若你要同時處理多筆合成請求、追求更高吞吐量,可改用內建的批次推論引擎 BlueMagpieEngine。它採用連續批次(continuous batching):多筆請求會一起批次解碼,新請求能在解碼途中加入,彼此互不影響。

引擎的特點:

  • 不需額外相依套件:只用到 torch,不必安裝 vLLM、flash-attn 等套件。
  • 跨裝置:CUDA、Apple Silicon(MPS)、CPU 共用同一套程式碼;CUDA 專屬的最佳化會自動偵測並啟用,其餘裝置自動略過。
  • 與單筆 generate 數值一致:在 batch=1 時,輸出與 model.generate 逐值相同(model.generate 始終是對照基準)。

基本用法

import soundfile as sf
from bluemagpie.serving import BlueMagpieEngine, EngineConfig, Request

# model 與 tokenizer 的載入方式同前(from_local)
engine = BlueMagpieEngine(model, EngineConfig(max_num_seqs=16))

engine.add_request(Request(target_text="今天天氣真好。", seed=0))
engine.add_request(Request(target_text="第二句話。", reference_wav_path="speaker.wav"))

for out in engine.run():            # 依請求加入順序回傳
    # out.audio:48 kHz 波形(已掛載 AudioVAE 時);out.latents:潛在表徵 [T, p, d]
    sf.write(f"output_{out.request_id}.wav", out.audio.numpy(), out.sample_rate)

Request 支援與 generate 相同的四種輸入模式(一般合成、語音接續、參考音檔、語者向量),欄位對應 target_textprompt_textprompt_wav_pathreference_wav_pathspeaker_centroidcfg_valueinference_timesteps 等。每筆請求可給定 seed,使該請求的輸出與同批其他請求的數量、加入順序無關。

串流輸出

engine.stream() 是一個產生器,會在每一步逐筆回傳各請求的區塊:

for chunk in engine.stream():
    # chunk.request_id、chunk.latents、chunk.audio、chunk.finished
    play_or_write(chunk)

一般合成、參考音檔、語者向量這三種模式會回傳串流音訊(chunk.audio);語音接續模式目前只回傳 latents,需要音訊時請改用 run()

設定

EngineConfig 常用參數:

參數 預設值 說明
max_num_seqs 16 同時批次處理的最大請求數
max_model_len 2048 每筆序列的最大長度(提示+生成)
inference_timesteps 9 取樣步數
cfg_value 2.8 引導強度
enforce_eager True 維持與單筆 generate 數值一致的路徑
compile False 啟用 torch.compile(僅 CUDA 有效,其餘裝置自動略過)

引擎的設計、取捨與已知限制詳見 src/bluemagpie/serving/DESIGN.md

加速原理:為什麼不是直接套 vLLM?

很多人期待「用 vLLM 之類的框架就能加速」,但對 BlueMagpie 來說,直接套 vLLM 並不可行,原因有二:

  1. 真正的運算瓶頸不在語言模型,而在擴散式解碼器。 每生成一個音訊單元,DiT(擴散式解碼器 LocDiT/CFM)要被呼叫約 16–18 次(取樣步數 × 無條件/有條件兩路),而語言模型(Barbet、RALM)各只跑一次。vLLM 是文字語言模型的推論框架,它根本不處理擴散式解碼器——就算把語言模型搬到 vLLM,主要運算量仍是 eager 執行,端到端不會明顯變快。
  2. vLLM 不支援 Barbet 的混合架構。 BlueMagpie 的語意語言模型 Barbet 是 Mamba2 與注意力的混合模型,vLLM(以及 nano-vllm、vllm-omni)對這種混合 TSLM 是零支援,得自行實作一個 first-class 混合模型才跑得起來,工程量大且僅限 CUDA。

因此本引擎改採借用 vLLM 的架構技術、但不依賴它的 CUDA 套件的做法:

  • 連續批次處理多請求(吞吐量的主要來源),跨請求共用批次運算。
  • padded KV cache + SDPA + 遮罩取代 vLLM 的 PagedAttention/FlashAttention,換取跨裝置、零依賴(代價是單一運算略慢、記憶體較不精省)。
  • Barbet 的 Mamba 狀態以純 PyTorch 單步遞迴處理,不需融合 kernel。
  • 可選的 compile=True 透過 torch.compile(內部即 CUDA graphs)加速 DiT 與 LocEnc——也就是真正的熱點,而這正是直接套 vLLM 不會幫你做的部分。

一句話總結:我們不追求單一運算比 vLLM 快,而是用 vLLM 級的批次調度搭配針對 DiT 瓶頸的最佳化,在零額外依賴、跨裝置的前提下提升整體吞吐量。

Apple Silicon MLX 加速(選用)

在 Apple Silicon(M 系列)上,可改用 MLX 原生路徑,直接在 Apple GPU(Metal、統一記憶體)上推論,通常比 PyTorch 的 MPS 後端更快。這是選用功能,核心仍維持 torch-only:

pip install -e .[mlx]
from bluemagpie import BlueMagpieModel
from bluemagpie.mlx import BlueMagpieMLX, mlx_generate

model = BlueMagpieModel.from_local(model_dir, tokenizer=tokenizer, device="cpu")
mlx_model = BlueMagpieMLX(model)          # 轉換權重(只需一次)

import soundfile as sf
audio = mlx_generate(model, mlx_model, "今天天氣真好。", seed=0)   # 48 kHz 波形
sf.write("output.wav", audio.numpy(), model.sample_rate)
  • 整條推論路徑(Barbet、RALM、LocEnc、LocDiT/CFM、AudioVAE 解碼器、AR 迴圈)皆以 MLX 重寫,並逐模組對 PyTorch 做數值 parity 驗證——生成過程可完全不經 PyTorch(僅斷詞與參考音檔編碼仍用 torch)。
  • decode 採用快取式單步(cached step),逐步推進、不重算整個序列。
  • mlx_generate 支援與 generate 相同的四種輸入模式(一般合成、語音接續、參考音檔、語者向量)。
  • 真實 7.75GB 模型上端到端 RTF 0.77(比即時還快)——比 torch-MPS 快約 1.45×、比 torch-CPU 快約 3.27×(fp32,scripts/bench_rtf.py)。設計與限制詳見 src/bluemagpie/mlx/DESIGN.md

注意事項

  • 上面範例都直接從 tokenizer.json 載入 tokenizer 再傳給 from_local,在較新版 transformers(5.x)也能穩定運作;背後原因見〈疑難排解〉。
  • 沒有 GPU 也可以執行:把 device 設為 "cpu" 即可(速度較慢,但短句合成只需數十秒)。輸出為 48 kHz 單聲道。
  • 模型內附的 hung_yi_lee 語者向量已取得本人授權,可直接作為範例使用;指定其他語者或進行聲音複製時,請只使用你已取得授權的參考音檔或語者向量。
  • 請妥善保管語者向量表與合成出來的音檔,未經授權前不要對外散布。

疑難排解

較新版 transformers(5.x)的 tokenizer 載入

上面的範例都直接從 tokenizer.json 載入 tokenizer 再傳給 from_local,因此在 transformers 5.x 也能正常運作,不需額外處理(模型只用到 tokenizer 的 encode)。

若你改用 from_local 的自動載入(不傳入 tokenizer),在 transformers 5.x 可能會失敗 —— 解析 tokenizer_config.json 時出現

TypeError: ..._patch_mistral_regex() got multiple values for keyword argument 'fix_mistral_regex'

或載入看似成功、但呼叫 generate() 時才報 ValueError: No tokenizer attached to BlueMagpieModel。遇到時改回上面範例的明確載入方式即可。

Downloads last month
109
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Space using OpenFormosa/BlueMagpie-TTS 1