Whistle: 16.9 MB の音声認識 — そして誰もラベルを付けなかったベンチマークの棒
- 16.9 MB の中に実際に何が入っているのか、そして 9 倍というサイズの見出しのうち、どの部分がアーキテクチャで、どの部分が比較で固定されていない量子化の選択なのかを理解する
- ベンダー自身の WER のグラフを、決してラベルを付けない競合の棒も含めて読む: Whistle は直接対決 8 つのうち 5 つに勝ち、現実に最も近い 3 つに負ける
- 30 秒がなぜ設定ではなくエンコーダー内の壁なのかを知り、それが強いる VAD によるセグメンテーションを作る
- ローンチの議論が存在しないと結論づけたストリーミング API を見つけ、その実際のレイテンシが 11.1 ms の最初のトークンまでの時間ではない理由を理解する
- キーワードバイアスを、ちょっとした便利機能ではなく主要な精度のてことして使う — 閉じた語彙では 41% と 96% の差になる
- 自分の音声について、Whistle、Whisper、Parakeet、クラウド API のどれにするかを決める
2026 年 10 月 8 日、「Whistle: Speech to Text in 16.9 MB」 というタイトルのブログ記事が Hacker News で 768 ポイントに達しました。 タイトルの数字が売り込みのすべてで、それは事実です。多言語の音声認識モデル全体が 16.9 MB の単一ファイルで、 GPU も依存関係もなく CPU 上で動きます。
続いた議論はきれいに二分されました。ベンチマークのグラフを読んだ人は感心しました。マイクを向けた人は そうではありませんでした — あるテスターは 170 発話のうち 70 だけが正解だったと報告しています。どちらのグループも 正しく、その両方が正しい理由は、ベンダー自身のグラフに印刷されています。ただ、数字の付いていない棒の中にあるだけです。
一文でまとめると
Whistle は、小さなエンコーダー・デコーダー型の ASR モデルを 2〜4 ビットに量子化し、フロントエンドを 250〜3500 Hz に帯域制限することでサイズを買っています。 近接マイクの単一話者の音声 — Whisper base に確かに勝つ領域 — ではほとんど何も失わず、遠距離、重なり合い、あるいは訛りのある音声では多くを失い、 そこでは自身の比較の 3 つのモデルのうち最悪です。
16.9 MB の中身
| コンポーネント | 詳細 |
|---|---|
| フロントエンド | 25 ms ウィンドウ、10 ms ホップ、80 のログメルビン、250〜3500 Hz に帯域制限 |
| ステム | 128 チャンネルの畳み込み、80 ms ごとに 1 フレームにダウンサンプリング |
| エンコーダー | Simple Attention ブロック 8 個、Monarch Hadamard MLP |
| デコーダー | はしご状の Simple Attention ブロック 8 個、幅 512、クエリヘッド 8 に対して KV ヘッド 2 |
| 語彙 | 8,192 のテキストピースと 7 つの言語トークン |
| 出力の上限 | クリップあたり 320 トークン |
| 入力の上限 | 480,000 サンプル — 16 kHz モノラルで 30 秒 |
| コンテナ | .cact、Cactus Quants、2〜4 ビット |
| ライセンス | Apache-2.0 |
そのうち 3 行は他より重要な役割を担っており、2 つは人が読み飛ばすものです。
9 倍というサイズの見出しは、精度を固定していない
誰もが引用する比較は、16.9 MB 対 Whisper base の 145.3 MB です。 9 分の 1 のサイズですが、ベンダー自身の脚注には、Whistle は 2〜4 ビットで測定されているのに対し、Whisper は CPU 上のメモリで fp32 とあります。 アーキテクチャ上の判断が一つも入る前に、重みあたりのビット数で 8〜16 倍離れています。
同じグラフにある、公平に比べられる行は、int8 で 41.9 MB の Moonshine tiny v2 です。Whistle はそれより 2.5 倍小さく、9 倍ではありません。 残りの 2.5 倍は本物で、アーキテクチャが実力を示すところですが、9 倍という数字を繰り返すなら、 それは主に量子化の選択を繰り返しているのです。
これはAI ベンチマークに騙されずに読む方法で扱った罠と同じです。 数字が間違っているのではなく、比較の条件が揃っていないのです。
3500 Hz への帯域制限は、予測できる種類の誤りを生む設計判断
フロントエンドは 250〜3500 Hz を残し、それ以外を捨てます。およそ電話の帯域で、ウェアラブルで動かすことを想定したモデルには 賢明な選択です — 音声のエネルギーの大半はそれ以下にあります。
大半であって、すべてではありません。音響音声学の文献は、ここについて具体的です。3〜4 kHz は母音が聞き取れる帯域としては十分ですが、
ほとんどの無声摩擦音には足りません。それらのスペクトルは 4 kHz より上に集中しています。英語の s はおよそ 5〜10 kHz の範囲にエネルギーが最も集中し、
ピークは約 8 kHz付近 — Whistle のカットオフの 2 倍以上 — で、sh は 4 kHz 付近を中心に 8 kHz までエネルギーが広がります。
3500 Hz で切っても、それらの音が聞こえなくなるわけではありません。それらを互いに最もきれいに区別する帯域が取り除かれるのです。
したがって、テストを 1 回も実行する前に、誤りの種類を予測できます。摩擦音での混同と語尾の脱落で、 リズムや訛りのせいでそれらの子音に補うための長さが与えられない話者で最も悪くなります。ローンチのスレッドでの現場の報告 — 「存在しない単語とひどい タイプミス」のスペイン語出力、検出されないメキシコ人とベネズエラ人のアクセント、強い訛りで急激に劣化する — は、その予測が予定どおりに届いたものです。
誰もラベルを付けなかったベンチマークの棒
このページが価値を持つのはここです。Whistle のグラフは、3 つのモデルについて 9 つのテストセットにわたる単語誤り率を描いています。 Whistle のすべての棒には数字が印刷され、他のものには一つも印刷されていません。
それでも棒はそこにあり、線形のスケールで描かれています。Whistle の印刷されたラベルがそのスケールを正確に較正しています — WER 1 ポイントあたり 6.867 ピクセルで、 9 つすべてにわたって ±0.01 で一貫しています — ので、競合の値は棒の高さから復元できます。 そうすると、グラフがあと一歩のところで見せてくれない表ができます。
| テストセット | 内容 | Whistle | Whisper base ≈ | Moonshine tiny v2 ≈ |
|---|---|---|---|---|
| LibriSpeech test-clean | 朗読された audiobook、クリーン | 4.31 | 4.89 | 4.51 |
| LibriSpeech test-other | 朗読された audiobook、より難しい | 10.49 | 11.00 | 11.71 |
| SPGISpeech | 金融の電話会議 | 7.65 | — | 7.70 |
| Earnings-22 | 決算説明会、訛りあり | 19.01 | — | 21.25 |
| AMI | 会議、遠距離、重なり合い | 26.07 | 21.50 | 22.78 |
| AMI cleaned | 同上、クリーンにした参照 | 22.87 | — | — |
| TED-LIUM | カンファレンスの講演 | 7.61 | 4.99 | 5.64 |
| FLEURS | 多言語の朗読音声 | 21.39 | 24.50 | — |
| MLS | 多言語の audiobook | 24.90 | 23.10 | — |
低いほど良く、太字は各行の勝者です。Whistle の列はベンダーが印刷した数値です。他の 2 つの列はグラフの棒から読み取ったもので — ベンダーはこれらが Whisper と Moonshine 自身の公開された数字だと述べつつ、印刷はしていません。
Whistle は、比較が存在する 8 行のうち 5 行で勝っています。 最も近い精度の競合より 2.5 倍小さいモデルとしては本物の成果で、 FLEURS の行 — 多言語の朗読音声で Whisper base より 3.1 ポイント良い — は、グラフで最も印象的なものです。
では、負けているものを見ましょう。
- AMI は、Whisper base に 4.57 ポイント差で負け。 遠距離マイク、複数の話者、重なり、割り込み。ここで Whistle は単に遅れているだけでなく、 3 つのうち最悪で、自分の 8.6 倍の大きさのモデルに負けています。
- TED-LIUM は 2.62 ポイント差で負け。 話者は 1 人ですが、大きな部屋、ステージのマイク、台本のない話し方です。
- MLS は 1.80 ポイント差で負け。 多言語の長尺で、英語以外の 6 言語にわたる平均です。
数字を並べて見れば、パターンは微妙ではありません。Whistle が勝つ行はすべて、近接マイクで実質的に単一話者です。負ける行は、 口とマイクの間に距離があるか、部屋に 2 人以上いるかのどちらかです。 朗読された audiobook やディクテーションの音声は、 16 kHz に帯域制限されたフロントエンドと小さなエンコーダーがうまく扱えるプロファイルそのものです。 残響と重なり合う話者は、それをほどく容量を持つ余裕がないものそのものです。
その一文が、ローンチのスレッドの二つの半分を調停します。顔の近くに持った電話にディクテーションを試した人は、皆気に入りました。 映画のクリップや会議や部屋に向けた人は、皆気に入りませんでした。誰も測り方を間違えていません。
4.31 と 26.07 は、同じ重みの同じモデルです。Whistle の WER を一つだけ覚えるなら、見出しの数字ではなく幅を覚えてください。
70/170 の報告について
スレッドで最も引用された現場の結果 — 170 問中 70 問の正解、はるかに大きな Qwen ASR モデルの 168/170 に対して — は本物の測定ですが、 閉じた語彙での標準設定の測定です。同じテスターが、調整後には 164/170 と報告しました。何が変わったのかは次の節の主題で、 モデルカードで最も過小評価されている機能です。
キーワードバイアスが主要な精度のてこ
Whistle は、長さで正規化した対数確率でスコア付けされる 5 本のビームでデコードし、聞こえると予想される単語のリストを受け取って、 その探索のあいだそれらを優遇します。照合には Aho-Corasick オートマトンを使います。
汎用の ASR モデルでは、これは便利機能です。8,192 ピースの語彙を持つ 16.9 MB のモデルでは、荷重を支える部分に近いものです。 暗黙の言語モデルに割ける容量がごくわずかなので、固有名詞、製品名、地名、専門用語はまさにモデルが間違えるもので — そしてまさにキーワードのリストが直すものです。70/170 から 164/170 になるのは、同じ重みで 41% から 96% です。
Transcribe with the two arguments that matter
import needle r = needle.transcribe( "clip.wav", keywords=["Kubernetes", "Grafana", "Prometheus", "Aoife", "Nguyen"], word_timestamps=True, language="en", # skip detection when you already know ) print(r["text"]) for w in r["words"]: print(w["word"], w["start"], w["end"], w["probability"])
そのスニペットで、はっきり述べておく価値のある点が 3 つあります。
keywordsは後処理のフィルターではありません。 ビームサーチを変えるので、 デコーダーがそのままでは決して置かなかった単語を回収できます。language="en"は、レイテンシだけでなく失敗のモードを取り除きます。 短い、あるいはノイズの多いクリップで 7 言語にわたる自動検出を行うと、 うまくいかない要素がもう一つ増えます。アプリが言語を知っているなら、そう伝えてください。- すべての単語が自分の
probabilityを持っています。 それが信頼度のゲートです — 下の引き継ぎのパターンを参照してください。
- 長すぎるキーワードのリストはバイアスを薄め、誰も言っていない単語へデコーダーを引き寄せ始めます。この文脈でユーザーが実際に発する語彙 — 現在の画面、現在の連絡先リスト、現在のドキュメント — に絞り、製品用語集全体を入れないでください。
30 秒の壁は、設定ファイルではなくエンコーダーの中にある
16 kHz で 30 秒は 480,000 サンプルです。畳み込みのステムを経ると 80 ms ごとに 1 フレームなので、エンコーダーのフレームは 375 で、 デコーダーは 320 の出力トークンで頭打ちになります。これらは 16.9 MB のテンソルファイルの固定された形状です。 それを上げるフラグはなく、ローンチのスレッドで上限を超えて録音したテスターは、切り詰められた書き起こしではなく ランタイムエラーを受け取りました。
つまり、30 秒を超えるクリップでは、セグメンテーションはあなたの仕事になります — そしてセグメンテーションこそ長尺の ASR の精度が実際に決まるところです。 単語や節の途中で切れた箇所は、モデルが回復できない誤りだからです。
- 16 kHz モノラルは推奨ではなく、入力の契約です。44.1 kHz のステレオファイルは、モデルに届く前に変換が必要です。基本のインストールは 16 kHz の WAV と生のサンプルを扱い、[mic] extra がリサンプリングとマイクのキャプチャを追加します。
- 音声区間検出器を実行して、隙間で切ります。固定の 30 秒スライスはいずれ単語の途中で切れ、その誤りは書き起こしに永久に残ります。10〜25 秒のセグメントを目標にすると、長い最後の節のための余裕が残ります。
- 連続するパスに共有領域を持たせて、固いつなぎ目に頼る代わりに、一致するところで継ぎ合わせられるようにします。コストは 1 秒分の音声を再デコードすることで、毎秒 1,319 トークンのデコードではそれがボトルネックにはなりません。
- すべての単語が開始と終了を返すので、文字列の照合ではなく時間で重なり部分の重複を取り除きます。正当に繰り返された単語を落とさずに二重の単語を落とせる、唯一の確実な方法です。
- 各セグメントで単語ごとの確率を平均します。信頼度の低いセグメントが、より大きなモデルへ送るキューになります — デバイス上なら無料、デバイス外なら重要なときに。すべてを再実行しないでください。
無音は処理される。SNR の低い音声は処理されない
モデルカードは、具体的で歓迎すべき主張をしています。無音と定常的なノイズは、でっち上げた文ではなく空の書き起こしを返します。 無音検出がビームサーチの前に実行されるからです。これは Whisper の最も悪名高い失敗、つまり何もない ところに自信たっぷりに字幕を幻覚する問題への直接の修正です。
主張を正確に読んでください。対象は無音と定常的なノイズです。静かな、遠い、あるいは重なり合う音声は対象外で、スレッドにはまさにその失敗があります。 あるテスターは、実際の会話が流れているあいだ、モデルが 1 分以上にわたって「Thank you.」を繰り返し出力すると報告し、別のテスターは否定が反転する — 「can't handle」が「can handle」に — のに加え、単語がまるごとでっち上げられるのを見つけました。
これらは、「Thanks for watching」がテキストの大きな割合を占める、Web 動画の字幕で訓練したときの典型的なアーティファクトで、
ゲートがそれらを狙ったものではなかったため、無音のゲートをすり抜けます。脱落した n't でアプリケーションの動作が変わるなら、
単語ごとの確率のチェックは任意ではありません。
ストリーミングは存在する — ローンチのスレッドは存在しないと結論づけた
議論で繰り返された不満は、Whistle にはライブの書き起こしができない、というものでした。デモは話しているあいだ部分的なテキストを見せなかったからです。
デモがそうだっただけで、ライブラリはそうではありません。needle.stream(chunks) はライブのマイク入力を受け取り、
連続する重なり合ったパスが一致した単語を確定します。
そのポリシー — 重なり合ったウィンドウを繰り返しデコードし、2 回のパスが一致する接頭辞だけを出力する — は、ストリーミング ASR の LocalAgreement の系統であり、 それを知っていれば、スペックシートが教えてくれないことが分かります。
体感のレイテンシは、11.1 ms の最初のトークンまでの時間ではありません。 それは一致の遅延、つまり単語が、2 回目のパスで確認されるまでに待たされる時間です。 TTFT は、完全な 10 秒のクリップでのデコード速度の測定です。ストリーミングのループでは、ユーザーに見える数値はウィンドウのストライドと、 安定するまでどれだけ待つかで決まり、11 ではなく数百ミリ秒になります。
それでも速いことには変わりありません — 11.1 ms に対して Whisper base は 73.2 ms、Moonshine は 22.8 ms、デコードは毎秒 1,319 トークンに対して 266 と 262 で、 Apple M4 Pro の CPU で 10 秒の音声を測定したものです。ただし、プロダクトマネージャーに 11 ms のライブ字幕を約束してはいけません。
サイズよりも静かに興味深い 2 つの機能
デコーダーははしご状なので、1 つのファイルがファミリーになる
2 層以上のすべての深さがデプロイ可能なモデルで、ロード時に --audio-depth で選びます。16.9 MB の塊を一つダウンロードして、
精度とレイテンシのバランスをデバイス上で選べます。それを選ぶのに適切な場所です
— 腕時計と電話が、同じ成果物を異なる深さで動かせます。参考までに、
兄弟の Needle テキストモデルは Raspberry Pi 5 で、2 層でおよそ毎秒 4,000 トークン、20 層で 400 でデコードします。
embed() は、書き起こしなしで音声のマッチングを提供する
エンコーダーの出力は直接利用でき、80 ms フレームごとに 1 行を、needle.Whistle().embed(audio) で得られます。ウェイクワードの検出、コマンドのマッチング、
音声の重複排除、「この録音のどこで誰かがこれを言ったかを探す」が — テキストをデコードせず、言語モデルなしで、
上で述べた誤りの種類もなく — できます。綴りを求めることがないからです。
多くの組み込みの用途(「ユーザーはこの 11 のうちのどれかを言ったか?」)では、 これが正しい道具で、書き起こしは遠回りです。
Run it from the CLI, including the built-in three-way comparison
pip install cactus-needle # microphone playground needle whistle playground # put Whistle next to Whisper and Moonshine on YOUR audio needle whistle compare my-clip.wav # air-gapped / embedded: fetch a platform engine and the weights needle download macos-arm64 needle download whistle ./macos-arm64/needle --model whistle.cact --audio clip.wav --audio-word-timestamps
compare サブコマンドは特筆に値します。ベンダーが、自社の主張をあなたの音声に対して確認するツールを出荷しているのです。
上の WER の幅が収録条件にどれだけ強く依存するかを考えると、あなた自身の音声の代表的なクリップで実行する方が、
このページのどの表よりも価値があります。
コピーする価値のある再現性の性質
エンジンは環境変数を一切読みません。すべての挙動はコンパイル済みのデフォルトか、明示的なフラグです。つまり同じ塊と同じフラグなら、 どのマシンでも同じスコアになります。これはほとんどの推論スタックが主張できない性質で、先週の評価が退行したのか先週のシェルが退行したのかを 切り分けようとするときに、非常に重要です。
選ぶ: Whistle、Whisper、Parakeet、クラウド API
| あなたの状況 | 選択 | 理由 |
|---|---|---|
| 電話やウェアラブルでのディクテーション、近接マイク、オフライン、対応 7 言語 | Whistle | 設計の中心です。16.9 MB、GPU 不要、単語のタイムスタンプ付きで、まさにこの音声プロファイルで Whisper base に勝ちます |
| マイコンでのウェイクワードや固定のコマンドセット | Whistle embed() | 書き起こしを丸ごと飛ばして、エンコーダーのフレームをマッチさせる |
| 会議の録音、複数の話者、ルームマイク | Whistle ではない | 自身のグラフで AMI の最下位。フルサイズの Whisper、Parakeet、または話者分離付きのクラウド ASR を使う |
| 7 言語以外のあらゆる言語 | Whistle ではない | 英語、ドイツ語、フランス語、スペイン語、イタリア語、オランダ語、ポーランド語のみ。中国語はなく、ローンチのスレッドで最も要望の多かった追加です |
| GPU での英語で、オープンウェイトの秒あたり精度を最大に | Parakeet | NVIDIA の parakeet-tdt-0.6b-v2 がスレッドで実務者に人気でした。CC-BY-4.0 |
| どこにも送れない音声で、サイズより精度が重要 | Whisper large、ローカル | 今も精度の基準です。その代わりに約 100 倍のフットプリントを払います |
| 医療、法律、金融の公式な書き起こし | 人間が確認するクラウド ASR | 上の否定の反転という失敗モードだけで、不適格です |
ハイブリッドが通常は正解で、このサイトの他のあらゆるローカルとリモートの分割と同じ形です。小さなモデルをすべてに対して実行し、 単語ごとの確率をゲートに使い、不確かな部分をエスカレートします。一般的なパターンは Claude とローカルモデル、書き起こしの手順がそのなかのどこに属するかは プライベートなローカル AI スタックを参照してください。
これがオンデバイスの波全般について教えること
Whistle は、小さなモデルのあいだで今見られるパターンのよい実例です。 能力は本物で、動作範囲は狭く、見出しに収まるのは前半だけです。 2 ビット量子化はズルではなく モデルは本当に動きますが、難しい音声を扱うはずだった容量を使ってサイズを買っており、ベンダーのグラフは、その請求書がどこに届くかを正確に示しながら、 届かない行にしかラベルを付けていません。
実践的なルールは ASR を超えて一般化できます。小さなモデルが広いベンチマークの幅を公開しているなら、その幅が仕様そのものです。 最も悪い行を見つけ、そのテストセットに他にないものが何かを考え、 実際の入力がその行に似ているかを確認してください。Whistle の場合の答えは距離と重なり合いです。量子化された言語モデルでは、たいてい長いコンテキストです — 「98.2% の保持率」が隠すものを参照してください。
Check yourself
0/6情報源とさらなる読み物
- Cactus-Compute/whistle — Hugging Face のモデルカード — アーキテクチャ、入力の契約、API の引数、ベンチマークのグラフ、ライセンス、引用
- Whistle: Speech to Text in 16.9 MB — Cactus Compute のブログ — ローンチの投稿: ブロック構造、デコード戦略、ベンチマークの方法論、精度の脚注
- cactus-compute/needle — GitHub —
cactus-needleの Python パッケージとエンジンのソース。needle.stream()、transcribe()、embed()を含む - Cactus-Compute/needle3 — Hugging Face — 共有エンジンとプラットフォームごとのフォルダー(
needleバイナリ、libneedle.a、needle.h) - Needle supported devices — Cactus Compute — 13 のプラットフォームフォルダー、ランナーのフラグ、WASI コンポーネント、エアギャップ環境のセットアップ
- 「Whistle: Speech to Text in 16.9 MB」— Hacker News — 768 ポイント、153 コメント: 70/170 と 164/170 の報告、30 秒のランタイムエラー、訛りとスペイン語出力への不満、ループする「Thank you.」と否定の反転
- Robust Speech Recognition via Large-Scale Weak Supervision — Radford et al. (arXiv 2212.04356) — Whisper の論文。表 9、10、13 が Whistle のグラフにある Whisper の数値の出典
- Moonshine: Speech Recognition for Live Transcription and Voice Commands — Jeffries et al. (arXiv 2410.15608) — Moonshine の論文、表 3
- nvidia/parakeet-tdt-0.6b-v2 — Hugging Face — ローンチのスレッドで実務者に人気の、秒あたり精度の優等生、CC-BY-4.0
- Turning Whisper into Real-Time Transcription System — Macháček et al. (arXiv 2307.14743) —
needle.stream()が実装する LocalAgreement のストリーミングポリシーと、そのレイテンシが実際にどこから来るのか - Classification of Fricative Consonants for Speech Enhancement in Hearing Devices — PLOS ONE — 3〜4 kHz の帯域が母音には足りても、エネルギーが 4 kHz より上にある無声摩擦音には足りない理由
- The perceptual significance of high-frequency energy in the human voice — Monson et al., PMC — 帯域制限されたフロントエンドが捨てるものと、聞き手がそれで失うもの
次へ
- 全二重の音声 AI: 音声エージェントが突然現実になった理由 — ループのもう一方の半分: モデルが聞くと同時に話すと何が変わるのか、そして人間の会話の順番交代がレイテンシの予算を決める理由
- プライベートなローカル AI スタック — オフラインの書き起こしの手順が、自分のハードウェアで動かす他のすべてのなかでどこに属するのか
- 実践的な三値量子化: Bonsai 2 27B を 5.95 GB で — 一段上の階層での同じ教訓: 保持率のパーセンテージが隠すものと、標準のローダーが自信たっぷりのゴミを出しうる理由