VoxCPM 語音合成 — 繞了五年才有人說,別再把聲音剁成 Token 了
把時間倒回 2023 年初。那時候語音合成圈子最熱的東西叫 VALL-E,微軟丟出來的。它做了一件當時看起來理所當然的事:把一段聲音先壓成一串離散的 token,然後拿語言模型去預測下一個 token,就像 GPT 預測下一個字一樣。聲音被它當成另一種語言來處理。
這個想法太順了。語言模型那幾年正在橫掃一切,誰都想把自己的領域「翻譯」成 token 序列,這樣就能搭上那班車。於是 Bark 這麼做、ChatTTS 這麼做、阿里的 CosyVoice 也這麼做。差別只在 token 怎麼切、切幾層、解碼器長什麼樣。整個領域有志一同地往同一個方向走了好幾年。
VoxCPM 是清華 OpenBMB 團隊做的開源 TTS,最新版叫 VoxCPM2。它最值得停下來看一眼的地方,不是它支援 30 種語言、也不是 48kHz 的輸出,而是它在所有人都覺得理所當然的那一步上,按了暫停鍵:它不做離散化。
先搞懂大家到底在剁什麼
「離散 token 化」聽起來很玄,拆開其實不難。
聲音本身是連續的——空氣壓力隨時間平滑變化的一條曲線。電腦存不下無窮多的點,所以要採樣。但採樣完還是一大堆浮點數,直接餵給語言模型太貴。於是有人想了個招:訓練一個編碼器(像 EnCodec、SoundStream),把這堆連續訊號對應到一張「碼本」裡有限的幾千個格子,每一小段聲音就近似成「第幾號格子」。這串格子編號,就是 audio token。
這一步等於把聲音做了一次 JPEG 壓縮。你把高解析度照片存成 JPEG,檔案小了、好傳了,但放大看會發現邊緣有色塊、漸層有斷階——那些被量化掉的細節,回不來了。聲音也一樣,音色裡最細緻的那些泛音、換氣時的氣聲、情緒帶來的微小顫抖,很容易在「歸到最近的格子」這一步被抹平。
所以這幾年 TTS 聽起來「對,但少了點什麼」的那個「少了點什麼」,很大一部分就是在離散化這關漏掉的。大家不是不知道,是覺得這是搭語言模型便車必須付的過路費。
VoxCPM 的選擇:那一步乾脆別做了
VoxCPM 的做法,用一句話講:文字 → 語言模型生成連續向量 → 擴散模型把細節長回來。中間沒有碼本,沒有把聲音歸格子那一步。
它怎麼敢拿掉?因為它換了一個對細節更有耐心的工具——擴散模型。
這裡借個畫圖的比喻會清楚很多。離散 token 的路線,像是要求模型一筆到位、直接畫出成品,畫錯了也只能將就。擴散模型的路線反過來:先給你一張很糊的草稿,然後一步一步去噪、修細節,模糊的地方慢慢顯影成清晰的圖。VoxCPM 就是讓語言模型先在「模糊的連續空間」裡生成一個粗略表徵,再讓擴散模型一步步把它精修成乾淨的聲波。整條管線從頭到尾都在連續的數值上跑,沒有任何一刻需要把聲音塞進有限的格子裡。
如果你把它的生成流程攤開,會看到五個接力的元件,各管一段粒度:
最前面是 LocEnc,局部編碼器。它把聲音切成一塊塊 patch,用小型 Transformer 抽局部特徵——概念上跟 Vision Transformer 把圖片切成方格再讀的做法是同一套。接著是 TSLM,核心語言模型,backbone 用的是 MiniCPM-4,自回歸地建立「文字」跟「語音表徵」之間的對應。再來 RALM 是個八層的殘差模型,專門撿 TSLM 沒顧到的聲學細節補回去。然後 LocDiT 是基於 Conditional Flow Matching 的擴散 Transformer,負責把粗表徵還原成精細語音。最後 AudioVAE V2 收尾,這個解碼器有個很巧的設計:吃 16kHz 進去、吐 48kHz 出來,等於把超解析度直接內建在最後一關。
你不用記住每個縮寫。重點是這個分工背後的思路——把「決定說什麼」跟「把細節畫漂亮」拆成兩種專長的模型,而不是逼一個語言模型用離散 token 把兩件事一起幹完。
工程上它沒有想像中嬌貴
理論漂亮歸漂亮,能不能在自己機器上跑才是工程師會關心的。這部分我是整理 Notion 筆記裡的安裝紀錄,幾個關鍵的坑值得先講在前面。
官方文件寫著要 NVIDIA CUDA,但筆記裡的實測是 Apple Silicon 的 MPS 也能跑——模型會自動偵測到 MPS、用 bfloat16 載入,只是 torch.compile 那層優化只支援 CUDA 所以會被跳過,速度慢一點但功能正常。M 系列晶片上大約 1 token/s,一句中文要等 40 秒左右。VRAM/統一記憶體抓 8GB 上下。
真正會卡死人的是兩個 macOS 特有的坑。第一個,Homebrew 裝的 Python 現在預設禁止全域 pip install(PEP 668),而且系統 Python 常常是 3.13、3.14 這種太新的版本,VoxCPM 只吃 3.10~3.12。解法是老老實實開一個虛擬環境:
1 | # VoxCPM 只支援 3.10~3.12,太新的版本依賴會裝不起來 |
第二個坑更陰——跑官方的 Gradio Web Demo 時,app.py 不在 pip 套件裡(要自己去 repo 抓),而且第一次啟動會卡在背景下載一個 893MB 的 FunASR 模型,下載完之前 Gradio 根本不會真的起來。在台灣這種頻寬可能要等上好一陣子,看起來像當掉其實是在下載。知道這件事,就不會在那邊狂按 Ctrl+C 了。
純用 Python API 反而最乾淨:
1 | from voxcpm import VoxCPM |
那個 inference_timesteps 很值得玩味——它就是擴散模型「修幾次草稿」的次數。調大,細節更穩、更慢;調小,快但偶爾糊。這個旋鈕本身就是連續表徵路線才給得起的,離散 token 一旦定下來就是定下來了,沒有「再修一輪」這種選項。
它能做的事,跟它說自己做不到的事
VoxCPM2 有個我覺得最像玩具又最實用的功能叫 Voice Design——你不給任何參考音檔,直接用一句話描述想要的聲音,它生給你:
1 | wav = model.generate( |
性別、年齡、語氣、語速都能寫進那串括號描述裡。代價是每次生出來的音色會有點不一樣,官方自己也建議跑個 1~3 次挑最順耳的。另一條路是 Voice Cloning,給一段參考音檔讓它抽音色;如果你連那段音檔的逐字稿也一起給(Ultimate Clone 模式),還原度會明顯更高——因為模型等於拿到了「這個聲音是怎麼把這些字唸出來的」這份對照表,接話接得更無縫。
難得的是這份筆記也老實列了它的短板。30 種語言裡,核心的中英日韓法德表現最好,阿拉伯語、印地語、粵語、羅馬尼亞語的字錯率偏高;列進去的中國方言基本是實驗性質,沒有獨立基準。它純粹是 TTS,不附語音辨識,要 STT 得另外接。還有一條寫得很重的紅線:語音克隆的濫用風險明擺著,官方明文禁止拿去假冒身份、製造假訊息,並建議所有 AI 生成的語音都該明確標示。這條不是法律免責聲明,是這類技術成熟後每個用它的人都得自己先想清楚的事。
真正的故事,比一個 TTS 模型大
繞回開頭那條時間線。VoxCPM 有意思的地方,從來不是「又一個更自然的語音模型」——它有意思,是因為它示範了一件事:當整個領域為了搭某班車而集體接受某個妥協時,那個妥協往往不是物理定律,只是一時的工程便利。
把連續訊號剁成離散 token,是為了讓聲音長得像文字、好餵給語言模型。但聲音本來就不是文字。等到擴散模型這種「對連續數值有耐心」的工具夠成熟了,回頭就會發現當初那道過路費根本不必交。同樣的劇情,在影像生成從像素自回歸走向 latent diffusion 時演過一次,現在輪到語音。
所以下次再看到某個領域所有人都用同一套管線、卡在同一個地方上不去,值得問一句:大家共同接受的那個「沒辦法,只能這樣」的步驟,到底是真的沒辦法,還是只是還沒有人敢把它拔掉試試看。VoxCPM 拔了,聲音沒垮,反而更乾淨。下一個被拔掉的妥協會在哪,才是這條時間線真正還沒寫完的部分。
整理自開發知識庫筆記,內容含個人安裝實測紀錄。技術細節以官方為準。
原文來源:VoxCPM GitHub Repo、技術報告 (ICLR 2026)










