AI 工具 15 min read

whisper.cpp 與 WhisperX 不是二選一:M2 實測後我兩個都留著

兩套本機語音轉文字工具,我在同一台 M2 MacBook(8GB)上都裝過都跑過:whisper.cpp 贏在形態,clone 加兩行 cmake、零個坑;WhisperX 贏在設計,用 wav2vec2 強制對齊把時間戳磨到字級還附信心分數。裝 WhisperX 我踩了三個坑——結論是先裝 whisper.cpp,真需要字級時間戳再加 WhisperX,兩個不衝突。

whisper.cpp 與 WhisperX 不是二選一:M2 實測後我兩個都留著
本文目錄 · 11
TL;DR
>
我在同一台 M2 MacBook(8GB)上把 whisper.cpp 和 WhisperX 都裝過、都跑過,結論是這兩個不在同一層,沒有「該選哪個」這種問題。
whisper.cpp 贏在形態:clone、cmake 兩行、下載一個 .bin,我從頭到尾沒踩到坑。WhisperX 贏在設計:它把「時間戳」從生成模型的順手猜測,改成一道有解的對齊問題。
我的順序是先裝 whisper.cpp;只有當你真的需要字級時間戳或語者分離時,才值得再扛 WhisperX 那套依賴。

📌 目錄

兩個工具各自在解什麼問題

whisper.cpp 是 Georgi Gerganov 的 ggml 系列專案之一,把 OpenAI 的 Whisper 模型用純 C/C++ 重寫一次,MIT 授權。它要解的問題是「讓 Whisper 在一般人的機器上跑起來」:不用 Python、不用 PyTorch,build 完就是一支執行檔加一個模型檔。

WhisperX 是 Max Bain 的研究專案,BSD-2-Clause,論文發表在 INTERSPEECH 2023。它要解的是另一個問題:Whisper 給你的時間戳不夠準也不夠細,只有句子級,而且會漂。WhisperX 在轉錄前後各接一段處理——前面用 VAD 切掉靜音,後面用 wav2vec2 音素模型做強制對齊,把時間戳磨到每一個字。轉錄本身它不自己做,是呼叫 faster-whisper。

看清楚這句話會省下很多糾結:WhisperX 的核心價值不是轉錄,是轉錄之後那一步。 它跟 whisper.cpp 不是同一個位置上的兩個選項。

我這兩個工具各自寫過一篇實測:whisper.cpp 本機語音轉文字WhisperX 字級時間戳與語者分離。這篇是把兩次實測擺在一起,回答「所以我該裝哪個」。

我只用兩個維度比

我沒有用功能對照表來做這個決定。因為 whisper.cpp 在功能表上缺的那些欄位,多數是它刻意不做的——把「缺勾」當成「比較差」,會誤讀它的設計取向。

我實際做決定時只看兩件事:

  • 形態成本——把它裝起來、跑起來,我要付出什麼?失敗的機率有多高?

  • 設計能力——它在技術上做對了什麼別人沒做的事?
  • 這兩個維度是正交的。一個工具可以在形態上極簡而在設計上保守,反之亦然。這兩個工具剛好各佔一邊,所以它們的比較才有意義。

    維度一:形態成本,以及我踩到的三個坑

    whisper.cpp 的安裝在我這台是這樣:

    git clone https://github.com/ggml-org/whisper.cpp.git
    cd whisper.cpp
    cmake -B build -DCMAKE_BUILD_TYPE=Release
    cmake --build build -j --config Release
    bash ./models/download-ggml-model.sh large-v3-turbo

    沒有第六步。macOS 上不用額外裝任何東西,Metal 支援預設開啟。跑完之後你手上有一支執行檔 build/bin/whisper-cli 和一個 .bin 模型檔,把這兩個東西複製到另一台 Mac 一樣能跑。

    我從 clone 到轉出第一段中文,一個坑都沒踩到

    WhisperX 這邊,我裝在一個獨立的 venv 裡(whisperx 3.8.6torch 2.8.0faster_whisper 1.2.1),過程踩到三個東西:

    遇到的狀況影響解法
    torchcodec 載不起來,噴 libavutil.59.dylib 找不到沒有影響,轉錄照跑照出想清掉就 brew install ffmpeg
    NLTK 的 punkt_tab 沒附,對齊那步需要真的擋住:跑完五分鐘輸出目錄是空的python -c "import nltk; nltk.download('punkt_tab')"
    /tmp 底下執行被擋,Blocked import of regex from current working directory直接跑不起來換到自己家目錄跑,或加 PYTHONSAFEPATH=1
    第二個最惡劣:它不報錯、不中斷,就是安靜地跑完然後什麼都不寫。我是 ls 輸出目錄才發現是空的。

    這就是形態成本的差距。whisper.cpp 的失敗模式很少,因為它的依賴幾乎只有一個 C++ 編譯器;WhisperX 站在 PyTorch、faster-whisper、pyannote、NLTK 這一整疊之上,每一層都有自己的裝法和自己的坑。三個坑各自都有解,也都不難解,但你得先知道要去解。

    這一項 whisper.cpp 大勝,而且不是小勝。 如果我要教別人裝一套本機語音轉文字,我只會教 whisper.cpp——不是因為它比較好,是因為對方照著做幾乎不會失敗。

    維度二:時間戳是怎麼來的

    翻過來看設計,WhisperX 有一件事做得很漂亮。

    Whisper 的時間戳是它在生成逐字稿的同時「順便」預測出來的。這是一個生成任務:模型一邊猜下一個 token,一邊猜這個 token 大概在第幾秒。既然是猜,就會漂,而且沒有明確的訊號告訴你哪裡漂了。

    WhisperX 換了一個問法。它先把逐字稿拿到手,然後另外載入一個 wav2vec2 音素辨識模型,做強制對齊:在「文字內容已經確定」的前提下,問題變成「把這串已知的字,排進時間軸上最合理的位置」。這已經不是生成問題,是一個有標準解法的動態規劃問題。

    差別在於,這個問法會順便產出一個副產品:對齊的信心分數。這是我實測 JSON 裡的一段:

    {"word": "我", "start": 0.993, "end": 1.193, "score": 0.984}
    {"word": "是", "start": 1.193, "end": 1.393, "score": 0.903}
    {"word": "陳", "start": 1.393, "end": 1.534, "score": 0.969}
    {"word": "彥", "start": 1.534, "end": 1.594, "score": 0.668}

    「彥」那個字 score 是 0.668,鄰居都是 0.9 以上。而那個位置剛好就是轉錄把我名字聽成同音字的地方——對齊不上,分數就掉下來了。

    我沒有教它去偵測轉錄錯誤,這是「換一種問法」自然掉出來的東西。你可以直接拿 score 當篩選條件,把低分的位置抽出來人工複查。做語料清理、做字幕校對,這一欄很值錢。

    whisper.cpp 在這個維度上是保守的:它就是把 Whisper 原本的行為忠實地跑出來,包含 Whisper 原本的時間戳品質。它沒有想解這個問題。

    速度數字與它的可比性

    先講一件必須誠實說的事:這兩組數字不能直接對比。 我兩篇實測用的不是同一段音檔(whisper.cpp 那次是用 macOS 的 say 合成的 17.6 秒旁白,WhisperX 那次是我自己錄的 17.66 秒語音),模型也不同,一個走 Metal 一個純 CPU。

    whisper.cpp 與 WhisperX 在同一台 M2 MacBook、8GB 記憶體上的實測結果並列對照,涵蓋安裝坑數、依賴、產物、耗時、中文正確性、時間戳粒度與信心分數

    所以下面這張表只能當「各自的量級」看,不是賽跑成績:

    工具與設定音檔耗時相對即時
    whisper.cpp base(多語,BLAS)17.6 秒中文2.54 秒約 6.9 倍
    whisper.cpp large-v3-turbo(Metal)17.6 秒中文11.94 秒約 1.5 倍
    WhisperX base + 對齊(純 CPU)17.66 秒中文35.11 秒約 2.0 倍(比音檔慢)
    WhisperX base + --no_align(純 CPU)17.66 秒中文25.71 秒約 1.5 倍(比音檔慢)
    耗時都不含模型載入。要注意最後兩列的「相對即時」跟前兩列方向相反:whisper.cpp 是比音檔短(快過即時),WhisperX 是比音檔長

    從這張表能安全推出來的結論只有兩個:

    • 兩者在這台 8GB 的 M2 上都是可用的量級,一小時的錄音都在幾十分鐘內能處理完。
    • WhisperX 的對齊那一步在我這台大約多花 9 秒(35.11 減 25.71),這是換到 86 個字全部帶時間戳的價格。
    如果你要的是「哪個轉得快」,這張表回答不了,得用同一段音檔同一個後端重測。但我認為那個問題本身不太重要——兩者都快過或接近即時,真正的差別在前面那兩個維度。

    選擇順序

    我的建議不是二選一,是先後:

    先裝 whisper.cpp。 理由是它的成本近乎為零,而且對大多數需求它就是答案。把會議錄音轉成文字、把 podcast 轉逐字稿、把訪談整理成筆記——這些只要句子級時間戳,甚至只要純文字。whisper.cpp 用 large-v3-turbo 在我這台中文全對,還快過即時。

    確定需要下面這些,才裝 WhisperX:

    • 要做字級字幕(卡拉 OK 式逐字上色、短影音逐字跳動字幕)
    • 語者分離,需要知道每句話是誰講的
    • 要做語料品質篩選,想用 score 自動標出可疑位置
    • 要在逐字稿上做精確剪輯,需要知道某個詞的秒數
    如果你的需求不在上面,WhisperX 的那疊依賴就是純成本。它換來的能力很實在,但那個能力你用不到的時候,價值是零。

    反過來說,如果你確實需要字級時間戳,那三個安裝坑就完全值得——因為沒有第二個工具會用同樣乾淨的方式給你 score 這一欄。

    順帶一提,我兩個都留在機器上,沒有卸載任何一個。它們吃的空間不衝突,用途也不重疊。

    什麼情況我不會用這兩個

    誠實講邊界:

    • 要即時串流轉錄(一邊講一邊出字)。這兩個都是為離線批次設計的。whisper.cpp 有 stream 範例,但那是滑動視窗的近似做法,不是真正的串流架構。
    • 音檔量大到需要 GPU 農場。WhisperX 的 README 寫的「70x realtime with large-v2」是 CUDA 環境的數字,跟 Mac 沒有關係;真要大量處理,該考慮的是租 GPU 而不是在筆電上排隊。
    • 需要商用等級的中文標點與段落切分。兩者輸出的中文標點都偏機械,WhisperX 的中文對齊還是字元級不是詞級,正式字幕仍然要自己拿 words 陣列重新分組。
    • 語者分離要開箱即用。WhisperX 的 diarization 預設模型是 HuggingFace 上的 gated model,要先去接受條款、掛個人 access token。這一段我自己沒有實測過(我的測試音檔只有我一個人講話),上面的描述是我讀 whisperx/diarize.py 和 README 得到的,不是我跑出來的結果。

    FAQ

    whisper.cpp 跟 WhisperX 該選哪一個?

    多數情況先選 whisper.cpp,因為安裝成本近乎為零而且對一般轉錄需求足夠。只有當你需要字級時間戳、語者分離或對齊信心分數時,才需要再裝 WhisperX。這兩個不是互斥選項,可以同時裝。

    WhisperX 為什麼比 whisper.cpp 慢?

    因為它做的事情比較多。WhisperX 除了轉錄,還跑了 VAD 前處理和 wav2vec2 強制對齊。我實測對齊那一步在 M2 純 CPU 上大約多花 9 秒(17.66 秒的音檔)。另外我的 WhisperX 測試是純 CPU,whisper.cpp 大模型走的是 Metal GPU,這兩組數字用的不是同一段音檔也不是同一個後端,不能直接對比。

    字級時間戳一定要用 WhisperX 嗎?

    whisper.cpp 有 -ml 之類的參數可以控制輸出粒度,但那是把句子切短,時間戳的來源仍然是 Whisper 自己預測的。WhisperX 的字級時間戳是另外用 wav2vec2 音素模型對齊算出來的,而且附帶信心分數,來源和品質是兩回事。

    兩個都裝會不會衝突?

    不會。whisper.cpp 是一支獨立執行檔加模型檔,WhisperX 是 Python 套件,我把它裝在獨立的 venv 裡。兩者各自的模型權重也是分開下載、分開快取的。

    8GB 記憶體的 Mac 跑得動嗎?

    我這台就是 8GB 的 M2。whisper.cpp 載入 1.5GB 的 large-v3-turbo 全程沒有 swap 壓力,運算緩衝區加起來不到 200MB。WhisperX 用 base 模型加 int8 量化也跑得動,但它同時要載轉錄模型和對齊模型,記憶體壓力比 whisper.cpp 明顯大。

    小結

    whisper.cpp 和 WhisperX 放在一起比,會發現它們在不同的維度上各自做到很好:一個把安裝成本壓到幾乎不存在,一個把時間戳從猜測改成可解的對齊問題。這兩件事沒有互相取代的關係。

    我在同一台 M2 MacBook 上實測的結果是:whisper.cpp 從 clone 到轉出中文零個坑,large-v3-turbo 中文全對且快過即時;WhisperX 踩了三個安裝坑,但 86 個字全部拿到 startendscore,而且低分的位置準確指向轉錯的那個字。

    所以順序是先 whisper.cpp,需要字級時間戳再加 WhisperX。兩個都留著不衝突。

    延伸資源

    author
    陳彥彤

    AI 工程師 · AI 顧問。Java 後端 8 年、AI 工程師 2 年。AI 內訓 · AI 導入顧問 · 前後端與雲端培訓。

    support

    覺得文章有用可以到 GitHub 給個 star,或是透過信箱聊聊 AI 內訓、AI 導入顧問或前後端 / 雲端培訓。