音声認識ソフトウェアのWhisperを高速化したwhisper.cppというプロジェクトがあり、Macで音声認識をするならばこれだ、という噂を見かけたので、試してみることにしました。(READMEにも「Apple Silicon first-class citizen – optimized via ARM NEON, Accelerate framework, Metal and Core ML」とあります。)

この記事の中身は、「whisper.cppのCore ML版をM1 MacBook Proで動かす」というページに書かれていることをM2 MacBook Airでやってみた、というものになります。

使用環境

  • MacBook Air (M2, 16GB)
  • macOS Sonoma 14.4.1

whisper.cppをクローンする

whisper.cppは自前ビルドする必要があるようなので、まずはリポジトリのクローンを作ります。今回は、ホームディレクトリにsrcディレクトリを作成し、そこにクローンしました。どこに作っても問題ないはずです。

% git clone https://github.com/ggerganov/whisper.cpp.git
% cd whisper.cpp

必要なパッケージのインストール

まずは必要なPythonパッケージをインストールするのですが、Python 3.12ではパッケージのインストールに失敗したので、推奨環境であるPython 3.10を使います。Macに標準でインストールされているPythonもバージョンが進んでいる可能性があるので、推奨環境を使うようにした方が良いと思います。インストールし直すのも面倒なので、Pythonの実行環境を整備してくれるMinicondaを使います。楽をするため、Homebrewを使います。

% brew install miniconda
% conda init "$(basename "${SHELL}")"

変更を反映するにはシェルを開き直せ、とあるので、ターミナルを終了させて、再度実行します。そして、Python 3.10環境を作成していきます。

% conda create -n py310-whisper python=3.10 -y

環境の作成が終わった後は、必要なパッケージをインストールしていきます。

% conda activate py310-whisper
% pip install ane_transformers
% pip install openai-whisper
% pip install coremltools

Core MLモデルの生成

Pythonは、この部分で必要になります。逆に言えば、Core MLモデルの生成が終わってしまえば、Pythonは必要ありません。whisper.cpp単体(とモデルデータ)で実行できます。

Core MLモデルを生成していきます。whisper.cppが用意しているスクリプトを使うのですが、その内部でcoremlcというXcodeのコマンドを使っているので、パスを通しておかないと失敗します。コマンドラインでXcodeを使っている場合はパスが通っているはずですが、特に使っていない場合は、明示的に通しておく必要があります。なお、パスを通しておいても、Xcodeをインストールしていなければ、当然ですが、失敗します。AppStoreで入手してください。

base以外にも、mediumやlarge-v3などを使うこともできます。なぜかlargeのデータが用意されていないので(おそらくWhisperでlargeのモデルが更新されているためだと思いますが)、何が使えるのか知りたい場合は手動でダウンロードする場合のページを見れば分かります。

% PATH=$PATH:/Applications/Xcode.app/Contents/Developer/usr/bin
% ./models/generate-coreml-model.sh base

(2024/9/7追記)pipでインストールされるnumpyのバージョンが上がっており、次のようなエラーメッセージが出てpythonスクリプトが動作しなくなっています。

A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.0.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

NumPy 1.xでコンパイルされたモジュールはNumPy 2.0.2で使えないよ、と言われているので、numpyのバージョンを下げると動作するようになります。

% pip uninstall numpy
% pip install numpy==1.26.4

モデルのダウンロード

どこにも明確には書かれていないのですが、ggml形式のモデルをダウンロードしておく必要があります。当たり前ですが、作成したCore MLモデルに対応したものでなければなりません。

% bash ./models/download-ggml-model.sh base

whisper.cppのビルド

実行ファイルをビルドします。オプションを指定する必要があります。

% WHISPER_COREML=1 make -j

音声認識

作成されたmainを使って、音声認識を行います。

% ./main -m models/ggml-base.bin -f ※ファイル名 -l ja

適切なオプションを指定しなければ、結果をファイルに書き込むことができません。

MacBook Airでも、ものすごい速度で音声認識されます。baseモデルの精度はイマイチ。mediumを使うと、かなり精度が上がります。

実行すると、Core MLモデルを読み込んでいる旨のログが出るので、M2のニューラルエンジンが使われているようです。生成したCore MLモデルを削除すれば、きちんと(?)動作しなくなります。

ベンチマーク

各モデルの変換速度や精度は、以下のとおりです。インターネットでサンプルとして公開されていた78.8秒のナレーションをサンプルとして使いました。初めて変換をする場合、モデルの初期化処理が入るため、音声認識が始まるまで時間がかかります。以下の比較は、2回目以降の実行です。

  • large-v3
    • 精度:完璧
    • 変換速度:24.895秒(約3.16倍)
  • medium
    • 精度:8割程度。変な認識はみられるが、内容はだいたい理解できる。
    • 変換速度:13.630秒(約5.78倍)
  • small
    • 精度:8割程度。変な認識はみられるが、内容はだいたい理解できる。
    • 変換速度:6.585秒(約11.96倍)
  • base
    • 精度:5〜6割程度。変な認識が多く、内容はなんとなく理解できる。
    • 変換速度:2.561秒(約30.76倍)

精度を重視するならば、large-v3一択です。見事な精度です。しかし、遅い。1時間の音声データの変換に20分かかることになります。

バランスを考えれば、smallでも十分かな、と思います。だいたいの内容を把握するのであれば、十分な変換の精度だと思います。信頼しすぎることはできませんが。

冷却ファンもないMacBook Airで、これだけの速度で変換ができというのは驚異的です。以前、GPUを使わずにCPUのみでWhisperを使ってみたところ、largeモデルで認識を始めると終わるのがいつになるのか分からないような状態でした。

扱いも簡単なので、使えるところが出てきそうです。

音声データの用意方法

whisper.cppが扱えるのは、16kHzのWAV形式のみです。iPhoneなどの録音データはm4aですし、ボイスレコーダーなどの録音データはmp3などが使われていますので、WAV形式に変換する必要があります。変換にはffmpegを使うのが間違いないでしょう。

% ffmpeg -i data.m4a -acodec pcm_s16le -ar 16000 -f wav data.wav

コーデックはpcm_s16leになります。(詳しく調べると奥深いです。とりあえず、このコーデックで動くと思っておけば十分です。)