WhisperXがM2 Macで遅い? MLX・pyannote・ローカルLLMでAI議事録サービスを検証した
こんにちは、オレンジソフトウェアの藤田です。
今回は、社内検証として、
「録音した音声から話者を自動で分離し、ローカルLLMで日本語の議事録を自動生成する」
というWebサービスを、クラウドの文字起こしAPIや外部LLMをできるだけ使わず、ローカル環境内で完結させられるか検証してみました。
当初はWhisperXによる文字起こしを試しましたが、Apple Silicon Mac上では文字起こし部分が大きなボトルネックになりました。
そこで最終的には、
- 文字起こし:mlx-whisper
- 話者分離:pyannote.audio
- 議事録生成:Ollama上のローカルLLM(Gemma系)
- フロントエンド:React
- バックエンド:Python / FastAPI
という構成で検証しています。
検証機にはApple Silicon搭載Macを使用し、録音・文字起こし・話者分離・議事録生成までを一気通貫で動かすところまで確認しました。
この記事では、実際に開発する中で遭遇した、
「文字起こしが異常に遅い」
「なぜCPUしか使われていないのか」
「Apple GPUを使えないのか」
といった問題について、原因を切り分けながら高速化していった過程を、実測データとあわせて紹介します。
ローカルLLMや音声AIを使ったサービス化を検討している方の参考になれば幸いです。
この記事でわかること
この記事では、主に次の内容を紹介します。
- WhisperXをApple Silicon Macで動かした際に起きた速度問題
- CTranslate2とApple GPUの関係
- mlx-whisperへ切り替えた理由
- MLXによるApple GPU活用と高速化
- pyannote.audioによる話者分離
- PyTorchのMPSを使ったApple GPUでの話者分離
- 文字起こしと話者分離を並行実行する設計
- ローカルLLMによる議事録生成
- Apple SiliconをPoC環境として使うメリット
- 本番運用でCUDA対応NVIDIA GPUを検討する理由
全体構成:ローカル完結型のAI議事録サービス
今回検証したサービスの処理フローは、シンプルにすると次のようになります。
flowchart TD
A["録音・音声アップロード(Webブラウザ)"] --> B["文字起こし:mlx-whisper / MLX"]
A --> C["話者分離:pyannote.audio"]
B --> D["文字起こし結果と話者情報を統合"]
C --> D
D --> E["ローカルLLM:Ollama / Gemma系"]
E --> F["議事録生成"]
F --> G["Web画面で文字起こし・議事録を確認"]
フロントエンドにはReact、バックエンドにはPythonのFastAPIを使用しました。
今回の構成では、音声データや文字起こし結果、議事録生成用のテキストを外部の文字起こしAPIやクラウドLLMへ送信しません。
そのため、
- 社内会議
- 顧客との打ち合わせ
- 商談メモ
- 機密情報を含む会議
- 外部AIサービスへ送信しにくい情報
などを扱うシステムとの相性が良いと考えています。
今回のPoCではログイン機能やユーザー管理などは省略し、
「録音 → 文字起こし → 話者分離 → 議事録生成」
というコア部分の実現性検証に集中しました。
つまずきポイント①:WhisperXの文字起こしが異常に遅い
最初は、素直にWhisperXを使って文字起こしを行いました。
ところが、ここで大きな問題が発生しました。
約52分の会議音声をlarge-v3系モデルで処理したところ、文字起こし完了までに約6時間かかったのです。
CPU使用率を見ると、処理中は複数コアが継続的に使用されていました。
つまり、プログラムが停止しているわけではありません。
計算は確実に進んでいます。
しかし、とにかく遅い。
最初は、
「設定を間違えているのでは?」
「GPUが認識されていないのでは?」
と考えました。
そこで処理内容を順番に調べていきました。
原因はCTranslate2だった
WhisperXの音声認識部分では、構成やバージョンにもよりますが、faster-whisper経由でCTranslate2が利用されます。
このCTranslate2について調べたところ、Apple Silicon MacのGPUを直接利用するMetal/MPS向けの実行経路がありませんでした。
Apple Silicon自体は非常に高性能なGPUを搭載しています。
しかし、
「MacにGPUがある」
ことと、
「使用しているAIライブラリがそのGPUを使える」
ことは別問題です。
今回の構成では、Whisperの音声認識処理がApple GPUではなくCPU側で実行されていました。
これが大きなボトルネックになっていました。
int8にしても根本的には解決しなかった
次に確認したのが計算精度の設定です。
CTranslate2では、環境に応じてfloat32やfloat16、int8などの計算形式を利用できます。
今回のCPU実行では、すでに比較的軽量なint8を使用していました。
もちろん、
- 使用するWhisperモデルを小さくする
- beam sizeを調整する
- CPUスレッド数を調整する
- VADの設定を見直す
- バッチ処理を調整する
といった高速化方法はあります。
しかし、それらは基本的に、
「CPUで動いているWhisperをどう高速化するか」
という話です。
今回の目的は、M2 Maxに搭載されているApple GPUを活用して大幅に高速化することでした。
そこで、CTranslate2の設定調整を続けるのではなく、推論エンジン自体を変更することにしました。
解決策:AppleのMLXでWhisperを動かす
そこで試したのが、Appleが開発している機械学習フレームワーク「MLX」です。
MLXはApple Silicon向けに設計された機械学習フレームワークで、Apple GPUを利用した高速な推論が可能です。
Whisperについても、MLX上で動作する「mlx-whisper」があります。
そこで文字起こし部分については、WhisperXのCTranslate2ベースの処理からmlx-whisperへ切り替えてみました。
結果は大きく変わりました。
実測:35秒の音声が6分30秒 → 約6秒
同じテスト音声を使用して比較したところ、今回の検証環境では次の結果になりました。
| 実行方式 | 音声 | 処理時間 |
|---|---|---|
| WhisperX / CTranslate2 / CPU | 約35秒 | 約6分30秒 |
| mlx-whisper / MLX / Apple GPU | 約35秒 | 約6秒 |
約35秒の音声に対して、
CPUでは約390秒。
MLXでは約6秒。
今回の検証条件では、単純計算で60倍以上の速度差になりました。
これは非常に大きな違いです。
モデルを少し軽量化したり、設定値を細かく変更したりするだけでは得られないレベルの高速化でした。
「WhisperXが遅い」のではなく、実行環境との相性の問題
ここは重要なポイントです。
この結果だけを見ると、
「WhisperXは遅い」
と思ってしまうかもしれません。
しかし、そういう意味ではありません。
今回の問題は、
「WhisperXの音声認識部分で利用しているCTranslate2とApple Silicon GPUの組み合わせ」
にありました。
NVIDIA CUDA環境であれば、CTranslate2はGPUを利用できます。
つまり、
- NVIDIA GPUならWhisperX / faster-whisper / CTranslate2
- Apple SiliconならMLX系実装
というように、ハードウェアに合わせて推論エンジンを選ぶことが非常に重要だと感じました。
MLX版の文字起こし精度について
速度だけではなく、文字起こし結果についても確認しました。
今回使用したテスト音声では、mlx-whisperへ変更しても大きな精度低下は感じませんでした。
むしろ一部の発話については、CPU側で実行していた環境よりも誤変換が少ない結果もありました。
ただし、これは、
「MLX版Whisperの方が常に精度が高い」
という意味ではありません。
Whisperの出力結果は、
- モデル
- デコード設定
- 音声品質
- 話者
- ノイズ
- 言語
- 実装
- ライブラリバージョン
などによって変化します。
今回の結果としては、
「高速化しても、実用上問題になるような精度低下は確認できなかった」
という評価にしています。
つまずきポイント②:今度は話者分離が遅く感じる
文字起こしを約6秒まで高速化すると、今度は別の問題が目立つようになりました。
話者分離です。
今回、話者分離にはpyannote.audioを使用しています。
短い音声をテストしたところ、文字起こしは数秒で終わるのに、話者分離には約20秒かかるケースがありました。
つまり、それまで文字起こしに隠れていた話者分離処理が、新しいボトルネックとして見えてきたわけです。
pyannote.audioをApple GPUで動かしてみる
pyannote.audioはPyTorchをベースにしています。
PyTorchにはApple Silicon GPU向けの「MPS」というバックエンドがあります。
MPSはMetal Performance Shadersの略で、Apple GPU上でPyTorchの演算を実行する仕組みです。
そこで、話者分離処理をCPUからMPSへ変更して比較してみました。
結果は次の通りです。
| 実行デバイス | 話者分離時間 |
|---|---|
| CPU | 約19.1秒 |
| MPS / Apple GPU | 約8.0秒 |
今回の検証では、CPUと比較して約2.4倍の高速化となりました。
使用したテスト音声では、目立った精度低下や処理エラーも確認されませんでした。
MPSは便利だが、CUDAほど万能ではない
今回pyannote.audioはMPS上で問題なく動作しました。
ただし、MPSについては注意も必要です。
PyTorchのすべての演算が、常にMPSへ完全対応しているとは限りません。
使用するモデルやPyTorchのバージョンによっては、
- MPS未対応の演算が含まれる
- CPUフォールバックが必要になる
- 処理速度が期待ほど上がらない
- 場合によってはエラーになる
といった可能性があります。
今回の環境では問題ありませんでしたが、
「PyTorchならApple GPUで必ず動く」
とは考えない方が良さそうです。
文字起こしと話者分離は並行実行できる
ここでもう一つ大きな改善ポイントがありました。
文字起こしと話者分離は、基本的には互いの処理結果を必要としません。
文字起こしでは、
「何を話しているか」
を解析します。
一方、話者分離では、
「誰がいつ話しているか」
を音声から解析します。
つまり、
flowchart LR
A["音声"] --> B["文字起こし:何を話しているか"]
A --> C["話者分離:誰がいつ話しているか"]
という形で、同じ音声から独立して処理できます。
両者の結果が必要になるのは、最後に、
「この発言は話者A」
「この発言は話者B」
という形で統合するときです。
直列処理から並行処理へ
最初は、
flowchart LR
A["文字起こし"] --> B["話者分離"] --> C["統合"]
という直列的な処理を想定していました。
しかし、これでは、
文字起こし時間 + 話者分離時間
がそのまま待ち時間になります。
そこで、
flowchart LR
A["音声"] --> B["文字起こし"]
A --> C["話者分離"]
B --> D["両方の処理完了を待つ"]
C --> D
D --> E["結果を統合"]
という形で、両処理を並行して実行する構成に変更しました。
実装上は、それぞれの推論処理を独立したジョブとして動かし、両方の処理が終了した段階で結果を統合しています。
理想的には、
「文字起こし時間+話者分離時間」
ではなく、
「どちらか長い方の処理時間」
に近い時間で処理を完了できます。
Apple SiliconではCPUとGPUの使い分けも重要
Apple Siliconはユニファイドメモリアーキテクチャを採用しており、CPUとGPUが同じメモリ空間を共有しています。
そのため、一般的なCPU+NVIDIA GPU構成とは少し仕組みが異なります。
それでも、
- mlx-whisper:Apple GPU
- pyannote.audio:CPU
というように異なる演算リソースへ処理を分散すると、効率よく並行実行できる場合があります。
一方で、
- mlx-whisper:GPU
- pyannote.audio:MPS / GPU
として両方を同時にGPUへ載せた場合、GPU側でリソース競合が発生する可能性があります。
そのため、
「すべてGPUに載せれば最速」
とは限りません。
実際のサービスでは、
- GPU使用率
- CPU使用率
- メモリ使用量
- 音声時間
- 同時実行数
などを確認しながら、どの処理をどのデバイスへ割り当てるか調整する必要があります。
ローカルLLMによる議事録生成は比較的スムーズだった
文字起こしと話者分離ではかなり苦労しましたが、議事録生成については比較的スムーズに動きました。
今回、議事録生成にはOllama上で動作するGemma系のローカルLLMを使用しています。
文字起こし結果と話者情報を次のような形式へ整理し、
話者A:
本日の議題について説明します。
話者B:
まず前回の進捗について確認したいです。
話者A:
前回から変更になった点は3点あります。
これをローカルLLMへ渡します。
LLMには、
- 会議概要
- 決定事項
- 発言内容
- 課題
- TODO
- 担当者
- 次回確認事項
などを整理させます。
OllamaはApple Silicon上でGPUアクセラレーションを利用できるため、今回使用したモデルでは議事録生成速度について大きな問題はありませんでした。
同じ「ローカルAI」でもGPU対応状況は全く違う
今回の検証で特に感じたのが、
「ローカルで動くAIだからといって、同じようにGPUが使えるわけではない」
ということです。
今回だけでも、
| 処理 | 使用技術 | Apple GPU |
|---|---|---|
| WhisperX ASR | CTranslate2 | 基本的に使用できない |
| mlx-whisper | MLX | 使用可能 |
| pyannote.audio | PyTorch | MPS経由で使用可能 |
| Ollama | ローカルLLMランタイム | Apple Silicon GPUを利用可能 |
という違いがあります。
アプリ側から見ると、すべて「AI処理」です。
しかし内部で利用している、
- 推論エンジン
- フレームワーク
- GPUバックエンド
- モデル形式
によって、実際の動作は大きく異なります。
ローカルAIシステムを設計するときは、
「GPUがあるから速いはず」
ではなく、
「このライブラリは、このGPUを本当に使えるのか」
まで確認する必要があります。
Apple Silicon MacはPoC環境としてかなり優秀
今回の検証ではApple Silicon Mac 1台で、
- 音声アップロード
- Whisper文字起こし
- 話者分離
- 話者ラベル統合
- ローカルLLMによる議事録生成
- Web画面での結果表示
まで実現できました。
PoCや社内検証環境としては、Apple Siliconは非常に扱いやすいと感じました。
特にMLXの存在は大きく、Apple GPUを活用することで、CPU処理では現実的ではなかった処理を大幅に高速化できました。
では、本番サーバーもMacでいいのか?
ここからはサービス化の話です。
1人が自分のMacで使うだけであれば、Apple Siliconでも十分実用的です。
しかし、
- 社内の複数人が使う
- 複数拠点から利用する
- 複数の会議を同時アップロードする
- 数時間の録音ファイルを大量処理する
- Webサービスとして提供する
となると話が変わってきます。
今回の検証を通じて、本番環境についてはCUDA対応NVIDIA GPUを使ったLinuxサーバー構成の方が運用しやすいと考えています。
本番運用でCUDA GPUを勧める理由① WhisperXとの相性
WhisperXの音声認識で一般的に利用されるfaster-whisper / CTranslate2は、NVIDIA CUDA環境でGPUアクセラレーションを利用できます。
CUDA環境では、
- float16
- int8
- バッチ処理
- GPU推論
などを活用できます。
また、Whisper系AIをサーバー運用する際の情報量や実績も比較的多く、本番環境の構成として選択しやすいのがメリットです。
今回Apple Siliconで使用したMLXは非常に高速でしたが、基本的にはApple Silicon向けです。
Linux+NVIDIA GPUサーバーへそのまま移行する仕組みではありません。
そのため、PoCと本番環境で推論エンジンを切り替えられる設計にしておくことも重要です。
本番運用でCUDA GPUを勧める理由② MPSよりCUDAの方が選択肢が多い
pyannote.audioについては、今回MPSで問題なく高速化できました。
しかし、PyTorchを使ったAIモデル全体を見ると、CUDAの方が対応範囲や実績が広い傾向があります。
Apple SiliconでAI開発をしていると、
「この処理はMPSで動く」
「この処理はCPUでしか動かない」
「このモデルではエラーになる」
といったケースに遭遇することがあります。
CUDA環境では、多くのAIライブラリが最初からNVIDIA GPUを想定して開発・検証されています。
そのため、本番サービスではCUDA環境の方がトラブルシュートしやすいケースが多いと考えています。
本番運用でCUDA GPUを勧める理由③ 同時処理とスケール
今回のPoCでは、基本的に1件ずつ音声を処理するジョブキュー方式にしています。
これは、
「Apple Siliconでは複数ジョブを処理できない」
という意味ではありません。
技術的には複数の音声処理を同時に動かすこともできます。
しかし複数ジョブを同時に実行すると、
- GPU使用率が競合する
- ユニファイドメモリを大量に消費する
- 1件あたりの処理時間が伸びる
- LLM推論ともリソースが競合する
- メモリ不足が起きる
可能性があります。
そのため今回のPoCでは、安定性を優先して、
flowchart TD
A["アップロード"] --> B["ジョブキュー"]
B --> C["先頭のジョブを取得"]
C --> D["音声処理"]
D --> E["完了"]
E --> F{"待機中のジョブがある?"}
F -->|はい| C
F -->|いいえ| G["次のアップロードを待つ"]
という構成にしました。
複数ユーザー対応ではGPUリソース管理が重要になる
サービスとして提供する場合、単純な処理速度だけではなく、
「同時に何人処理できるか」
というスループットが重要になります。
例えば、
flowchart TD
A["ユーザーA:60分の会議音声"] --> D["同時アップロード"]
B["ユーザーB:90分の会議音声"] --> D
C["ユーザーC:30分の会議音声"] --> D
D --> E["処理順序・GPUリソースの割り当てを検討"]
が同時にアップロードされた場合、それぞれをどう処理するか考えなければなりません。
方法としては、
- GPUジョブキュー
- 複数GPU
- ワーカー分離
- GPUサーバーの追加
- クラウドGPU
- Kubernetesなどによるスケール
といった構成が考えられます。
このあたりは、Linux+NVIDIA CUDA環境の方が選択肢を取りやすいと考えています。
PoCはApple Silicon、本番はCUDAという選択肢
今回の検証を通じて感じたのは、
Apple SiliconとNVIDIA CUDAは、どちらか一方が優れているというより用途が違うということです。
Apple Siliconは、
- 開発機
- PoC
- 社内利用
- 小規模運用
- ローカルLLM実験
- MLXを利用した推論
との相性が非常に良いです。
一方、NVIDIA CUDA環境は、
- 本番サーバー
- 大量処理
- 複数ユーザー
- 複数GPU
- AIライブラリとの互換性
- インフラのスケール
といった用途で扱いやすいと考えています。
今回のシステムでも、
flowchart TD
A["PoC:Apple Silicon"] --> B["文字起こし:MLX"]
A --> C["話者分離:MPS / CPU"]
から、
flowchart TD
A["本番構成の候補:Linux"] --> B["NVIDIA GPU / CUDA"]
B --> C["文字起こし:WhisperX系"]
B --> D["話者分離:pyannote.audio"]
へ移行できることを意識して設計しています。
今回の検証で一番重要だったこと
今回、一番大きかったのは、
「遅いからスペック不足」
とすぐに判断しなかったことです。
最初は、
「M2 MaxでもWhisper large-v3はこんなに重いのか?」
とも考えました。
しかし調査してみると、問題はMacのスペックそのものではありませんでした。
実際には、
flowchart TD
A["WhisperX"] --> B["faster-whisper"]
B --> C["CTranslate2"]
C --> D["今回の構成ではApple GPUを使用できない"]
D --> E["CPU推論"]
E --> F["文字起こしがボトルネックに"]
という構造になっていました。
そこで、
flowchart TD
A["mlx-whisper"] --> B["MLX"]
B --> C["Apple GPU"]
C --> D["高速推論"]
へ変更したことで、今回の検証条件では60倍以上の差が出ました。
AIシステムでは、
「どのモデルを使うか」
だけではなく、
「どの推論エンジンで動かすか」
も非常に重要だと改めて実感しました。
まとめ
今回、Whisper・pyannote.audio・ローカルLLMを組み合わせて、完全ローカル型のAI議事録サービスを検証しました。
Apple Silicon Mac上でも、構成を工夫することで十分実用的な速度まで持っていくことができました。
特に大きかったポイントは、
- WhisperX / CTranslate2ではApple GPUを直接利用できず、CPU処理がボトルネックになった
- mlx-whisperへ変更することでApple GPUを活用できた
- 今回の検証では、約35秒の音声が約6分30秒から約6秒まで高速化した
- pyannote.audioもMPSを利用することで約2.4倍高速化した
- 文字起こしと話者分離は独立しているため、並行実行できる
- GPUだけでなくCPUとの処理分担も重要
- OllamaによるローカルLLM議事録生成もApple Silicon上で実用的に動作した
- PoCにはApple Silicon、本番の複数ユーザー環境ではCUDA GPUが有力
という点です。
ローカルAIを扱っていると、
「GPUを搭載しているのに遅い」
というケースがあります。
そのときはハードウェアスペックだけを見るのではなく、
- どの処理が遅いのか
- CPUなのかGPUなのか
- どのライブラリが処理しているのか
- そのライブラリは使用しているGPUへ対応しているのか
- 推論エンジンを変更できないか
というところまで確認することが重要です。
今回のように、推論エンジンを変えるだけで大きく性能が変わるケースもあります。
ローカルLLM・オンプレミスAIのシステム開発について
オレンジソフトウェアでは、ローカルLLMやオンプレミスAIを活用したシステムについて、検証段階からシステム構築まで対応しています。
例えば、
- 社内専用AIチャット
- 社内文書を検索できるRAG
- ローカルLLM
- AI議事録
- 音声文字起こし
- 話者分離
- 社内データと連携するAI
- 外部へデータを送信しないAIシステム
などの構築についても検証しています。
「生成AIを使いたいが、社内データを外部サービスへ送りたくない」
「クラウドAIの利用料金を抑えたい」
「自社専用のAI環境を構築したい」
といった場合には、ローカルLLMやオンプレミスAIという選択肢もあります。
ご興味がありましたら、お気軽にお問い合わせください。
最後までお読みいただき、ありがとうございました。
オレンジソフトウェアの藤田でした。
検証結果・技術情報についての注意事項
本記事に記載している処理時間、速度比較、精度に関する評価などは、オレンジソフトウェアが独自に実施した検証環境における結果です。
実際の性能は、
- 使用するハードウェア
- OS
- PythonやPyTorchなどの実行環境
- Whisper / WhisperX / mlx-whisper / pyannote.audioなどのバージョン
- 使用するモデル
- モデルの量子化方式
- 音声の長さや品質
- 話者数
- ノイズ
- バッチサイズ
- その他の設定
などによって大きく異なる可能性があります。
特に、本記事内の「約60倍」「約2.4倍」といった速度差は、今回使用した検証環境とテストデータにおける実測結果であり、すべての環境で同様の性能向上を保証するものではありません。
また、MLX、WhisperX、CTranslate2、PyTorch、pyannote.audio、Ollamaなどのソフトウェアは継続的に開発されており、GPU対応状況や仕様、推奨構成については今後変更される可能性があります。
本記事は執筆時点での当社独自検証に基づく技術情報としてご覧ください。
