この記事で分かること
- NVIDIA ではないグラフィックボード(Radeon)で、Whisper を速く動かす方法
- Windows で whisper.cpp を Vulkan 向けにビルドする手順
- CPU と GPU、Whisper とほかのモデルを、同じ音声で比べた数字
- 店の名前のような固有名詞を合わせるには、手がかりの言葉(prompt)がほぼ必須だったこと
先に結論です。
| 方法 | 1発話あたりの時間 | 全文が合った数(32本中) |
|---|---|---|
| faster-whisper large-v3-turbo(CPU) | 3.8 秒 | 26 |
| whisper.cpp large-v3-turbo(CPU) | 2.9 秒 | 23 |
| ReazonSpeech zipformer(CPU) | 0.05 秒 | 11 |
| whisper.cpp large-v3-turbo(Radeon、Vulkan) | 0.23 秒 | 26 |
なぜやったか
声で話しかける自作のアプリを作っています。スマホで録った声を自宅の PC に送り、PC で文字にして返す、という作りです。
話し終わってから返事が始まるまでの間を短くしたいので、文字にする時間は 1 秒を切りたい、というのが目標でした。発話は 2〜10 秒ほどの短いものです。
もう1つの悩みは、固有名詞でした。「(チェーンの名前)+(地名)+店」のような店の名前を、スマホの音声認識がよく聞き間違えていました。
環境
| OS | Windows 11 |
| CPU | Ryzen 9 9950X(16コア) |
| グラフィックボード | Radeon RX 9070 XT(16GB) |
| メモリー | 64GB |
| whisper.cpp | v1.9.5 |
| モデル | large-v3-turbo(ggml、1.6GB) |
Whisper を GPU で動かす話は、ほとんどが CUDA(NVIDIA)前提です。よく使われる faster-whisper(CTranslate2)も、GPU は CUDA だけです。Radeon では、CPU で動かすことになります。
まず CPU で測った
測り方
- 音声は、VOICEVOX の男の声2種類で作った8つの文です。それぞれに、車の走る音を真似た低い雑音を足したものも用意しました(合わせて 32本、平均 2.6 秒、いちばん長いもので 5.8 秒)。
- 文は、「(キャラクターの名前)、次は(店の名前)に行くからよろしく」「(店の名前)に案内して」「ラジオをはじめて」のような、アプリで実際に言う内容です。
- 正しさは、句読点と空白を取ったうえで、全文が一致した本数で数えました。1文字でも違えば、不正解です。かなり厳しめの数え方です。
- 時間は、モデルを読みこんだあと、最初の1〜2回を捨ててから測りました。
音声は合成の声です。本物の人の声や、本物の車の中の音での正しさは、この数字からは分かりません。モデルどうしを比べる目安として見てください。
結果
| 方法 | 時間 | 静か(16本) | 雑音入り(16本) |
|---|---|---|---|
| faster-whisper small、手がかりあり | 1.1 秒 | 3 | 4 |
| faster-whisper large-v3-turbo、手がかりなし | 3.1 秒 | 5 | 5 |
| faster-whisper large-v3-turbo、手がかりあり | 3.8 秒 | 13 | 13 |
| ReazonSpeech zipformer(sherpa-onnx)、手がかりあり | 0.05 秒 | 6 | 5 |
| whisper.cpp large-v3-turbo(公式の CPU 版)、手がかりあり | 2.9 秒 | 12 | 11 |
分かったことは3つです。
1. large-v3-turbo は正しいが、CPU では 3 秒かかる
Whisper は、短い発話でも 30 秒ぶんの音として計算します。2 秒の発話でも 10 秒の発話でも、ほぼ同じ時間がかかります。16コアの CPU でも、3 秒から縮みませんでした。スレッドの数、ビームの幅、量子化(int8 / float32)を変えても、ほとんど変わりません。
2. 日本語専用の速いモデルは、固有名詞が合わなかった
ReazonSpeech は、発話の長さぶんだけ計算するので、とても速いです。ただ、私の試験では、漢字の地名がカタカナで返ってきました(「○○店」が「○○テン」になる)。手がかりの言葉(hotwords)も、ほとんど効きませんでした。合成の声が苦手だった可能性はあります。
3. 手がかりの言葉がないと、固有名詞はほとんど合わない
同じ large-v3-turbo でも、手がかりなしだと 32本中 10本、ありだと 26本でした。モデルを大きくするより、手がかりを渡すほうが、ずっと効きます。
短く計算させる手
whisper.cpp には、計算する長さを縮める設定(-ac、audio_ctx)があります。1500 が 30 秒ぶんで、448 にすると 9 秒ぶんほどです。
| 計算する長さ | 時間 | 静か | 雑音入り |
|---|---|---|---|
30 秒ぶん(-ac 1500) |
2.9 秒 | 12 | 11 |
9 秒ぶん(-ac 448) |
1.1 秒 | 12 | 8 |
速くはなりますが、雑音入りで正しさが落ちました。1 秒も切れません。
faster-whisper にも chunk_length という引数がありますが、私の環境では、値を変えても時間は変わりませんでした。
Vulkan でビルドする
whisper.cpp は、Vulkan を使って GPU で計算できます。Vulkan は Radeon でも使えます。公式の配布には、Windows 用の Vulkan 版が入っていないので、自分でビルドします。
1. ビルドの道具を入れる
C++ のコンパイラーと CMake が入ります(約 7GB)。
winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --passive --norestart"
2. Vulkan SDK を入れる
winget install --id KhronosGroup.VulkanSDK
C:\VulkanSDK\<版の番号> に入ります。私のときは 1.4.363.0 でした。
3. ソースを取ってくる
git clone --depth 1 --branch v1.9.5 https://github.com/ggml-org/whisper.cpp
4. ビルドする
「x64 Native Tools Command Prompt for VS 2022」を開いて、実行します。ふつうのコマンドプロンプトから vcvars64.bat を呼んでも同じです。
入れたばかりだと、環境変数 VULKAN_SDK がまだ見えていないことがあるので、自分で指定しておくと確実です。
set VULKAN_SDK=C:\VulkanSDK\1.4.363.0
set PATH=%VULKAN_SDK%\Bin;%PATH%
cmake -S whisper.cpp -B build -DGGML_VULKAN=1 -DWHISPER_BUILD_TESTS=OFF
cmake --build build --config Release -j 16 --target whisper-server whisper-cli
16コアで、数分でした。警告はたくさん出ますが、エラーなしで通りました。build\bin\Release に、whisper-server.exe、whisper-cli.exe、ggml-vulkan.dll などができます。
5. モデルを取ってくる
curl.exe -L -o ggml-large-v3-turbo.bin https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
6. GPU で動いているか確かめる
.\build\bin\Release\whisper-cli.exe -m ggml-large-v3-turbo.bin -l ja -f test.wav
立ち上がるときの出力に、次のような行が出ていれば、GPU を使っています。
ggml_vulkan: Found 2 Vulkan devices:
ggml_vulkan: 0 = AMD Radeon RX 9070 XT (AMD proprietary driver) | ...
ggml_vulkan: 1 = AMD Radeon(TM) Graphics (AMD proprietary driver) | ...
whisper_init_with_params_no_state: use gpu = 1
whisper_init_with_params_no_state: gpu_device = 0
whisper_backend_init_gpu: using Vulkan0 backend
CPU に内蔵のグラフィックがあると、デバイスが2つ見えます。私の環境では、何も指定しなくても、0 番(RX 9070 XT)が使われました。内蔵のほうが選ばれると遅いので、ここは見ておくとよいです。
エンコードの時間は、同じ音声で、CPU が 2,550ms、GPU が 330ms でした。
サーバーとして動かす
発話のたびにモデルを読みこむと遅いので、常駐させます。
.\build\bin\Release\whisper-server.exe -m ggml-large-v3-turbo.bin -l ja -t 8 -ac 1500 -bs 5 --port 8178 -nt
音声(16kHz・モノラルの WAV)を送ると、文字が返ります。
curl http://127.0.0.1:8178/inference \
-F file=@test.wav \
-F response_format=json \
-F temperature=0.0 \
-F "prompt=ハードオフ ブックオフ ホビーオフ (ほか、聞き取りたい固有名詞を並べる)"
手がかりの言葉は、リクエストのたびに渡す
ここが、いちばんのはまりどころでした。
whisper-server を起動するときに --prompt を付けても、効きませんでした。リクエストの prompt の欄で、毎回渡す必要があります。
| 手がかりの渡し方(CPU 版、30 秒ぶん) | 合った数(32本中) |
|---|---|
| 渡さない | 13 |
起動するときに --prompt で渡す |
11 |
リクエストのたびに prompt で渡す |
23 |
手がかりは、聞き取りたい固有名詞を空白で区切って並べただけのものです。私のアプリでは、キャラクターの名前、今いるあたりの地名、行き先の候補、よく行く店の名前を、その場で組み立てて渡しています。
GPU 版の結果
| 設定 | 時間(平均) | いちばん遅い1本 | 静か | 雑音入り |
|---|---|---|---|---|
-ac 1500 -bs 5 |
0.23 秒 | 0.69 秒 | 14 | 12 |
-ac 1500 -bs 1 |
0.20 秒 | 1.54 秒 | 12 | 11 |
-ac 750 -bs 5 |
0.16 秒 | 0.65 秒 | 14 | 13 |
- 30 秒ぶんをそのまま計算しても 0.23 秒なので、計算する長さを縮める必要がなくなりました。
- ビームの幅は 5 のままがよさそうです。1 にしても、ほとんど速くならず、正しさが少し落ちました。
-
-ac 750は数字の上ではいちばん良いのですが、1本だけ、同じ言葉をくり返す出力(「オフ オフ オフ…」)が出ました。安全を見て、-ac 1500にしています。
残ったまちがいは、ほとんどが同じ1つの文(聞きなれない地名が入った店の名前)でした。
アプリに組みこんでからの数字
実際にスマホから声を送ったときの、PC の中での計算時間です。こちらは本物の人の声です。
| 発話の長さ | PC の中の時間 |
|---|---|
| 1.5 秒 | 0.17 秒 |
| 3.4 秒 | 0.18 秒 |
| 7.5 秒 | 0.28 秒 |
| 11.6 秒 | 0.34 秒 |
通信を入れても、話し終わってから文字になるまで 0.2〜0.7 秒でした。句読点つきの、そのまま読める文で返ってきます。
はまった所と、気をつける所
-
起動するときの
--promptは効かない: 上に書いた通りです。リクエストのたびに渡します。 - 最初の1〜2回は遅い: 立ち上げた直後は、準備のぶんだけ時間がかかります。測るときは捨て、使うときは、起動のあとに空の音声を1回送っておくとよいです。
- 音のない所から、決まり文句を作ることがある: Whisper は、声の入っていない音から「ご視聴ありがとうございました」のような文を作ることがあります。声が入っているかを先に確かめる(VAD)か、決まり文句を捨てる処理が要ります。
- GPU の取り合い: 同じグラフィックボードでローカルの LLM も動かしていると、重なったときに遅くなります。large-v3-turbo が GPU の上で使うメモリーは、1.6GB ほどでした。
- ビルドの道具は大きい: Build Tools と Vulkan SDK で、8GB ほど使います。
まとめ
- Radeon でも、whisper.cpp を Vulkan でビルドすれば、Whisper を GPU で動かせます。Windows でも、手順は6つで済みました。
- large-v3-turbo が、短い発話1つあたり 0.2 秒ほどで動きます。CPU(3 秒)の 10 倍以上です。
- 固有名詞を合わせたいなら、モデルを選ぶより先に、手がかりの言葉(prompt)を渡すのが効きます。
whisper-serverでは、リクエストのたびに渡します。 - 速いだけのモデルに替える前に、自分の使う言葉で測ってみるのがおすすめです。私は、見込みが2回外れました。