wav2vec2をC++だけで動かす「wav2vec2.cpp」とは
この回で扱うのは、HuggingFaceのブログで紹介されていた、wav2vec2をPythonなしでC++だけで動かせるようにしたという話題です。
C++だけで動かすと聞くと、LLM界隈のllama.cppやwhisper.cppを触ったことがある人には感覚がつかみやすい、と戸田さんは説明します。
しかもこのwav2vec2.cppは多言語対応で日本語モデルもあったため、今回はそれを試すことにしたと話されています。
検証データには、FLEURSという多言語音声データセットの日本語テストデータのうち、先頭30サンプルを使ったとのことです。
入り口でつまずいたモデル取得とビルド
戸田さんはまず入り口でつまずいたと振り返ります。ブログに書かれたGitHubリポジトリのモデルが「404」で、そのままでは取ってこられなかったそうです。
まず入り口でつまずいちゃったんですよね。ブログに書かれていたGitHubのリポジトリのモデルが404だったんで、まず取ってこれないみたいな現象だったんですけど。
実体は別の場所にあり、それを探すのがやや面倒だったとのこと。この試行錯誤はZennの記事にまとめており、そちらを見ればより簡単に再現できるようにしたと話されています。
次のつまずきはビルド部分でした。ブログの手順ではCMakeがあれば普通にビルドできそうな雰囲気だったものの、戸田さんのM3 Macの環境ではうまく再現しなかったそうです。
いろいろ試した結果、原因はビルドオプションが足りなかったことだったと説明します。通るオプションはZennの記事に書いているとのことです。
ビルドが通った後は、ユニットテストもCLIも無事に動作しました。Greedy DecodingやBeam Searchなどのオプションもかなりそろっていたと話されています。
出力形式も、.txtやJSONに加えて、単語ごとのタイムスタンプを入れることもできたそうです。
量子化で認識はどれだけ崩れるか
ここからは再現実験に入ります。まず測ったのは量子化誤差で、元のモデルに対するCER(文字ベースの誤り率)で評価しています。
戸田さんは、ここでのCERの見方に注意を促します。一般的なCERは正解文に対する誤り率ですが、今回見ているのは量子化誤差なので、元モデルの出力に対する量子化モデルのCERだという点です。
測定の結果、8ビット量子化では誤差はほぼゼロで、これはブログの主張どおりでした。4ビット量子化では8%ほどのエラーレートになったそうです。
この4ビットの結果もブログの主張と若干の誤差はあるものの、ほぼ一致していたと話されています。
8ビット量子化だと、ほぼゼロ。これはブログの主張通りで、4ビット量子化だと、8パーセントほどになるっていう結果でしたね。
ただし戸田さんは、英語より日本語の方が一文字当たりの情報量が大きいため、文字単位の崩れは体感上かなり目立つのではないか、との見立ても添えています。
日本語で精度は出るのか、CER28%をどう読むか
量子化誤差が確認できたので、次に一番実務に影響する音声認識精度を検証しています。
今回のモデルは、FLEURSの日本語データに対して、元モデルのCERが約28%でした。
8ビット量子化で28.58%、4ビット量子化で29.72%と、量子化しても元モデルの出力が結構保たれていることがわかる、と戸田さんは述べます。
一方で気になるのは、元モデル自体がこのデータでそこまで強くないように見える点です。ここは読み方に注意が必要だと話します。
元のブログの主張では、wav2vec2は英語以外でWhisperよりよいことがある、とされていました。しかし今回の日本語FLEURSの結果を見ると、このモデルがそこまで高精度とは思えない、というのが戸田さんの実感です。
Whisperと直接比較はしていないため断定はできないとしつつ、CER28%はあまりよい精度ではないのではないか、と戸田さんは受け止めています。
CPUで速いはずが、RTF3で遅かった
今回の実験で元のブログと大きくずれたのが速度でした。ブログではCPU推論でだいぶ速くなるという主張があったそうです。
ブログの環境はARMで、RTFが約0.32だったとのこと。RTFはReal Time Factorで、10秒の音声を処理するのに10秒かかればRTFは1、5秒で済めば0.5となり、小さいほど速いという指標です。
ところが今回のM3 Macで測ると、RTFは約3でした。10秒の音声処理に約30秒かかる計算で、リアルタイムよりかなり遅い結果になっています。
今回のM3 Macで測った時は、大体このRTFが3ぐらいだったんですよね。つまり、10秒の音声を処理するのに、大体30秒ぐらいかかっちゃうっていう感じ。
遅さの原因はCNN前段のシングルスレッド動作か
遅さの原因を探るためプロファイルを見ると、実行時間のほぼ全部が「wv2 conv1D」というモジュールに寄っていたそうです。
wav2vec2には、音声波形から特徴量を作るCNNの前段があります。今回量子化したのはTransformerの部分で、このCNNのところがシングルスレッドで動いているように見えた、と戸田さんは説明します。
これがハードの制約なのか、ビルド時にうまくいかなかったのか、環境の違いなのかは切り分けきれなかったそうです。ここが高速化できなかったことが遅さの原因ではないか、との見立てにとどまっています。
そのうえで、M3 MacやApple Siliconで動かす場合はCNN部分の最適化を何かしら考える必要があり、逆に元ブログの著者のようにARM環境でいければ問題ないのかもしれない、とまとめています。
記事だけでは分からない、手元で試す意味
今回はブログの再現を試みたものの、あまりうまくいかなかった、というのが結論です。ただし精度の面では大きな問題はなさそうだった、との印象も語られました。
戸田さんが挙げる教訓は、実際に手元で試してみることの大切さです。記事を読んだだけだと「出たんだ、今度使ってみよう」で終わりがちだと指摘します。
結構そのハードウェアに制約があるようなものだったりっていうので、すぐに使えるものじゃないよみたいなのとか、結構記事読んでるだけじゃわからないですからね。
環境構築でつまずいたり、ビルドオプションが足りなかったりと、自分の環境ならではの問題は試してみないと分からない、と話されています。
動かす際に残した試行錯誤や実際のオプションはポッドキャストでは伝えにくいため、Zennにテックブログ形式でまとめたとのことです。
まとめ
wav2vec2.cppで日本語音声認識をC++実行した検証は、量子化誤差はほぼ公表値どおりに再現できた一方、精度や速度では手元ならではの発見があった回でした。
- wav2vec2をPythonなしでC++実行するwav2vec2.cppを、日本語モデルとFLEURS先頭30サンプルで検証した
- 量子化誤差は8ビットでほぼゼロ、4ビットで約8%と、ブログの主張とほぼ一致した
- FLEURS日本語のCERは元モデル約28%で、日本語で高精度とは言い切れないと戸田さんは受け止めた
- 速度はブログのARM環境がRTF約0.32に対し、M3 MacではRTF約3と遅く、CNN前段のシングルスレッド動作が疑われた
- 記事を読むだけでは分からない環境依存の問題があり、手元で試す意味が大きいと語られた







