CPUで動くストリーミング音声認識:デスクトップアプリにNVIDIA Nemotronを組み込む
ローカルWebSocket上のキャッシュ対応モデルで、GPUもクラウドも使わず、話すそばから文字を表示するOpenWhispr。その信頼性を支える実装を解説します。
OpenWhispr
エンジニアリング
目次
ストリーミング音声認識は、録音終了を待たずに話している最中の音声を文字にします。バージョン1.7.6以降のOpenWhisprでは、すべてがデバイス上で完結します。NVIDIAのNemotronストリーミングモデル(600Mパラメータ、INT8量子化)がローカルのsherpa-onnx WebSocketサーバーを介してCPU上で動き、部分結果の到着に合わせてプレビューを更新し、停止した瞬間にストリームの文字列を文字起こしとして確定します。 GPUもPython環境も不要で、音声が端末外へ出ることもありません。
この記事は実装の記録です。旧プレビューが遅く感じられた理由、キャッシュ対応ストリーミングの意味、Electronアプリ内のパイプライン、誤デコードを招いたバージョン固定の不具合、録音ごとの再デコードからストリーム自体の確定へ移行した経緯を説明します。モデル同士の比較は Parakeet vs Whisper vs Nemotronをご覧ください。
最終更新:2026年7月18日。実装の説明はOpenWhispr 1.7.6で公開したストリーミング文字起こし機能に基づき、すべてオープンソースのリポジトリで確認できます。
一次資料による要点確認
- Nemotronのcache-aware FastConformerはキャッシュ済みエンコーダー文脈を再利用し、新しい音声だけを処理します。 チャンクサイズは実行時に80msから1.12sまで設定できます。 Nemotron Streaming ENモデルカード · キャッシュ対応ストリーミングについてのNVIDIA記事
- 英語モデルは1.12sチャンクのストリーミングで平均6.93% WERです。 多言語3.5モデルは自動判定付きで40の言語・地域組み合わせを扱います。 Nemotron 3.5 ASRモデルカード
- 推論はすべて、Python依存のないネイティブONNXランタイムsherpa-onnxで実行します。 online(ストリーミング)WebSocketサーバーを使い、バージョン1.13.4を固定して同梱しています。 GitHubのsherpa-onnx
- INT8 ONNX形式のディスク容量は英語632MB、多言語650MBです。 一度ダウンロードし、ローカルにキャッシュします。 OpenWhisprモデルレジストリ(オープンソース) · OpenWhisprモデルページ
問題:バッチモデルで作ったライブプレビュー
OpenWhisprには以前から、音声入力中にモデルの認識内容を示す小さな文字起こしプレビューがありました。1.7.6以前は、バッチモデルをライブに見せる唯一の方法を採用していました。マイク音声を約1.5秒ため、そのチャンクを丸ごと文字起こしし、文字を追加して繰り返す方式です。
この方式には構造上の問題が3つあります。第一に遅延。バッファが満ちるまで文字は出ず、推論時間に加えて常に1.5秒遅れます。第二に境界。2チャンクにまたがる単語は分断され、各チャンクを別々に処理するため修正できません。第三に文脈。5番目のチャンクは4番目を知らず、同じ曖昧さを1.5秒ごとに解き直します。
チャンクを短くすれば速く見えますが、文脈が減り境界が増えて精度が落ちます。重ねれば境界は補えますが、同じ音声を二度処理します。必要なのはストリームの文字起こし用に訓練されたモデルです。それがNemotronです。
キャッシュ対応ストリーミングの実際
キャッシュ対応ストリーミングモデルはチャンク間で内部状態を保持します。 次の音声が届いてもエンコーダーは全発話を読み直さず、新しいフレームだけを処理し、計算済み文脈のキャッシュを参照します。チャットボットを高速化するKVキャッシュを音声エンコーダーに応用した仕組みです。
結果は2つあります。計算量が録音時間に比例しなくなり、10秒後も10分後も各チャンクのコストは同じなのでCPUだけで動かせます。また文脈が引き継がれ、モデルはそれまでの発話全体から曖昧さを解き、後の音声が手掛かりを与えると前の単語を修正します。文字が発話後に少し「落ち着く」のは不具合ではなく、より良い根拠による更新です。
遅延は固定値ではなく設定です。Nemotronは80ms(最速、1ステップの文脈は最少)から1.12s(最高精度。leaderboardデータセットで平均6.93% WER、最良のバッチモデルと約1ポイント差)まで対応します。訓練にはNVIDIAのcache-aware FastConformerとtransducerデコーダーを使い、同社の 技術記事 が理論を詳しく説明しています。
OpenWhispr内部のアーキテクチャ
OpenWhispr のライブストリーミング経路
- •One persistent stream for the whole recording — the encoder cache carries context across chunks.
- •Everything is on-device: the WebSocket server is a local sherpa-onnx binary, not a cloud endpoint.
- •A clean flush at stop commits the streamed text as the final transcript; anything less falls back to a full re-decode.
パイプラインは意図的に単純です。AudioWorkletが16kHzのマイクPCMを取得し、フレームをfloat32形式に変換してWebSocket経由でsherpa-onnxのonlineサーバーへ送ります。これはOpenWhisprがローカルで起動し、録音ごとに1本の持続接続を127.0.0.1へ張るネイティブバイナリです。サーバーはINT8重みのNemotronを実行してJSON部分結果を返し、プレビューは追記ではなく全文置換で表示します。
なぜプロセス内推論ではなく別サーバーなのでしょうか。理由は分離です。ネイティブランタイムは落ちる可能性があり、ONNXカーネルのメモリ確保失敗でアプリ全体を終了させるべきではありません。補助プロセスなら障害は再接続で済み、音声入力を失いません。Electronのメインプロセスからネイティブコードも排除でき、アプリはプロトコルを話し、補助側が計算します。
同じ構成で ローカル話者ダイアライゼーション も動きます。1つのsherpa-onnxツールチェーンで複数の処理をデバイス上に収めています。
実装中に壊れたもの
ランタイムのバージョンは予想以上に重要でした。 Nemotronを正しくデコードするにはsherpa-onnx 1.13.4以降が必要です。Parakeet向けの古いランタイムでは明確なエラーにならず、誤った文字起こしを返しました。修正は各プラットフォームのバイナリを更新し再固定するだけでしたが、教訓は一般的です。「動く」と「正しい」は別のテストで、重要なのは後者です。
ストリームは失敗するため、旧経路を残しました。 ポート使用中、モデルファイル欠落、録音中のサーバー停止は起こり得ます。持続ストリームを開始できない場合、プレビューは自動でバッファ式チャンクへ戻ります。遅くても空にはなりません。offlineモデル(Parakeet、Whisper)は設計上この方式を使い、レジストリのonline/offline指定に応じてアプリが経路を選びます。
部分結果には別の描画方法が必要でした。 チャンク方式は文字を追記しますが、ストリーミング仮説は改訂されるため、UIは部分結果ごとにプレビュー全体を置き換えます。改訂中の仮説を追記すると重複が連続します。これは初期に直した実際のUX不具合でした。
ストリームを確定する:2パスから1パスへ
最初の版ではストリーミングを成果物ではなくプレビューとして扱い、停止後に録音全体を最初から再デコードして、その結果を貼り付けていました。最終処理は全コンテキストを見られるので安全ですが、毎回2回のデコードが必要で、画面上でほぼ確定した文字を見た後に、ほぼ同じ第二案を待つことになります。
同じリリースでストリームを正本にしました。プレビューの表示に関係なく音声入力は持続接続を通り、停止時にモデル末尾をフラッシュしてストリーム文字列を直接確定します。二度目のデコードはありません。終了時の遅延は1回の末尾処理だけになり、音声入力1回あたりのCPU負荷はおよそ半分です。
安全策は廃止せずフォールバックにしました。終了処理は欠落を検知し、結果が届く間は期限を延長します。接続切れや結果の欠落があればストリームを捨て、録音全体を従来どおり録音後に文字起こしします。高速経路は正しい場合にしか使いません。
性能とリソース使用量
- モデル: Nemotron Speech Streaming EN 0.6B(632MB)とNemotron 3.5 ASR Streaming 0.6B(650MB、文字起こし対応15言語、自動判定)。INT8 ONNXを一度ダウンロードし、ローカルにキャッシュします。
- ランタイム: 自己完結型ネイティブバイナリのsherpa-onnx 1.13.4。Python、PyTorch、CUDAは不要です。
- ハードウェア: 最新ノートPCのCPUでリアルタイム動作し、Apple Siliconも新しいx86も発話速度に余裕で追従します。
- 体感: 部分文字列は発話から1秒を大きく下回る遅延で届き、停止時は1回の末尾処理で確定します。再デコードはありません。
この経路はインターネットに接続しません。アプリは127.0.0.1でサーバーと通信し(Windowsでは限定したファイアウォール規則でネットワークからもポートを閉鎖)、モデルはローカルキャッシュに置かれ、音声は端末外へ出ません。これは ローカル文字起こし基盤全体と同じプライバシー方針です。
率直な制約
- ストリーミングは即時性と引き換えに精度が少し下がります。 同じベンチマークでストリーミングは~6.9%、NVIDIA最高の英語バッチモデルは5.91%です。確定文もストリーム由来になったため、これは実際の選択です。最終結果だけを重視するならofflineのParakeetが高精度です。
- 対応言語はWhisperより少数です。 多言語モデルの文字起こし対応は15言語、Whisperは99言語です。中国語やタイ語のストリーミングはまだありません。
- 部分文字列は動きます。 文脈に応じて仮説が改訂されます。確定していく様子は利点だと考えていますが、気になる場合はプレビューを無効にして従来どおり使えます。
- ディスクをさらに650MB使用します offlineモデルをすでに持っている場合でも、別の仕事向けに調整した2つ目のエンジンが必要になるためです。
OpenWhisprでモデルを選ぶ
| 目的 | 選択 |
|---|---|
| 英語の音声入力をライブ表示 | Nemotron Speech Streaming EN 0.6B |
| スペイン語、日本語、アラビア語、ヒンディー語などをライブ表示 | Nemotron 3.5 ASR Streaming 0.6B |
| ライブ表示より英語の最大精度 | Parakeet Unified EN 0.6B |
| NVIDIAの対象外の言語 | Whisper (turbo または large) |
すべて設定のドロップダウンで選べます。容量とトレードオフを含む一覧は モデルページをご覧ください。OpenWhisprは無料のオープンソースで、macOS、Windows、Linuxに対応しています。
よくある質問
ストリーミング音声認識とは何ですか?
ストリーミング(online)音声認識は、話し終わる前から音声を文字にし、通常80ミリ秒から約1秒という一定の遅延内で部分結果を返します。Whisperのようなバッチ(offline)モデルは録音終了後に全体を一括処理します。ライブ字幕、音声エージェント、話すそばから文字が出る音声入力プレビューを可能にするのがストリーミングです。
GPUなしでストリーミング音声認識をローカル実行できますか?
はい。NVIDIAのNemotronストリーミングモデルは600Mパラメータで、約650MBのINT8量子化ONNXファイルとして提供されます。PythonやPyTorchを必要としないネイティブバイナリのsherpa-onnxを使い、最新のCPUでリアルタイム動作します。OpenWhisprはmacOS、Windows、Linux向けにこの構成を同梱しています。
キャッシュ対応ストリーミングASRとは何ですか?
NVIDIAのcache-aware FastConformerという構成で、音声チャンクをまたいでエンコーダーの内部状態を保持します。重複する音声窓を再エンコードせず、新しいチャンクを一度だけ処理し、それまでのキャッシュ済みコンテキストを利用します。これにより、低遅延ストリーミングをノートPCのCPUでも動かせます。
ライブプレビューの文字が表示後に変わるのはなぜですか?
ストリーミングモデルは音声が増えるたびに仮説を見直します。単語境界や同音語は後の文脈で初めて確定することがあるため、部分結果はその場で置き換わります。これは仕様です。停止するとOpenWhisprはモデル末尾をフラッシュし、確定したストリーム文字列を文字起こしとして採用します。フラッシュが中断または欠落した場合は録音全体を自動で再デコードするため、不安定な結果が貼り付けられることはありません。
ストリーミング文字起こしはバッチ処理より不正確ですか?
わずかに低くなります。ストリーミングモデルには未来の音声が見えないためです。Nemotronの英語ストリーミングモデルは、Open ASR Leaderboardのデータセットで1.12秒チャンク使用時に平均6.93%の単語誤り率です。バッチモデルにかなり近い一方、NVIDIA最高の英語バッチモデルの5.91%には届きません。ライブ文字と停止直後の確定を得る代わりの小さな差であり、最大精度が優先ならofflineのParakeetを選べます。
OpenWhisprのストリーミングはどの言語に対応しますか?
Nemotronは英語専用モデルと、15の文字起こし対応言語(英語、スペイン語、フランス語、イタリア語、ポルトガル語、オランダ語、ドイツ語、トルコ語、ロシア語、アラビア語、ヒンディー語、日本語、韓国語、ベトナム語、ウクライナ語)を自動判定するNemotron 3.5の2種類です。ParakeetやWhisperなどのofflineモデルは対応言語が多いものの、ライブストリームではなくバッファ済みチャンクでプレビューします。