Haas-ja-v1.0をWindowsで動かす|日本語の文字起こしはWhisperから乗り換えるか

Haas-ja-v1.0をWindowsで動かす日本語の文字起こしをWhisperと比較(比較図) AI音楽・音声

この記事の要点

公開の朗読音声 FLEURS を短い発話ごとに渡した比較では、Haas-ja-v1.0 は比べたどのモデルよりも文字の誤りが少なく、GPU での処理もエンジンの違う比較ながら Whisper 系のどれより速かった。FLEURS のような朗読を短い発話に区切って文字にする使い方なら、Whisper から替えて試す価値がある。

Windows では公式のコードではなく speech.cpp と GGUF で動き、CPU だけで動かしても、誤り率は GPU で動かしたときとの差が小さかった。GPU を使わずに動かす使い方も、測った PC の CPU では候補に入る速さだった。

発話をつないだ長い音声を話している区間ごとに分けて処理すると、ほかより極端に音量の小さい発話が区間の検出から外れ、丸ごと抜けた。この30分の比較で、Haas-ja-v1.0 は区間の検出を既定設定で使った。Whisper で一番誤りの少なかった設定 (large-v3-turbo・区間の検出なし) と比べると、替えて誤りが減る結果にはならなかった。

スポンサーリンク

Haas-ja-v1.0はWhisperより正確で速いか

公開の音声データセット FLEURS の日本語 650 発話を1発話ずつ渡して比べると、speech.cpp で動かした Haas-ja-v1.0 (Q8_0) は、測った6つのモデルの中で文字の誤り率 (CER strict) が一番低かった。RTX 5080 での処理は Whisper large-v3 より1桁速かった。一方、発話をつないだ30分の音声を、話している区間を見つける処理 (VAD) にかけてから認識すると、ほかより極端に音量の小さい発話が丸ごと出力から抜けた。この30分の音声の誤り 774 文字のうち 521 文字は削除だった。

比べた6つは Haas-ja-v1.0・parakeet-tdt_ctc-0.6b-ja・reazonspeech-nemo-v2・Whisper large-v3・Whisper large-v3-turbo・kotoba-whisper-v2.0 で、FLEURS は英語の Wikipedia の文を日本語に訳して読み上げた音声になる。話し言葉・雑音・複数の話者を含む録音では測っていないので、誤り率の順はこの朗読音声での順として読む。速さの差も、speech.cpp と faster-whisper というエンジンの違う比較で、RTX 5080 に1発話ずつ渡したときのもの。

30分の音声は、発話ごとに録音の音量が違う朗読をつないだ合成の音声で、会議や講演などの実際の長い録音ではない。抜けがどこで起きていたかは、30分の音声の節で切り分けた。

Whisper large-v3 と large-v3-turbo を手元で動かすのに要る VRAM と速さは、Whisperをローカルで動かす必要スペックで扱っている。この記事は、そこで Whisper を動かせるようになった PC で、日本語専用のモデルに替えるとどう変わるかを見る。

Haas-ja-v1.0とは: 日本語専用の616Mパラメータの音声認識

Haas-ja-v1.0 は、Third Intelligence が公開した日本語の音声認識モデルで、Hugging Face のモデルカード (third-intelligence/Haas-ja-v1.0、revision 660728d) によると、NVIDIA の Parakeet-TDT をもとに、デコーダーの予測ネットワークを LSTM から Kimi Delta Attention (KDA) に置き換えた構成をとる。音声を読み取るエンコーダーは FastConformer、文字を出すデコーダーは TDT になる。パラメータ数は 615.8M で、そのうちエンコーダーが 608.9M を占める。構造の細部はこの記事では扱わない。

モデルカードには、学習に公開のコーパス (ReazonSpeech・Common Voice 26.0・YODAS) と社内のデータを合わせた約4万6,000時間の音声を使い、評価に使うデータは学習に使っていないと書かれている。ライセンスは、モデルの重みと推論のコードが Apache License 2.0 で、第三者の部品はそれぞれのライセンスのままとされている。特定の用途で使ってよいかは、このライセンスの記載を手元で読んで判断することになる。

公式の推論コード Haas-ASR の動作要件は、NVIDIA の GPU がある Linux と、Python 3.11 以上・NeMo 2.7 とモデルカードに書かれている。予測ネットワークが Triton と CUDA を要る flash-linear-attention のカーネルで動くため、CPU と macOS には対応していない。カードは Windows を要件に挙げておらず、Windows で公式のコードを動かすことは試していない。

配布元の評価と速さの数字の条件

配布元は、5つの公開データセット (JSUT basic5000・JVNV・TEDxJP-10K・FLEURS・SpeechBSD) を合わせた評価セット asr-ja-bench v1.1 で、再生時間で重み付けした CER strict が 6.12% と、評価したオープンなモデルの中で一番低かったと書いている。商用の API の中には、これより低いものがあるとも書かれている。この記事で測ったのは、このうち FLEURS の 650 発話だけで、ほかの4つのデータセットは測っていない。

モデルカードの RTFx 3,236 は、NVIDIA H200 1枚で、まとめて処理する発話の数 (バッチの大きさ) を 512 にして測った値で、ハードウェアとバッチの大きさで変わると書かれている。この記事の速さは1発話ずつ (バッチ1) 渡した値なので、この数字とは比べられない。

モデルカードは限界として、ストリーミング向けには学習していないこと、話者や感情などは認識しないこと、フィラーを省きがちで、漢字・かな・数字のどれで書くかといった出力の書き方は調整できないことを挙げている。これらはこの記事では確かめていない。出力全体の書き方とは別に、個々の語の書き方は、後で触れるカスタム語彙で指定できる (speech.cpp は 0.9.4 から対応していて、0.10.0 で指定の名前が変わった)。カスタム語彙の効果は測っていない。

Windowsで動かす: speech.cppとGGUF

公式のコードが Linux と NVIDIA の GPU を前提にしているので、Windows では、sakasegawa が Hugging Face で配る Haas-ja-v1.0 の GGUF を speech.cpp で動かす。配布ページ (sakasegawa/Haas-ja-v1.0-GGUF) の revision 25c400b (2026年10月31日更新) のファイルは speech.cpp 0.9.4 以降でだけ動き、0.9.3 は以前のファイル (revision 3168c92) を取ってくる。配布ページは、以前のファイルと 25c400b は重みが同じで、以前のファイルにはカスタム語彙の設定が無いと書いている。配布ページの最新は、同じ日のその後に出た revision 6b965d5 で、GGUF の本体は 25c400b と同じまま、付いている .gguf.json と説明の両方で、カスタム語彙の指定の名前が speech.cpp 0.10.0 に合わせて keywords に変わった。この記事の計測の大半は 3168c92 のファイルで、25c400b は Q8_0 だけを 0.9.4 で測った。speech.cpp 独自の形式なので、llama.cpp・LM Studio・Ollama など、GGUF を読むほかのソフトでは動かない。

配布ページは、公式のコードが NVIDIA の GPU を要るのに対し、この GGUF は Windows と Linux では Vulkan で、ほかに CPU だけでも動くと書いている。変換の各段階は、公式のコード (NeMo 2.7.3 と Haas-ASR) と FLEURS の5発話で照合したとも書かれている。公式のコードは動かしていないので、出力がそろうかは手元では確かめていない。

speech.cppの入れ方

speech.cpp は MIT ライセンスのソフトで、README (v0.9.3) によると実行ファイル1つで動き、Python も CUDA も要らない。Windows x64 向けは Vulkan で GPU を使うビルドで、インストールの文書 (v0.9.4 の docs/install.md) によると、Vulkan のローダー (vulkan-1.dll) が要る。NVIDIA・AMD・Intel の GPU のドライバーを入れると一緒に入るもので、実行ファイルがこのローダーにつながっているため、CPU で認識するときも要る。無いとインストーラーは止まる。PowerShell で次の1行を実行すると入る。

irm https://raw.githubusercontent.com/nyosegawa/speech.cpp/main/install.ps1 | iex

この1行は公式のスクリプトを取ってきてそのまま実行し、その時点で一番新しいリリースを入れる。入れた先のフォルダーがユーザーの PATH に無ければ足し、前に入れていたものは消して置き換える。2026年10月31日の時点で入るのは 0.10.0 になる。この記事の表の speech.cpp の値は 0.9.4 で測ったもので、0.10.0 で測り直した範囲は「speech.cpp 0.9.3と0.9.4の違い」の節にある。表と同じ 0.9.4 で試すなら、インストールの文書にある書き方で -Version 0.9.4 を付ける。

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/nyosegawa/speech.cpp/main/install.ps1))) -Version 0.9.4

入れた後は、新しいターミナルを開いて speech --version で入ったバージョンを確かめられる。この記事の計測ではインストーラーを使わず、GitHub のリリースにある zip (speech-0.9.3-windows-x64-vulkan.zip・speech-0.9.4-windows-x64-vulkan.zip と、計測の後に出た speech-0.10.0-windows-x64-vulkan.zip) を SHA256SUMS で照合してから展開した。測ったのはこの3つの Windows x64 向け (Vulkan) のバイナリになる。ただし 0.10.0 では、Haas-ja-v1.0 の Q8_0 を GPU で 650 発話測った分しか無い。

0.9.4 は 2026年10月31日に公開された。リリースノートには、FastConformer の計算の並びを変えて KDA のデコードの1歩を軽くしたことと、Haas-ASR のカスタム語彙 (words・words_alpha・words_guard の指定) に対応したことが書かれている。カスタム語彙は測っていない。同じ日の日本時間 14 時ごろには 0.10.0 も公開された。変更の説明 (#202) によると、カスタム語彙の指定の名前が OpenAI の文字起こしと同じ keywords (keywords_alpha・keywords_guard) に変わり、カスタム語彙とタイムスタンプを一緒に指定すると受け付けなくなった。リリースの説明 (#203) には、0.9.4 と比べて計算を行うコードは変わっていないとあるが、開発元が動かしたのは macOS (Apple M5) で、Windows では動かしていないとも書かれている。

基本のコマンド

GGUF の配布ページにある使い方は、短い音声と長い録音で次の2通り。

speech asr haas-ja-v1.0 utterance.wav
speech asr haas-ja-v1.0 --vad silero-vad meeting.wav

コマンドの各部分の意味を「基本のコマンドの指定表」にまとめた。

指定 意味
speech asr haas-ja-v1.0 Haas-ja-v1.0 で音声を文字にする。初回は配布ページから Q8_0 のファイルを取ってくる
haas-ja-v1.0:q4_k 名前の後ろに型を付けると、その型のファイルを取ってくる
ダウンロード済みのファイルのパス モデルの名前の代わりに書くと、そのファイルで動く (この記事の計測はこの書き方)
utterance.wav / meeting.wav 文字にする音声のファイル
--vad silero-vad 検出モデル silero-vad で話している区間を見つけ、区間ごとに認識してつなぐ。配布ページは、30秒ほどより長い録音はこの指定で認識するのがよいと書いている

使う装置と区間の検出の既定値

speech.cpp の文書 (v0.9.3 の docs/cli.md) にある、使う装置の指定と --vad の既定値を「装置と区間の検出の指定表」にまとめた。

指定 意味
--device auto 既定。最初の GPU を使い、GPU が無い PC では CPU を使う
--device gpu GPU を使う
--device cpu CPU を使う
--device Vulkan0 speech devices が出す名前で装置を選ぶ
--threshold 0.5 話していると見なす確率 (既定)
--speech-pad-ms 300 区間の前後に残す音声 (既定)
--min-silence-duration-ms 500 区間を終わらせる無音 (既定)
--max-speech-duration-s 10 区間の最長 (既定)。超えると一番長い無音で切る
--min-speech-duration-ms 250 残す区間の最短 (既定)

区間の検出は、--device に関係なく CPU の1スレッドで動く。この記事の計測は --device Vulkan0 か --device cpu を明示し、--vad の値は既定のままにした。変えたのは、30分の音声の節で試した --threshold だけになる。

誤り率と速さ: FLEURSの650発話でWhisper・Parakeetと比べる

誤り率は CER (文字誤り率) で比べる。CER は、正解文に対して別の文字に置き換わった文字 (置換)・抜けた文字 (削除)・余計に足された文字 (挿入) の数を合計し、正解文の文字数で割った値で、低いほど誤りが少ない。jacer で表記の揺れを正規化してから数える。CER strict は漢字とかなの書き分けの違いも誤りに数える。CER flex は、同じ語の書き方の違い (漢字とかなの選び方や、使う漢字の違い) は数えないが、音が同じ別の語の取り違えは誤りに数える。CER kana は読みで比べる。この3種類の定義はモデルカードの Metrics の節によるもので、この記事の CER は 650 発話全体の文字数で割ったマイクロ平均になる。

速さは RTFx で比べる。RTFx は音声の長さを処理にかかった時間で割った値で、240 なら1秒で240秒分の音声を処理したことになる。短い発話では、650 発話を通して測る1回ごとに、音声の長さの合計を処理時間の合計で割って RTFx を出し、3回の中央値を表に載せた。ここでの1発話の処理時間は、16 ビットの整数の音声を受け取った直後から、認識した文が手元に揃うまでの時間で、WAV ファイルの読み込みとモデルの読み込みは含まない。この間に、speech.cpp では speech worker への送信と受信が、faster-whisper では小数への変換と出力の取り出しが入る。表の「1発話の処理時間 (中央値)」は、発話ごとに3回の中央値を取り、その 650 発話の中央値を取った値。

表の「GPU全体の使用量の増分」は、nvidia-smi で 0.5 秒ごとに読んだ GPU 全体の値と、モデルを読み込む前の値との差の最大で、対象のプロセスだけの使用量ではなく、モデルが必要とする VRAM でもない。モデルを読み込む前の値は、条件ごとに計測を始める直前の2秒間に読んだ値の中央値で、差の最大は読み込みから3回の計測が終わるまでの間で取った。条件ごとに別のプロセスで動かし、終わるとプロセスごと閉じている。GPU を使うほかのベンチマークとは重ならないようにしたが、デスクトップなど、ほかのプロセスの増減は除けていない。

測った6つのモデルの結果

6つのモデルの誤り率・速さ・GPU 全体の使用量の増分を「FLEURS 650発話の比較表」にまとめた (RTX 5080・1発話ずつ・各3回。CER は1回目の文)。

モデル 動かし方 CER strict CER flex CER kana RTFx (3回の中央値) RTFx の幅 (3回) 1発話の処理時間 (中央値) GPU全体の使用量の増分
Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) 3.69% 3.02% 2.36% 326.4 325.2〜332.5 0.037秒 833MiB
Whisper large-v3 faster-whisper・GPU (float16) 4.22% 3.53% 2.61% 22.5 22.4〜22.7 0.543秒 4,344MiB
Whisper large-v3-turbo faster-whisper・GPU (float16) 4.48% 3.83% 2.67% 66.3 64.5〜66.7 0.190秒 2,485MiB
parakeet-tdt_ctc-0.6b-ja (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) 5.49% 4.15% 3.62% 346.5 337.8〜350.7 0.035秒 787MiB
reazonspeech-nemo-v2 (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) 5.91% 4.65% 3.69% 100.1 100.0〜100.1 0.126秒 806MiB
kotoba-whisper-v2.0 faster-whisper・GPU (float16) 6.68% 5.86% 4.25% 75.1 73.5〜75.4 0.169秒 2,354MiB
FLEURS 650発話の CER strict (低いほど誤りが少ない)FLEURS の日本語 650 発話の CER strict を6つのモデルで比べるHaas-ja-v1.0 (Q8_0)3.69%Whisper large-v34.22%Whisper large-v3-turbo4.48%parakeet-tdt_ctc-0.6b-ja (Q8_0)5.49%reazonspeech-nemo-v2 (Q8_0)5.91%kotoba-whisper-v2.06.68%単位: %
図: FLEURS の日本語 650 発話を1発話ずつ渡したときの CER strict (低いほど誤りが少ない、2026年10月31日測定、RTX 5080)。speech.cpp の行は 0.9.4

CER strict は、speech.cpp 0.9.4 で動かした Haas-ja-v1.0 (Q8_0) の 3.69% が測った6つのモデルで一番低く、2番目は Whisper large-v3 の 4.22% だった。そのあとは large-v3-turbo、parakeet-tdt_ctc-0.6b-ja、reazonspeech-nemo-v2、kotoba-whisper-v2.0 の順になる。CER flex と CER kana でも、Haas-ja-v1.0 の行が一番低い。この順は FLEURS の朗読音声での順で、音声の種類が変われば入れ替わりうる。

配布元の評価とのずれ

モデルカードの CER の表は画像 (assets/cer_table.png) で載っていて、その FLEURS の列と手元の値を「配布元の FLEURS 列との対照表」に並べた。モデルカードでの表記は、parakeet-tdt_ctc-0.6b-ja が Parakeet TDT+CTC 0.6B (ja)、kotoba-whisper-v2.0 が Kotoba-Whisper v2.0。

モデル モデルカードの FLEURS 列 (CER strict) 手元の値 (CER strict)
Haas-ja-v1.0 3.67% 3.69%
Whisper large-v3 4.25% 4.22%
parakeet-tdt_ctc-0.6b-ja 5.50% 5.49%
kotoba-whisper-v2.0 6.75% 6.68%

4つとも、手元の値はモデルカードの値と 0.1ポイント以内でそろった。モデルカードで見つけた測定条件は、速さを測った H200 とバッチの大きさだけだった。公式のコード Haas-ASR の評価スクリプト (examples/evaluate_asr_ja_bench.py) には、公開した評価と同じ設定として、bfloat16・バッチにまとめた greedy decoding (各段で一番確からしい候補だけを残すデコード)・512 発話ずつ・ベンチマークの並び順と書かれている。CER を出したときの GPU の機種は見つけられなかった。手元は speech.cpp の GGUF と faster-whisper (CTranslate2) の変換なので、配布元と計算の細部が同じとは限らない。手元の環境 (speech.cpp の GGUF・faster-whisper の変換・RTX 5080) で動かしても、誤り率は配布元の表の値とほぼ同じところに出た。

速さとGPU全体の使用量の増分

RTX 5080 での RTFx (3回の中央値) は、Haas-ja-v1.0 (Q8_0) が 326.4、Whisper large-v3 が 22.5 で、Haas-ja-v1.0 が1桁速かった。6つのうち一番速かったのは parakeet-tdt_ctc-0.6b-ja、一番遅かったのは Whisper large-v3 だった。どちらも1発話ずつ渡していて、speech.cpp はモデルを読み込んだまま音声を待つ speech worker に、faster-whisper は読み込み済みのモデルに渡した。エンジンの違う比較になる。faster-whisper はビームサーチの幅 5 (既定) で言語に ja を指定している。Haas-ja-v1.0 の 326.4 はデコードを既定の CPU で行った値で、GPU でデコードすると 235.8 になる。バッチをまとめて処理したときの速さは測っていない。

GPU 全体の使用量の増分は、Haas-ja-v1.0 (Q8_0) が 833MiB、Whisper large-v3 が 4,344MiB、large-v3-turbo が 2,485MiB で、RTX 5080 の VRAM (16,303MiB) に対してどれも小さい。speech.cpp で動かす3つのモデルは、faster-whisper の3つより増分が小さく出ている。ローカルの LLM と同じ GPU で文字起こしを回すときにこの差がどう出るかは、ローカルLLM常駐中にWhisperで文字起こしを回すと何が詰まるかが Whisper の側から扱っている。

量子化はQ8_0・F16・Q4_Kのどれにするか

配布ページの Files の表によると、Haas-ja-v1.0 の GGUF は「GGUF の型ごとの大きさ表」の3つのほか、Q6_K と Q5_K も配られている。表の値は計測に使った revision 3168c92 のファイルで、revision 25c400b のファイルはどれも 252,928 バイト大きい (最新の revision 6b965d5 も、GGUF の本体は 25c400b と同じ)。GiB は 1GiB = 1,073,741,824 バイトで換算した値で、Q6_K と Q5_K は測っていない。

型 ファイルの大きさ
F16 1,232,875,904 バイト (約1.15GiB)
Q8_0 (名前だけで取ってくる型) 656,128,544 バイト (約0.61GiB)
Q4_K 351,648,288 バイト (約0.33GiB)

3つのファイルの比較

3つの型を同じ 650 発話で比べ、デコードの置き場所と speech.cpp のバージョンも変えた結果を「量子化とデコードの比較表」にまとめた (RTX 5080・1発話ずつ・各3回)。デコードの列は decode_on_cpu の値で、Q8_0 と Q4_K の既定は CPU、F16 の既定は GPU になる。モデルの列に 25c400b と書いた行だけが配布ページの revision 25c400b のファイル (GGUF の本体は最新の 6b965d5 と同じ) で、ほかの行は revision 3168c92 のファイル。

モデル speech.cpp デコード CER strict RTFx (3回の中央値) RTFx の幅 (3回) GPU全体の使用量の増分
Haas-ja-v1.0 (Q8_0) 0.9.4 CPU (既定) 3.69% 326.4 325.2〜332.5 833MiB
Haas-ja-v1.0 (Q8_0・25c400b) 0.9.4 CPU (既定) 3.69% 332.4 329.7〜333.1 830MiB
Haas-ja-v1.0 (Q8_0) 0.9.4 GPU (--decode-on-cpu=false) 3.67% 235.8 231.9〜238.1 831MiB
Haas-ja-v1.0 (F16) 0.9.4 GPU (既定) 3.69% 241.6 240.5〜242.2 1,379MiB
Haas-ja-v1.0 (Q4_K) 0.9.4 CPU (既定) 3.74% 325.9 321.4〜327.1 540MiB
Haas-ja-v1.0 (Q8_0) 0.9.3 CPU (既定) 3.68% 237.6 222.4〜238.6 869MiB
Haas-ja-v1.0 (Q8_0) 0.9.3 GPU (--decode-on-cpu=false) 3.67% 226.0 225.3〜231.2 821MiB
Haas-ja-v1.0 (F16) 0.9.3 GPU (既定) 3.69% 223.8 208.0〜225.4 1,374MiB
Haas-ja-v1.0 (Q4_K) 0.9.3 CPU (既定) 3.75% 229.9 210.5〜230.8 551MiB

0.9.4 の行で見ると、Q8_0・F16・Q4_K の CER strict は 3.69%・3.69%・3.74% で、差は 0.1 ポイント未満だった。速さは Q8_0 と Q4_K がほぼ同じで、F16 だけが遅い。GPU 全体の使用量の増分は Q4_K、Q8_0、F16 の順に大きくなる。この PC と FLEURS の範囲では、測った F16 と Q4_K のどちらも、名前だけで取ってくる Q8_0 より誤り率や速さが良くなることは無く、Q4_K に替えると GPU 全体の使用量の増分が減る代わりに CER strict がわずかに上がった。この差が別の音声でも同じかは測っていない。

revision 25c400b の Q8_0 を speech.cpp 0.9.4 で動かすと、CER strict は 3.69%・RTFx は 332.4 で、650 発話と30分の音声の出力の文は、計測に使った 3168c92 の Q8_0 と1文字も違わなかった。F16 と Q4_K は 3168c92 のファイルで測っている。

デコードをCPUとGPUのどちらでするか

speech.cpp の文書 (v0.9.3 の docs/models/fastconformer.md) によると、GPU に載せたモデルでも、Q8_0 と K-quant (Q6_K・Q5_K・Q4_K) のファイルは既定でデコードを CPU で行い (decode_on_cpu が true)、F16 と F32 は GPU で行う。decode_on_cpu を false にすると、量子化したファイルも GPU でデコードする。GGUF の配布ページは、以前のファイル (revision 3168c92) の説明では RTX 2080 で F16 のほうが Q8_0 より速かったと書き、revision 25c400b の説明では F16 と Q8_0 がほぼ同じ時間だったと書いている。

speech.cpp 0.9.4 で F16 が遅かったことには、最後のデコード (エンコーダーが出した音声の特徴から、出力のトークンを順に決めて文字列にする段) を CPU と GPU のどちらに置くかが関わっていると考えられる。Q8_0 を --decode-on-cpu=false で GPU のデコードに移すと RTFx が 235.8 に下がり、デコードを既定で GPU に置く F16 (241.6) と同じくらいになった。F16 を CPU でデコードする回は測っていないので、型の違いとデコードの置き場所の影響を切り分けきった比較ではない。CPU が Core i7-14700F のこの PC では、既定のまま (デコードは CPU) のほうが速かった。CPU や GPU が違えば結果は変わりうる。

speech.cpp 0.9.3と0.9.4の違い

量子化とデコードの比較表の 0.9.3 の行と 0.9.4 の行を比べると、Q8_0 の RTFx は 0.9.3 で 237.6、0.9.4 で 326.4 で、CER strict は 3.68% と 3.69% でほとんど変わらなかった。F16 は 223.8 から 241.6、Q4_K は 229.9 から 325.9 になった。2つのバージョンは同じ日に、0.9.3 を 07:59 から、0.9.4 を 11:37 から測っている。GPU (Vulkan) で動かした30分の音声の出力の文は、Haas-ja-v1.0 も parakeet-tdt_ctc-0.6b-ja も、0.9.3 と 0.9.4 で1文字も違わなかった。Haas-ja-v1.0 を CPU で動かした30分の音声は、CER strict が 0.9.3 で 11.72%、0.9.4 で 11.66% とわずかに違った。表の 0.9.3 の行は比べるために載せている。速くなった理由は、リリースのどの変更によるのかも、測った時刻の違いが影響したのかも切り分けていない。0.9.4 のリリースノートに書かれた内容は、Windows で動かす節にある。

計測の後、同じ日に speech.cpp 0.10.0 が公開されたので、Haas-ja-v1.0 の Q8_0 の 650 発話を GPU (Vulkan) で 0.10.0 でも測った。revision 25c400b のファイルでも、計測に使った 3168c92 のファイルでも、出力の文は 650 発話とも 0.9.4 と1文字も違わず、CER strict は 3.69% のままだった。RTFx (3回の中央値) は、25c400b のファイルが 320.0 (0.9.4 では 332.4)、3168c92 のファイルが 317.8 (0.9.4 では 326.4) で、どちらも 0.9.4 より少し低く、3回の幅も 0.9.4 の幅と重ならなかった。0.10.0 は日本時間の 15:49 から測っており、0.9.4 とは測った時刻が違う。この差の理由は切り分けていない。30分の音声、CPU だけの計測、ほかの量子化とモデルは 0.10.0 では測っていないので、表には 0.10.0 の値を入れず、0.9.4 の値のまま載せている。2026年10月31日の時点では、インストーラーをそのまま実行すると 0.10.0 が入る。

スポンサーリンク

GPUなしで使えるか: CPUだけの速さ

GPU を使わず Core i7-14700F だけで動かした結果を「CPU だけの比較表」にまとめた。speech.cpp のスレッド数は既定 (性能コアの数) のままで、speech.cpp は 8 スレッドで動いていると報告した。faster-whisper の cpu_threads は、指定しない回 (既定の 0) と 8 にした回を測った。指定しない回に実際に何スレッドで動いたかと、環境変数 OMP_NUM_THREADS の値は記録していない。faster-whisper の CPU は、650 発話の1回目が 500 発話までで処理時間の累計 2,172 秒になり、650 発話では1回に 2,800 秒ほどかかる見込みだったので打ち切り、先頭100発話 (650 発話の一覧の並びで先頭から100発話、音声 1,303秒) に絞って比べた。

範囲 モデル 動かし方 CER strict RTFx (3回の中央値) RTFx の幅 (3回) 1発話の処理時間 (中央値)
650発話 Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.4・CPU (スレッド数は既定) 3.66% 25.1 24.7〜25.4 0.483秒
650発話 Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.3・CPU (スレッド数は既定) 3.70% 22.8 22.8〜23.0 0.531秒
先頭100発話 Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.4・CPU (スレッド数は既定) 3.92% 25.3 24.8〜26.2 0.479秒
先頭100発話 Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.3・CPU (スレッド数は既定) 3.94% 23.9 23.7〜25.0 0.509秒
先頭100発話 Whisper large-v3-turbo faster-whisper・CPU (int8・cpu_threads は既定) 4.69% 2.9 2.9〜3.0 4.377秒
先頭100発話 Whisper large-v3-turbo faster-whisper・CPU (int8・cpu_threads=8) 4.69% 2.8 2.8〜2.9 4.590秒

650 発話の行では、Haas-ja-v1.0 (Q8_0・speech.cpp 0.9.4) を CPU だけで動かすと RTFx 25.1、CER strict 3.66% で、GPU で動かしたとき (3.69%) との差は 0.03 ポイントだった。この速さは、FLEURS 650発話の比較表で RTX 5080 を使った Whisper large-v3 と同じくらいかそれより上にあたる (エンジンの違う比較)。

先頭100発話の行では、Haas-ja-v1.0 が RTFx 25.3、faster-whisper の large-v3-turbo (int8) が 2.9 で、Haas-ja-v1.0 が1桁近く速かった。large-v3-turbo は cpu_threads を 8 にしても 2.8 で、速くならなかった。先頭100発話の CER は発話の範囲が違うので、650 発話の行の値とは比べない。

30分の音声で起きたこと: 音量の極端に小さい発話が丸ごと抜ける

長い録音に --vad を付けるのは、speech.cpp の文書 (v0.9.3 の docs/cli.md) の説明による。--vad を付けると検出モデルが話している区間を見つけ、区間ごとに認識してつなぐ。その理由として文書は、いくつもの文を含む長い区間を1度に渡すと、文がまるごと落ちたり、誰も話していない所に言葉を書いたりすることがあるためと書いている。

公式のコード Haas-ASR は、30秒より長い録音には transcribe_longform を使うよう案内していて、これは音量で静かな箇所を見つけて区切る。この記事は公式のコードを動かしていないので、この区切り方での結果は測っていない。

30分の音声の結果

650 発話の一覧の先頭から順に、長さの合計が30分を超えるところまで発話をつないだ音声1本を処理した結果を「30分の音声の結果表」にまとめた (各3回)。つないだのは 128 発話で、16kHz・モノラルの 16 ビットの音声を、元のファイルの前後の無音は削らずに並べ、発話の間に1秒の無音を 127 か所はさんだ。長さは 30分12秒 (1,812秒、28,996,480 サンプル)。正解文は正規化後で 6,602 文字。CER は1回目の文で、Whisper large-v3 の区間の検出なしの回だけは3回で文が変わり、ほかは3回とも同じ文だった。

モデル 動かし方 区間の検出 CER strict 削除 (文字) 置換 (文字) 挿入 (文字) 処理時間 (3回の中央値) RTFx (3回の中央値) RTFx の幅 (3回)
Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) --vad silero-vad 11.72% 521 210 43 7.0秒 258.6 258.1〜260.3
Haas-ja-v1.0 (Q8_0) speech.cpp 0.9.4・CPU --vad silero-vad 11.66% 517 210 43 42.6秒 42.5 41.5〜43.3
parakeet-tdt_ctc-0.6b-ja (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) --vad silero-vad 11.92% 512 208 67 7.0秒 258.7 257.8〜260.0
reazonspeech-nemo-v2 (Q8_0) speech.cpp 0.9.4・GPU (Vulkan) --vad silero-vad 16.46% 746 265 76 15.3秒 118.3 116.9〜119.4
Whisper large-v3-turbo faster-whisper・GPU (float16) なし 10.81% 267 321 126 25.8秒 70.2 69.7〜71.9
Whisper large-v3-turbo faster-whisper・GPU (float16) vad_filter 16.42% 801 249 34 23.5秒 77.0 72.6〜78.9
Whisper large-v3 faster-whisper・GPU (float16) なし 30.61% 384 1,002 635 142.6秒 12.7 12.7〜15.6
Whisper large-v3 faster-whisper・GPU (float16) vad_filter 16.98% 655 276 190 75.4秒 24.0 24.0〜24.5

speech.cpp の --vad (既定の設定) で1回で処理すると、Haas-ja-v1.0 (Q8_0) の CER strict は 11.72% だった。同じ128発話を1発話ずつ渡したとき (FLEURS 650発話の比較表の回のうち、この128発話だけで数えた値) は 4.30% だった。誤り 774 文字のうち 521 文字が削除で、発話が丸ごと出力から抜けた箇所があった。削除のうち、抜けた発話の分が何文字かは数えていない。parakeet-tdt_ctc-0.6b-ja と reazonspeech-nemo-v2 も誤りの大半が削除で、Haas-ja-v1.0 だけの現象ではなかった。この音声は発話ごとに録音の音量が違う朗読をつないだ合成の音声で、会議・講演などの実際の長い録音では測っていない。

faster-whisper の large-v3-turbo は区間の検出なしで CER strict 10.81% と、Haas-ja-v1.0 と同じくらいだった。Whisper large-v3 は区間の検出なしだと同じ文を何度も繰り返す箇所があって 30.61% になり、3回とも出力の文が違った。faster-whisper の vad_filter (silero) を付けると、large-v3-turbo も large-v3 も削除が増えた。vad_filter でどの発話が抜けたかは確かめていない。

この30分の音声で、--vad を付けた Haas-ja-v1.0 (11.72%) より誤り率が低かったのは、区間の検出なしの large-v3-turbo (10.81%) だけで、差は1ポイント弱だった。large-v3 は区間の検出なしで 30.61%、vad_filter を付けて 16.98%、large-v3-turbo に vad_filter を付けると 16.42% で、どれも Haas-ja-v1.0 より高かった。区間の検出を付けた同士で比べると、Haas-ja-v1.0 の削除 (521 文字) は vad_filter を付けた large-v3-turbo (801 文字)・large-v3 (655 文字) より少なかった。speech.cpp の --vad と faster-whisper の vad_filter はどちらも silero の検出モデルを使うが、使うファイルも区間の決め方の設定も違う。speech.cpp は silero-vad の GGUF (配布ページによると v6.2) を上に書いた既定値で使う。faster-whisper 1.2.1 は同梱の silero_vad_v6.onnx を、閾値 0.5・残す区間の最短の制限なし・区間を終わらせる無音 2,000ms・区間の前後に残す音声 400ms・区間の最長なし、の既定値で使う (vad_parameters は指定していない)。faster-whisper は見つけた区間をつないでから認識する。削除の差を、区間の検出の性能の差だけとは読めない。

処理時間 (3回の中央値) は、Haas-ja-v1.0 (Q8_0) が GPU で 7.0秒、CPU だけで 42.6秒、faster-whisper の large-v3-turbo (区間の検出なし・GPU) が 25.8秒だった。speech.cpp は新しいプロセスの起動から終了まで (読み込みと区間の検出を含む)、faster-whisper は同じ Python のプロセスの中でのモデルの構築と認識を測っていて、計時の範囲が同じではない。

抜けたのは音量の小さい11発話

出力から丸ごと抜けた11発話は Haas-ja-v1.0 と parakeet-tdt_ctc-0.6b-ja で同じで、どれも録音の音量が極端に小さかった。11発話の RMS の中央値は -61.6dBFS、残りの117発話は -21.9dBFS で、約40dB の差がある。振幅にすると約100分の1になる。同じ11発話を1発話ずつ渡すと Haas-ja-v1.0 の CER strict は 2.3% で、読めていた。区間の検出だけを行う speech vad (0.9.4) に、--vad の既定と同じ値を指定して区間を書き出すと、区間は 173 個で speech asr --vad が報告する数と同じになり、11発話の時間には区間が1つも無く、残りの117発話にはどれも区間があった。この11発話が丸ごと抜けたのは、認識の段ではなく、区間の検出の段だった。RMS が -45dBFS 未満の発話は14あり、うち3つは区間があって抜けなかった。抜けた発話と抜けなかった発話で RMS の範囲が重なっていて (-62.1dBFS は両方にある)、音量だけでは抜けるかどうかが決まらない。音量のほかに何が関わるかは確かめていない。

抜けた発話は2段階で決めた。まず speech.cpp の -v --timestamps の出力 (0.9.3) で、各発話について、つないだ音声の中のその発話の時間と少しでも重なる区間の文を集めた。正解文は、空白・句読点・かぎかっこを除いて隣り合う2文字の組に分け (同じ組は1つと数える)、集めた文に現れる組が半分未満だった発話を候補にした。次に、候補の11発話の時間に重なる区間が無いことを、区間の検出だけを行う speech vad の出力で確かめた。RMS は、発話のファイル全体 (前後の無音を含む) の値を 32,768 で割り、二乗平均の平方根を dB にしたもので、直流分は引いていない。1発話ずつの 2.3% は FLEURS 650発話の比較表の回 (speech.cpp 0.9.4) の1回目の文で、0.9.3 の回でも同じ 2.3% だった。

切り分けの結果を「抜けの切り分け表」にまとめた (RTX 5080・speech.cpp 0.9.3・--vad silero-vad・各1回)。区間の数は speech.cpp が出す regions の数で、閾値を変えたのは Haas-ja-v1.0 だけ。この診断は 0.9.4 の公開前に 0.9.3 で行ったもので、元の音声・既定の閾値での出力の文は 0.9.4 と同じだった。

音声 モデル --threshold 区間の数 CER strict 削除 (文字)
元の音声 Haas-ja-v1.0 (Q8_0) 0.5 173 11.72% 521
元の音声 Haas-ja-v1.0 (Q8_0) 0.3 172 10.92% 473
元の音声 Haas-ja-v1.0 (Q8_0) 0.2 179 10.60% 406
元の音声 Haas-ja-v1.0 (Q8_0) 0.1 198 9.60% 349
元の音声 parakeet-tdt_ctc-0.6b-ja (Q8_0) 0.5 173 11.92% 512
小音量の14発話を持ち上げた音声 Haas-ja-v1.0 (Q8_0) 0.5 192 4.70% 64
小音量の14発話を持ち上げた音声 parakeet-tdt_ctc-0.6b-ja (Q8_0) 0.5 192 5.09% 71

RMS が -45dBFS 未満の14発話だけを、RMS が -22dBFS になる倍率で一律に大きくした音声も処理した。ただし、この倍率をかけるとピークが -1dBFS を超える発話は、-1dBFS で止まる倍率にした。そのため、14のうち4つは -22.3〜-24.9dBFS どまりになっている。この音声を --vad の既定のまま処理すると、Haas-ja-v1.0 の CER strict は 11.72% から 4.70% に下がり、削除は 521 文字から 64 文字に減った。parakeet-tdt_ctc-0.6b-ja も 11.92% から 5.09% に下がった。各1回の値だが、同じ条件の本計測の3回は毎回同じ文だった。この音声は発話ごとに音量を合わせた対照 (ピークは -1dBFS まで、ほかの発話は1サンプルも変えていない) で、録音全体を一律に大きくする手順ではない。

元の音声のまま --threshold を下げると、0.3 で 10.92%、0.2 で 10.60%、0.1 で 9.60% と少しずつ下がった。区間の数は 0.5 で 173、0.3 で 172、0.2 で 179、0.1 で 198 で、閾値に沿ってそろって増えたわけではない。それでも、音量を持ち上げた 4.70% には届かなかった。閾値を下げると削除は減る一方で、挿入は 0.5 の 43 文字から 0.1 では 101 文字に増え、正解文に無い「うん。」「ふむ。」のような短い言葉が増えた。閾値を下げても戻りきらなかった理由は切り分けていない。

長い録音で取れる手

測った範囲で言えるのは、調べた11発話の抜けが、認識の段ではなく区間の検出の段で起きていたことだ。抜けた発話の内容は、出力に残らない。既定の閾値の出力には、正解文に無い「うん。」が5回、「すいません。」が1回出ていたが、抜けた11発話のそれぞれに出たわけではない。録音の音量が極端に小さい発話が混じる長い録音を --vad で処理するときは、出力の文に発話がまとまって抜けた箇所がないかを、元の音声と照らして確かめることになる。この30分の音声では、--threshold を既定の 0.5 より下げると削除が少しずつ減ったが、元に戻るほどではなく、挿入が増えた。

検証環境と測り方

測定機は、GPU が RTX 5080 (VRAM 16GB、ドライバー 610.88)、CPU が Core i7-14700F、メインメモリが 96GiB、OS が Windows 11 (ビルド 26200)。RTX 5060 Ti も挿さっているが、この計測では使っていない。どの装置で動いたかは、計測した回ごとに記録で確かめた。speech.cpp の GPU の回は、次の2つで確かめた。まず、speech devices が出す Vulkan0 の名前が NVIDIA GeForce RTX 5080 で、同じ名前の装置がほかに無いこと。次に、nvidia-smi で見て VRAM が増えたのが RTX 5080 だけで、RTX 5060 Ti は増えていないこと。30分の音声は回ごとに新しいプロセスなので、回ごとに VRAM の増え方を見た。faster-whisper の GPU の回は、モデルを作った後に同じプロセスから CUDA が返した装置の PCI バスの番号が、nvidia-smi の RTX 5080 と一致した。speech.cpp の CPU の回は、speech.cpp が報告した装置が CPU で、GPU の VRAM が増えていないことを確かめた。faster-whisper の CPU の回は、CUDA を使わない指定 (device="cpu") で動かした。測定機の構成の詳しい記録は検証環境のページに置いている。本記事の実測値は2026年10月31日に、上記の測定機・設定で計測したもの。

ソフトは speech.cpp 0.9.3・0.9.4・0.10.0 (いずれも Windows x64 向け Vulkan の zip)、faster-whisper 1.2.1 (CTranslate2 4.8.4) で、CER の計算には jacer 1.2.0 を使った。0.10.0 で測ったのは Haas-ja-v1.0 の Q8_0 を GPU で 650 発話測った分だけで、CPU だけと30分の音声は測っていない。モデルは次のとおり。

  • Haas-ja-v1.0 の GGUF (sakasegawa) の revision 3168c92 の Q8_0・F16・Q4_K と、revision 25c400b の Q8_0
  • parakeet-tdt_ctc-0.6b-ja と reazonspeech-nemo-v2 の GGUF (どちらも Q8_0)
  • 区間の検出に使う silero-vad の GGUF (F32)
  • Whisper は Systran/faster-whisper-large-v3・mobiuslabsgmbh/faster-whisper-large-v3-turbo・kotoba-tech/kotoba-whisper-v2.0-faster

faster-whisper は GPU では float16、CPU では int8 で動かした。認識は WhisperModel.transcribe に言語 (ja)・ビームサーチの幅 (5)・vad_filter の有無だけを渡し、ほかは faster-whisper 1.2.1 の既定のままにした。既定の設定は次のとおり。うまく解けなかった区間は、温度を 0.0 から 1.0 まで 0.2 ずつ上げて解き直す。前の区間の文は次の区間の手がかりに使う (condition_on_previous_text が True)。30秒ずつ区切り、タイムスタンプを付けて解く。温度を上げて解き直すときは候補を無作為に選ぶ処理に切り替わり、乱数の種は指定していないので、同じ音声でも回ごとに出力や処理時間が変わることがある (30分の音声の large-v3・区間の検出なしでは3回とも文が違った)。faster-whisper の行は、この既定の設定のままで測った参考の値として読む。kotoba-whisper-v2.0 の配布ページの使い方の例は chunk_length=15・condition_on_previous_text=False で、この記事の設定とは違う。speech.cpp の3つのモデルはデコードの設定を変えておらず、speech.cpp の文書によると、Haas-ja-v1.0 と parakeet-tdt_ctc-0.6b-ja は greedy decoding、reazonspeech-nemo-v2 はビームサーチで解く。

音声は FLEURS の日本語 (ja_jp) の test の 650 発話で、合計 8,511秒。どの 650 発話を使うかと、正解文の2件の修正は、配布元が公開している asr-ja-bench の一覧に合わせた。元の音声は 32 ビットの浮動小数点の WAV なので、16 ビットの整数に変換してから全部のモデルに渡した。変換は、-1〜1 の外を切り詰めてから 32,767 倍し、一番近い整数に丸める (ちょうど半分は偶数の側) だけで、ディザは入れていない。意図して音量を変える処理はしていないが、丸めの誤差は入る。faster-whisper には、同じ 16 ビットの値を 32,768 で割って小数に戻して渡した。faster-whisper の large-v3-turbo に元の 32 ビットのまま渡しても CER strict は 4.47% で、変換した音声の 4.48% とほぼ同じだった。変換の前後を比べたのはこのモデルだけになる。FLEURS のライセンスは CC BY 4.0。

短い発話は、モデルを1回読み込み、ウォームアップの後に 650 発話を1つずつ渡すのを3回くり返した。RTFx は3回の中央値と最小〜最大の幅、CER は1回目の文で出している。モデルの読み込みにかかった時間は1発話の処理時間に含めていない。30分の音声は、3回とも毎回読み込みから測った。

ほかの GPU やモデルで測った値は、AIハードウェア実測データベースから探せる。

測っていないこと

試すときに気になりやすい順に並べる。

  • 会議・講演・電話など、話し言葉や雑音のある録音と、複数の話者がいる録音
  • RTX 5080 以外の GPU (AMD・Intel など NVIDIA 以外の GPU と、VRAM 12GB 以下の GPU を含む)
  • Core i7-14700F 以外の CPU (GPU の無い PC・ノート PC を含む)
  • speech.cpp 0.10.0 での30分の音声・CPU だけの計測・Q8_0 以外の量子化・Haas-ja-v1.0 以外のモデル
  • マイクからのリアルタイムの文字起こしと、タイムスタンプの正確さ
  • FLEURS 以外の4つのデータセット (JSUT basic5000・JVNV・TEDxJP-10K・SpeechBSD)
  • Q6_K と Q5_K、revision 25c400b と 6b965d5 の F16 と Q4_K
  • 音量が同じくらいでも、区間の検出から外れる発話と外れない発話が分かれる理由
  • kotoba-whisper v2.1・v2.2 (v2.0 に句読点や話者分離の後処理を足したもの)
  • カスタム語彙 (0.9.4 の words 系の指定も、0.10.0 の keywords 系の指定も)
  • バッチをまとめた処理
  • 公式のコード (Haas-ASR・Linux) での速さと出力、transcribe_longform での長い録音の区切り方
  • モデルカードが挙げる限界 (フィラーの省略・出力の書き方など)

まとめ

Windows で faster-whisper の large-v3 や large-v3-turbo を使っていて、短い発話の単位で文字にしているなら、FLEURS で比べた範囲では Haas-ja-v1.0 に替えると誤り率と処理時間の両方が下がった。動かすのは speech.cpp で、この GGUF は Ollama や LM Studio では読めない。GPU を使わず CPU だけで動かしても、誤り率の差は小さかった (速さは Core i7-14700F で speech.cpp 0.9.4 を動かして測った値で、CPU だけの計測は 0.10.0 では行っていない)。

量子化は、測った F16 と Q4_K のどちらも、RTX 5080 と Core i7-14700F のこの PC と FLEURS の範囲では、名前だけで取ってくる Q8_0 より CER strict や速さが良くなる結果にはならなかった。Q6_K と Q5_K は測っていない。GPU 全体の使用量の増分をさらに抑えたいときは Q4_K が候補になり、CER strict のわずかな上昇と引き換えになる。speech.cpp 0.9.4 では、デコードの置き場所も既定のまま (Q8_0 は CPU) が速かった。

この記事では、長い音声を speech.cpp の --vad で区間ごとに処理した。この処理では、ほかより極端に音量の小さい発話が区間の検出から外れ、内容が出力に残らないまま抜けることがある。この30分の合成音声 (speech.cpp 0.9.4 で処理し、0.10.0 では測っていない) では、CER strict が Haas-ja-v1.0 で 11.72%、区間の検出なしの large-v3-turbo で 10.81% で、誤り率の面で替える利点は確かめられなかった。区間の検出なしの large-v3 と、vad_filter を付けた Whisper は、どれも Haas-ja-v1.0 より誤り率が高かった。処理時間は Haas-ja-v1.0 のほうが短かったが、計時の範囲が違うので何倍とは言えない。会議などの実際の録音では測っていない。Haas-ja-v1.0 の --vad でも Whisper でも抜けや削除が残るので、抜けがないかを確かめる手間を含めて使い方を決めることになる。

参考資料

タイトルとURLをコピーしました