開発ブログ

BLOG

「ヘイ Friko」の呼びかけを聞き分けるモデルを、自分で学習させた

「ヘイ Friko」と呼びかけたときだけ反応するよう、openWakeWord の上で聞き分けの分類器を自分で学習させた。Gemini TTS で学習用の声を作ったこと、YouTube の音声を集めたデータセット YODAS で、話し声への誤った反応を 1 時間あたり 79 回から 3.8 回に減らしたこと、効かなかったことを書く。

公開 2026年10月12日

Metronome.fm の声の操作を、合言葉で始められるようにしました。パソコンのブラウザで、メニューの「「ヘイ Friko」で声の操作」をオンにすると使えます(試験的)。「ヘイ Friko」と呼びかけるとピコンと鳴り、そのあとに「テンポ 120」などと頼めます。英語の「Hey Friko」にも、同じモデルで反応します。Friko(フリコ)は Metronome.fm のマスコットキャラクターで、名前はメトロノームの振り子から付けました(マスコットの記事)。

合言葉を聞き分けるには、マイクをずっと開いておく必要があります。練習中の音をずっと端末の外へ送るわけにはいかないので、端末の中で動く小さなモデルを作りました。この記事では、学習に使うデータの集め方と、効いたこと・効かなかったことを書きます。ブラウザで動かす話は「ヘイ Friko」を聞き分けるモデルを、画面を固めずにブラウザで動かすに、合言葉のあとの頼みを読み替える話は声の頼みを Jev で操作に変え、練習中の独り言には反応させないに書きました。

openWakeWord をもとに、分類器だけを学習させた

合言葉の聞き分けには、既製の仕組みを 2 つ比べました。

  • Picovoice Porcupine: 好きな合言葉をすぐ作れて、日本語にも対応しています。ただ、2026 年 6 月 30 日で無料枠が終わり、企業向けの契約だけになったようです
  • openWakeWord: 音をメルスペクトログラムにし、Google の音声の埋め込みモデルに通し、最後に合言葉ごとの小さな分類器で判定します。前の 2 段のモデル(メルスペクトログラムへの変換と埋め込み)のライセンスは Apache 2.0 です

openWakeWord を選び、最後の分類器だけを自分で学習させることにしました。ただ、公式の学習済みの分類器は CC BY-NC-SA(非商用)です。openWakeWord の学習の手順で標準として使われる否定データ(反応してはいけない例として学習に使う、合言葉でない音の特徴。17GB)も、出どころによって CC BY 4.0 とも CC BY-NC-SA 4.0 とも書かれていて、どちらが正しいか確かめられませんでした。Metronome.fm には有料のプランがあるので、どちらも使わず、利用条件のはっきりしたデータだけで分類器を学習させました。

分類器は、埋め込みのモデルが出した 16 フレーム分(約 1.3 秒)の特徴を受け取り、「いま合言葉を言い終えた」確率を返す全結合のネットワークです。openWakeWord の学習のスクリプトは、古い依存(acoustics・torchaudio.info)が今の環境で動かなかったので、特徴を計算する部分だけを使い、音の加工(次の節)と学習の部分は自分で書き直しました。

声は Gemini TTS で作った

「ヘイ Friko」は新しい言葉なので、録音されたデータはどこにもありません。合言葉の声は、Gemini TTS(gemini-3.8-flash-tts)で合成しました。

  • 30 種類の声に、日本語 12 通り・英語 6 通りの話し方(小声・早口・眠そう・遠くから呼ぶ など)で言わせる。英語の「Hey Friko」も同じモデルで覚えさせる
  • 1 回の呼び出しで 8〜16 回続けて言わせ、無音の位置で切り分ける。前後の 2 回がつながって切れなかったものは捨てる
  • 切り分けた合言葉は Whisper で文字に起こし、「へい」と「ふりこ」の両方が聞こえたものだけを使う(485 個のうち 366 個)

反応してはいけない例として、紛らわしい言葉(「振り子」「フリコ」だけ・「ヘイシリ」・「hey Rico」など)と練習中の独り言も、合言葉と同じ声で作りました。違う声で作ると、モデルが「合成音声なら合言葉」と覚えてしまうおそれがあるためです。

呼び出しは 152 回で、多く見積もっても $0.7 ほどでした。困ったのは料金ではなく呼び出しの上限で、Gemini API の Tier 1 の枠では 1 日 100 回までしか呼べません。軽い版(gemini-3.8-flash-lite-tts)の上限は別に数えられていたので、両方を使いました。

作った声は加工してから学習に使いました。Metronome.fm のクリック音・部屋の残響(データセット RIRS_NOISES)・雑音を重ね、速さ・高さ・音量・帯域を変えています。合言葉は、2 秒に切った音の終わり近くで言い終わるように置きます。なお、特徴の計算は CPU でリアルタイムの 87 倍ほどの速さだったので、GPU は使っていません。

物差しは、本物の人の声で 3 つ用意した

合成音声だけで測っても、本物の人の声で通用するかはわかりません。そこで、評価用の声を自分で録るための Web ページを作り、3 種類の物差しを用意しました。

録音のページの単発の欄。番号 1 の枠が、画面に出る言葉「ヘイフリコ」と条件の表示、番号 2 の枠が録音のボタンを囲んでいる
評価用の声を録るページ
  1. 言う言葉と、録る条件(静か・クリックあり・楽器あり)
  2. スペースキーで 2.5 秒録る
  • 単発の録音: 静かな部屋・クリックを鳴らしながら・楽器を弾きながら、の 3 つの条件で、合言葉と紛らわしい言葉を 1 回 2.5 秒ずつ録ったもの
  • 通しの録音: クリックを鳴らし、ギター・ピアノを弾き、BGM とナレーションを流しながら 305 秒続けて録ったもの。合言葉は 33 回言い、言い終えた時刻をそのつどキーで記録した
  • YouTube の日本語の動画 4 時間: YouTube の音声のデータセット YODAS(後の節で書きます)から、学習に使わずに取っておいたもの。合言葉を言っていない音なので、1 時間あたりに何回誤って反応するかを数える

自分の録音は測るためだけに使い、学習には混ぜていません。混ぜると、学習に使った声で測ることになり、正しく測れなくなるためです。

最初のモデルは「フリコ」だけで反応した

最初のモデルは、合言葉にはよく反応しました(単発の録音で 92〜100%)。ところが、「フリコ」や「振り子」と言うだけでも、ほぼ毎回反応しました。モデルは「ヘイ+フリコ」ではなく、「フリコ」という音を覚えていました。

まず、紛らわしい言葉の声を増やしました。静かな部屋で紛らわしい言葉を言ったときに反応した割合は、60% から 33% に下がりました。

さらに効いたのは、学習用の合言葉から頭の 35〜55% を切り落とした音を、否定データに足すことでした。同じ声・同じ話し方で「フリコ」の部分だけが残るので、「ヘイ」に続くフリコだけが合言葉だとモデルに覚えさせることができます。反応した割合は 13% まで下がりました。

話し声には YODAS が効いた

残った誤った反応は、通しの録音の BGM とナレーションの区間に集まっていました。学習に使った音に、人が話し続けている音がほとんどなかったためです。YouTube の動画 4 時間で測ると、1 時間に 79 回誤って反応しました。

そこで学習に加えたのが、YODAS の第 2 版の YODAS2 です。CC ライセンスで公開された YouTube 動画の音声を集めたもので(ライセンスは CC BY 3.0)、ナレーション・解説・雑談・BGM 入りの声が多く入っています。日本語の部分から 20 時間分をダウンロードし、16 時間を学習の背景の音に使い、4 時間を評価用に取っておきました。

YODAS には動画ごとに時刻つきの文字起こしがあります。それを使って「振り子」などが出てくる区間を探し、本物の人が話す紛らわしい言葉としても切り出しました。ただ、日本語の全体(278GB 分)を探しても 54 区間しか見つからなかったので、そうした区間が多く見つかったファイル 4 個(話し声 40 時間)を、まとめて学習に足しています。

YODAS を入れる前
16 時間を入れた
56 時間(16+40)と区間を入れ、3 つのモデルを平均した
YouTube の 4 時間: 1 時間あたりの誤った反応
79 回
8.1 回
3.8 回
同(境目を 0.95 にしたとき)
37 回
2.0 回
0.3 回
通しの録音: 合言葉に反応した割合
88%
85%
82%
単発: 静かな部屋で「振り子」などに反応した割合
13%
18%
7%

境目は、合言葉とみなす確率のしきい値です(アプリでは 0.5)。真ん中と右の列は、学習を 3 回ずつした平均です。右の列だけは、3 回の学習でできた 3 つのモデルの確率を平均して判定したもの(次の節)で測りました。

1 回の学習で判断しない

途中で気づいたのは、学習のたびのぶれの大きさです。同じデータで乱数の種だけを変えると、YouTube の 4 時間での誤った反応は 1 時間 6〜10 回と揺れました。最初に 1 回だけ学習させて 6 回と出たのは、たまたまよく出た 1 回でした。

それからは、作り方を変えたら種を変えて 3 回ずつ学習させ、平均で比べています。比べると、YODAS から切り出した区間を足した作り方は、「振り子」などへの反応が 3 回とも 7% で、足す前(13〜27%)より安定して低くなりました。その代わり、通しの録音で合言葉に反応した割合も 3 回とも少し下がっています(1 つずつのモデルの平均で 85% → 80%)。

3 つのモデルの確率を平均すると、ぶれが減り、誤った反応は 1 つずつのモデルの半分ほどになりました。ファイルの大きさは 1.25MB(1 つ約 400KB の 3 倍)になりますが、分類器は軽いので、判定にかかる計算はほとんど増えません。

効かなかったこと

  • 頭を切った音を 6 倍に増やし、紛らわしい言葉の重みを 3 倍にする: 自分の声の「振り子」には効かず、通しの録音で合言葉に反応した割合も下がりました
  • 自分の声の「振り子」などを学習に入れる: 測るための録音を、試しに学習にも入れてみました。録った 42 回の半分(21 回)を入れても、ほとんど変わりませんでした。数千個の合成音声に埋もれてしまいます
  • 声の登録: 自分の合言葉を 22 回登録し、元のモデルが反応したときだけ「この人の声か」をロジスティック回帰で判定する方法です。紛らわしい言葉への反応は 10% ほどから 3% に下がりましたが、通しの録音で合言葉に反応した割合が 88% から 73% に下がりました。選んで使える機能にする余地はありますが、今は見送っています

このあと

話し声への誤った反応は、境目を 0.95 にすれば 1 時間に 1 回を下回るところまで来ました。ただ、その境目で通しの録音の合言葉にどれだけ反応するかは、まだ測っていません。「振り子」などへの反応を減らすには、本物の人が話す紛らわしい言葉がもっと要ります。次は、家族や知り合いに録ってもらうつもりです。

この記事を共有

X でポストはてなブックマーク