ONNX/TFLiteモデルでオフライン音声制御

2026年10月 · ONNX · TFLite Micro · ESP32-S3 · ウェイクワード + コマンド

小さな固定キーワードモデルのセット——スマホ・ブラウザ・デスクトップには標準ONNX、マイコンにはINT8 TFLite——が、ウェイクワードと少数の音声コマンドを完全オフラインで待ち受けます。この記事では、この種のモデルがどんなときに適切なのか、同じモデルファイルが各プラットフォームをどう渡り歩くのかを説明し、最後に自分の言葉で再現できるESP32-S3デモの全手順をたどります。

どんなときにこの種のモデルが必要か

キーワードスポッティング(KWS)モデルが適するのは、語彙が固定かつ少数——ウェイクワード1つと高々数十のコマンド——で、製品が常時待受けしながら音声をどこにも送らない場合です。利用者が何でも話せる必要があれば完全なASRモデルが必要ですが、ASRは計算量も消費電力も一桁多く要求するため、ESP32クラスのマイコンやバッテリー製品では手が届かず、常時待受けは非現実的です。

固定キーワードKWS
(ONNX/TFLite)
オンデバイスASRクラウド音声アシスタント
語彙固定:ウェイクワード1 + コマンド2〜10オープンオープン
サイズ約100KBクラス数百MBローカルはゼロ、音声は端末外へ
ハードウェアMCU(ESP32-S3)からブラウザまでLinux系SBC / スマホマイクとネットワークのあるもの
ネットワーク不要不要必須
計算と電力MCU上でミリ秒クラス——常時待受けでも余裕、バッテリー製品でも耐えられる一桁多くCPU/RAM/電力が必要——常時待受けは非現実的ローカルは軽いが、無線とネットワークは常時消電
応答端末内で即時重め、端末依存往復レイテンシ
ランニングコストなし——モデルファイルは自分のもの計算/電力従量制またはサブスク
プライバシー音声は端末の外に出ないローカルに留まる音声をアップロード

具体的に、チームが固定キーワードモデルを選ぶのはこういう場面です:

いずれも語彙は固定であり、KWSのトレードオフを喜んで受け入れます:オープンな対話を諦める代わりに、小型・即時・プライベート・ランニングコストゼロを手に入れる。こうした固定語彙のKWSモデルが必要ですか?voicute.comで学習できます——日本語・英語・ドイツ語・フランス語・中国語対応。以下の手順で全工程をたどります。

ひとつのモデル形式で、すべてのプラットフォームへ

オープンソースのオープンソース推論エンジンとデモモデルを見る →パイプラインは、同じ学習から2つの形式を生成します:ONNXはONNX Runtimeを持つすべての環境へ、INT8 TFLiteはESP32-S3などのTFLite Microデバイスへ。推論パイプラインは3ファイルだけです:

音声 (16 kHz) → melspectrogram.onnx → embedding_model.onnx → your_word.onnx → 確率

同じリポジトリのオープンソースランタイムがこれらのファイルをAndroid(android/)、Web(web/、ブラウザ内ONNX)、Windows/Linux/macOSのPython(linux/)、ESP32-S3/P4(esp32/、TFLite)で読み込みます。Wyomingサイドカーで同じモデルをHome Assistantに接続できます。AccessKeyなし、クラウド推論なし、デバイスごとのランタイム料金なし——ダウンロードしたモデルファイルはあなたのものです。

実例:ESP32-S3上のウェイクワード + 音声コマンド

チェーン全体をエンドツーエンドで示すため、同じモデル群をこのリストの最小端で動かします。デモはパイプラインが生み出す2種類のモデルをちょうど組み合わせた構成です:単一キーワードのウェイクモデルが「Hallo Lumo」を担い、マルチキーワードモデルが後続の4つのコマンドを担当します。ボードはESP32-S3 HMI DevKit(デュアルコア240 MHz、8 MB PSRAM、ES7210マイクコーデック)、ESP-IDF 6.0.1。「Hallo Lumo」(ドイツ語のカスタムウェイクワード)と言うとLEDが点灯してウェイクを知らせ、6秒の窓内で「Licht rot / blau / grün / weiß」と言うとライトがその色に変わり、その後デバイスは待受けに戻ります。

このデモの実測値(1.5秒窓、INT8をESP-NNで高速化):Mel ≈ 47 ms + Invoke() ≈ 76 ms ≈ 1フレーム121 ms、160 msのホップに対してリアルタイム。静かな部屋と騒がしい部屋で20回以上のウェイク、4コマンドすべて認識、混同ゼロ。ウェイクモデルの誤検知はハードネガティブマイニングにより約319回/時から2.6回/時に低下(24時間のホールドアウト音声で実測)。推論時間はモデルにより異なるため、必ず自身のモデルで計測してください。

なぜ自前で学習するのか。Espressif純正のMultiNetはコマンドを中国語と英語しかサポートしません。ここでの2つのモデルは、Mel特徴から学習する独自パイプラインで訓練されており、同じ流れはどの言語でも機能します。ドイツ語なのは、このデモがドイツ語を話すように作られただけです。

自分のキーワードモデル——単一のウェイクワードでも、マルチキーワードのコマンドセットでも、5言語対応——を学習したいなら、それがvoicute.comの仕事です。以下、その全手順を順にたどります。

仕組み:2つの小さなモデルを時間分割

1つのデバイスが、コンパクトな2つのINT8 TFLiteモデルを同じコアで、互いに競合しないようスケジューリングして実行します:

  1. ウェイクモデル、常時稼働。ESP-SR AFEがオーディオフロントエンド(AEC、NS、VAD)を担い、ウェイクモデルが最新のMel窓を消費します。検出するとデバイスはモードを切り替えます。
  2. コマンドモデル、ウェイク後のみ。続く6秒間、2つ目のマルチキーワード分類器が発話を設定済みコマンド(ここでは4色)に対応させます。窓の終了後——またはコマンド実行後——デバイスはウェイクのみの待受けに戻ります。

このゲート構造こそが誤コマンドを抑えます:コマンドモデルは単独では決してリスンしません。誤検知の負担はすべてウェイクワード側が引き受けており、それはまさにパイプラインで最適化できる部分です(ステップ4)。

開発中の教訓:初代のウェイクモデルは推論1回あたり約250 msで、音声ホップより遅く、フレーズの一部を静かに取りこぼしていました。解決は常に最新の窓を処理し、推論がホップに収まるまでモデルを縮小すること。まず「推論 < ホップ」を確保してから他を考える、という順序です。

ステップ1 · デモモデルを自分で動かす(無料)

2つのデモモデルはGitHubにあり、登録不要です。最速の確認にハードウェアは不要——デスクトップのPythonランタイムが同じモデルファイルを読み込みます:

git clone https://github.com/voicute/onnx-wakeword.git
cd onnx-wakeword
pip install onnxruntime numpy sounddevice
python linux/infer.py --model-dir ./models/de/

組み込みのフルパスは実測済みのESP-IDFサンプルです:

cd onnx-wakeword/esp32/examples/esp32s3_hmi_devkit
idf.py set-target esp32s3
python patch_led_strip.py
idf.py build
idf.py -p COM6 flash monitor

Webランタイムは同じデモモデルをブラウザ内だけで実行できます——ハードウェアを触る前にキーワードの響きを確かめるのに便利です。

ステップ2 · 自分のウェイクワードを学習する(無料)

voicute.comでフレーズを入力し、言語を選択——日本語、英語、ドイツ語、フランス語、中国語に対応。学習すると最初のモデル(R0)が得られます:デスクトップ/モバイル/ブラウザ用の標準ONNX分類器と、ESP32-S3用の対応するINT8 TFLiteです。このステップは無料です。

ステップ3 · 自分の声でテストする(無料)

コンソールでBasicモデルを、自分のマイク・実際の距離・実際の背景騒音で試します。このステップがその後のすべてを決めるので、支払いの前にテストを:普段の話し方で、普段の使用距離から呼んでください。リコールが物足りなければ、そのフレーズの実声レコーディングを数本追加して再学習——録音は任意の学習入力で、これも無料です。

ステップ4 · 実測に応じて道を選ぶ

テストのあと、あなたは次の4つのどれかにいます:

  1. ときどき呼びかけに反応しない → 実声レコーディングを5本追加して再学習(無料)。リコール問題の大半はカバレッジの問題で、この段階で解決します。
  2. ウェイクは確実だが、テレビや会話で誤反応する → 誤検知最適化を実行(1回につき有料)——仕組みは次のセクションで。
  3. ウェイクワードだけでなく音声制御が欲しい → 2〜10個の固定コマンドを1ファイルに収めたマルチキーワードモデルを学習するか、ウェイクワードをやめてコマンドワードを直接トリガーにします。上のデモはまさにこの構成です。
  4. そのまま使える → モデルをダウンロード(一回払い)し、上のどのランタイムにも配置できます。

誤検知の制御:R0とR1、そしてハードネガティブマイニング

すべてのモデルはR0から始まります——準備した音声データと、ノイズ・残響・音量変化といった固定の妨害セットで学習した最初のモデルです。しかし現実の妨害はるかに多く、テレビ、音楽、背後の会話、広告……。しかも妨害は単語依存です:同じ広告音声が「Hallo Lumo」のモデルでは誤検知を起こしても、別の単語のモデルは完全に無反応、ということも起きます。学習直後のR0の誤検知が多いのはすべてのキーワードモデルに共通する性質で、学習が下手な証拠ではありません。

R1がこれを治します。コンソールの2つのボタンに対応する2ステップです:

  1. 負例スキャン。R0モデルに約100時間の対象言語ネガティブ音声を聞かせ、反応したクリップを抽出——これが定義上、このモデル固有のハードネガティブです(最大10,000件保持)。数分。
  2. 全量再学習。抽出クリップを負例として元の学習セットに加え、モデルを丸ごと再学習します。通常40〜80分。

負例がR0の実弱点に合わせて選ばれるため、1ラウンドで誤検知は平均して毎時数百回から一桁へ(約95%減)。このデモのウェイクワードでは、24時間のホールドアウト音声で319回/時 → 2.6回/時を実測しました。単一キーワードでもマルチキーワードでもこの流れをサポートします。デモの4色コマンドモデルも同じスキャン+再学習のループを通せます。R2パイプラインは将来の新たな妨害源のために用意されていますが、ほとんどのキーワードはR1の1ラウンドで日常使用に十分です。最適化は1回につき有料、現在の価格はvoicute.comをご覧ください。

ステップ5 · 実機で検証する

コンソールのテストがモデルを証明し、デバイスが製品を証明します。出荷前の3つのチェック:

FAQ

固定キーワードモデルが不向きなのはどんなとき?
語彙が固定していないとき。書き起こし、自由な質問などオープンな発話には完全なASRが必要——KWSモデルは設計上、学習した単語しか認識しません。
完全にオフラインで動きますか?
はい。ウェイクワードもコマンドもローカル動作。クラウド推論なし、実行時アカウントキーなし。
対応プラットフォームと言語は?
Android、Web、Python(Windows/Linux/macOS)、ESP32-S3/P4、加えてHome Assistant向けWyoming。モデルは日・英・独・仏・中に対応。
無料と有料の境界は?
学習とコンソールテストは無料。モデルファイルのダウンロードと誤検知最適化は有料——現在の価格はvoicute.comで。
無関係な会話でコマンドが誤動作することは?
ウェイク後6秒の窓内のみで、ゲートが大半を防ぎます。窓内の発話は現状まだ誤分類の可能性があり、キーワードのハードネガティブマイニングで改善できます。
開示:本文で参照したオープンソースランタイムとデモモデルはVoicuteが開発しており、ステップ2〜4で使うオンライン学習プラットフォームもVoicuteの製品です。
自分のウェイクワードを無料で学習・テストする
オープンソース推論エンジンとデモモデルを見る →
ONNX / TFLite · Android · ESP32 · Web · Python · Home Assistant