競馬チャンネルのコメント 4,495 件をJev と EmbeddingGemma2 で分類し直してみた
はじめに
YouTubeのライブ配信のコメントを「質問」「攻略」「指示」「雑談」などで振り分けるアプリ「LiveChatDashboard」を作っています(macOS / iPad)。今回はこれで記録したコメントを再分類するという計測を行いました。再分類の方法は以下の2点となります。
- Jev: TypeSafe AI のテキスト分類モデル。短い文を、こちらが渡した問い(カテゴリの説明文)に沿って分類する API として呼びます(今回は Cloudflare Workers AI 経由)。このアプリでは、安全(暴言・スパム・ネタバレ)と話題の問いを渡して使っています
-
EmbeddingGemma2(アプリでの呼び名): Google の埋め込みモデル
embeddinggemma-2:270mを手元の Ollama で動かし、例文との近さで分類する自作の分類器。カテゴリごとに例文を数値にしておき、コメントといちばん近い例文のカテゴリを選びます
アプリには「シチュエーション」という仕組みもあります。配信のジャンル(ゲーム・競馬・雑談など)ごとに、例文と短い補足(「ゲームではなく、競馬などのレース中継の配信です」など)をまとめたものです。選んだシチュエーションを分類器に渡すと、EmbeddingGemma2 は例文を、Jev は補足を手がかりに使います。
分類し直しには、記録した配信のコメントを、分類器とシチュエーションを替えて流す道具を作りました。同じコメントを条件だけ替えて流せば、条件の差がそのまま見えます。
今回の題材は、ある土曜日の中央競馬の第11R中継です。分類器に送ったコメント 4,495 件を、次の 4 通りで分類し直しました。
| シチュエーションなし | シチュエーション「競馬などのレース」 | |
|---|---|---|
| Jev(Cloudflare) | ① | ② |
| EmbeddingGemma2 | ③ | ④ |
正解ラベルは付けていません。この記事の「一致」は「条件どうしで判定がどれだけ同じだったか」で、正しさではありません。どちらが正しいかは、本文を人が見て確かめる必要があります(後述)。
コメントの概要
- 4,495 件。本文の長さは中央値 8 文字、9 割が 17 文字以内(平均 9.7 文字)
- 競馬の中継なので、馬名・騎手名・「頼む」「来い」「おめでとう」が並ぶ短いコメントがほとんど
短いうえにジャンルの固有名詞だらけ、という分類器泣かせのデータです。
結果 1: 話題の分かれ方は「分類器の癖」がはっきり出る
4 通りそれぞれで、話題がどう分かれたか(4,495 件に占める割合)。
| chat(雑談) | question(質問) | guide(攻略) | instruction(指示) | other(その他) | |
|---|---|---|---|---|---|
| ① Jev・なし | 76.1% | 6.8% | 2.0% | 2.6% | 12.4% |
| ② Jev・競馬 | 78.3% | 6.5% | 1.1% | 0.4% | 13.7% |
| ③ Gemma・なし | 91.2% | 3.0% | 0% | 0% | 5.8% |
| ④ Gemma・競馬 | 92.3% | 7.7% | 0% | 0% | 0% |
- EmbeddingGemma2 はほぼ雑談に寄せる(9 割超)。競馬の例文には攻略・指示の例文を置いていないので、その 2 つはほぼ出ません(問いの説明文だけが見本になるため。ゲームでない配信で当てすぎ1ないための設計です)
- Jev は「その他」を 1 割強使う。短い応援コメントを、雑談ではなく「どれでもない」と見る傾向
- 4 通りすべてで話題が同じだったのは 70.3%。残り 3 割は、条件によって行き先が変わるコメントでした
結果 2: シチュエーションを渡すと何が変わるか
Jev: 補足 1 行で「指示」の当てすぎが消える
Jev のプラグインが使うのは、シチュエーションの補足の 1 行だけです(「ゲームではなく、競馬などのレース中継の配信です」・例文は使いません)。それだけで、
- 指示(instruction): 116 件 → 16 件(-86%)
- 攻略(guide): 92 件 → 51 件
と、ゲーム実況向けの話題に当てすぎていた分がほぼ消えました。たとえばレースの「差せ」「そのまま」のような応援は、ゲーム実況の文脈なら「配信者への指示」とも読めます。補足 1 行でその区別が付くようになった、という読み方ができます(推測です)。
①と②(Jev のありとなし)で話題が同じだったのは 88.0%。変わった 540 件の内訳は、雑談 ↔ その他の入れ替わりが 334 件、指示・攻略 → その他 / 雑談 が 150 件でした。
EmbeddingGemma2: 例文がないと「暴言」を当てすぎる
EmbeddingGemma2 は、シチュエーションの例文を見本に足して使います。例文を外すと(③)、
| ④ 競馬の例文あり | ③ なし | |
|---|---|---|
| 暴言(toxic) | 8 件 | 35 件 |
| スパム(spam) | 23 件 | 29 件 |
| 質問(question) | 347 件 | 133 件 |
暴言が 4 倍以上に増えました。④で当たった 8 件はすべて③にも含まれていたので、③は「同じものを見たうえで、さらに 27 件を暴言に寄せた」ことになります。
埋め込みは「どの見本にいちばん近いか」で決まります。私の見立てでは、共通の見本だけだと、騎手や馬に向けた強めの言葉が「配信者への暴言」の見本に近く見えてしまいます。競馬の「ふつうのコメント」の例文があると、そちらに引き寄せられて暴言に寄らなくなる、という仕組みです(増えた 27 件の中身を 1 件ずつ見たわけではないので、ここは推測です)。
結果 3: 「安全」は分類器どうしでまったく重ならない
いちばん驚いたのはここです。安全(暴言・スパム・ネタバレ)のどれかに当たったコメントの重なり(件数):
| Jev・なし | Jev・競馬 | Gemma・なし | Gemma・競馬 | |
|---|---|---|---|---|
| 安全のどれかに当たった件数 | 8 | 6 | 64 | 39 |
| Jev・なし と重なる | — | 4 | 1 | 0 |
| Gemma・競馬 と重なる | 0 | 0 | 31 | — |
暴言だけで見ても同じです。暴言に当たったのは Jev・なし 7 件、Gemma・競馬 8 件で、両方に当たったコメントは 0 件(ほかの組み合わせでも 0〜1 件)。同じ分類器のありとなしでは半分以上重なるのに、分類器が替わると別の 1% を指しています。
話題(7〜8 割一致)とは対照的です。安全の判定は件数が少ないうえに、「何を暴言と見るか」の基準が分類器ごとに違う、ということでしょう。「1 つの分類器の暴言判定をそのまま信じて隠す」のは危ない、という結論になります。アプリでは、暴言と判定されたコメントの見せ方(ぼかす・隠すなど)を選べ、「この言い回しを暴言にしない」許可リストでも外せるようにしているのですが、この数字を見るとそうしておいてよかったと思います。
結果 4: 再現性 — 同じ条件なら 100% 同じ
④(EmbeddingGemma2+競馬)は、配信を見ていたときと同じ条件です。分類し直した結果は、記録の判定と 4,495 件すべて一致(話題も安全も)しました。
- 埋め込みは毎回同じ数値を返すので、判定が揺れない
- 道具が記録を正しく読み、当時と同じ条件を作れていることの確かめにもなる
逆に言うと、①〜③と④の差は、純粋に分類器と文脈の差だと言えます。
速さとお金
測った環境: Mac mini(Apple M4・10 コア・メモリ 24 GB・macOS 26.6)。EmbeddingGemma2 は同じ Mac の Ollama 0.40 で動かしました(GPU は M4 の内蔵のもの)。Jev は外部の API なので、こちらの機械の速さは通信と前後の処理にしか効きません。
| 全体 | 要求 | 1 回の応答 p50 / p95 | |
|---|---|---|---|
| Jev(Cloudflare) | 71〜74 秒 | 139〜141 回 | 325〜350 / 432〜435 ms |
| EmbeddingGemma2(手元の Ollama) | 66〜71 秒 | 141 回 | 454〜479 / 522〜546 ms |
- どちらも 1 分あたり約 3,700〜4,000 件。EmbeddingGemma2 の 1 回の応答(約 32 件・0.45〜0.5 秒)は、この Mac の内蔵 GPU での埋め込みの時間がほとんどです。これは分類し直しの道具でまとめて流したときの速さです(配信中はコメントの届き方に合わせて送るので、これより少なくなります)。配信のピークでも余裕がある速さです
- Jev(Cloudflare)は呼ぶたびに料金がかかります。今回は 4,495 件 × 2 回(要求 280 回)。EmbeddingGemma2 は手元で動くので料金はかかりません
例文を増やすと、どれだけ遅くなるか
「文脈(例文)を厚くすれば効くなら、どんどん増やせばいい」とはいきません。EmbeddingGemma2 は例文を見本にして比べるので、例文の数がそのまま計算量になります。同じ 600 件を、見本の数(共通の例文+シチュエーションの例文+問いの文)を変えて流しました。
| 見本の文 | 1 回の応答(約 32 件)p50 | 準備(最初の 1 回) |
|---|---|---|
| 66(シチュエーションなし) | 448 ms | 約 1 秒 |
| 246 | 512 ms | 約 3 秒 |
| 516 | 657 ms | 約 7 秒 |
| 966 | 810 ms | 約 13 秒 |
| 1,866 | 1,119 ms | 約 24 秒 |
- 1 件ごとの分類は、見本 1,000 文あたり約 +370 ms(1 回 32 件)。コメントを数値にする時間(約 0.45 秒)に、見本と比べる計算(768 次元の内積 × 見本の数 × 32 件・JavaScript)が足し合わさります。1,866 文でも 1 回 1.1 秒で、1 分あたり約 1,700 件は処理できるので、配信のピークには足ります
- 準備(例文を数値にする)は 1 文あたり約 13 ms で比例。1,866 文で 24 秒。これは接続したときとシチュエーションを選び直したときの 1 回だけで、アプリはウォームアップとして前倒ししています
- 増やしすぎると、速さより先に精度が落ちます。今回の記録でも、競馬に雑談の例文を足したら質問の再現率が下がりました(例文どうしが邪魔をする)
対して Jev は例文を読まず、補足の 1 行だけを使うので、補足を 0 〜 1,500 文字(アプリの上限)に変えても 1 回の応答は 339〜399 ms で変わりませんでした。長い補足を渡しても速さの心配はいらない、ということです。
この測定で、見本が約 320 文を超えると EmbeddingGemma2 の分類が全件失敗する不具合を見つけました。Ollama が返す数値(768 次元 × 文の数)が 5 MB を超え、アプリ側の応答の上限に当たっていました。128 文ずつ送るように直しています。測ってみないと分からないものです。
作ってみて分かった落とし穴(おまけ)
JSON のキーの並びで、見本のキャッシュが毎回外れていた
EmbeddingGemma2 のプラグインは、例文を数値にした結果を「要求の中身を JSON.stringify した文字列」を鍵にして覚えています。ところが本体(Swift)がプラグインに渡す JSON は、辞書のキーの並びが毎回変わっていました(JSONEncoder は並びを決めない)。同じ中身でも鍵が毎回違うので、要求のたびに例文を数値にし直していたのです。
outputFormatting = [.sortedKeys] の 1 行で直り、別の評価データ(600 件)では処理が 35 秒 → 12 秒、1 回の応答が 1.8 秒 → 0.5 秒になりました。「同じ中身なら同じ文字列になる」は、言語をまたぐと当たり前ではありません。
評価のキャッシュの鍵に、文脈を入れ忘れていた
分類し直しの道具は、分類器の結果をファイルにキャッシュします。鍵には補足(notes)は入れていたのに、シチュエーションの例文を入れていませんでした。補足のないシチュエーションで測ると、「シチュエーションなし」の結果を使い回してしまうところでした。文脈で結果が変わるなら、文脈は全部鍵に入れる。当たり前ですが、条件を増やすたびに見直す必要があります。
まとめ
- 話題の当てすぎには、文脈(シチュエーション)が効く。Jev は補足 1 行で「指示」の当てすぎが 86% 減り、EmbeddingGemma2 は例文がないと暴言を 4 倍以上当てた
- 安全(暴言など)の判定は、分類器の差が大きい。話題は条件をまたいでも 7〜9 割そろうのに、安全は分類器どうしでほぼ重ならない。1 つの分類器を鵜呑みにしない
- 同じ条件なら埋め込みの判定は 100% 再現する。記録を条件だけ替えて流し直す道具は、分類器と文脈の差を切り分けるのに便利
- シチュエーションには改良の余地がありそうです。例文は増やせば効くわけではなく(競馬+雑談で質問の再現率が下がった・見本 1,000 文で 1 回の応答が +370 ms)、ジャンルに合った例文を必要な数だけ置くのが要点になりそうです
次は、条件ごとに判定が割れたコメント(4 通りで話題がそろわなかった約 3 割)に人が正解を付け、どの条件が「当たって」いるのかを確かめるつもりです。
さいごに
今回効いた「シチュエーション」は、自分で作って取り込めます。ジャンルごとの例文と補足を書いた JSON 1 つで、スクリプトはありません。アプリから仕様書ごと LLM に渡して書いてもらい、返ってきた JSON を貼り付けて取り込むこともできます。手元の Ollama で動く EmbeddingGemma2 なら料金もかからないので、ぜひローカルでも試してみてください。
アプリ「LiveChatDashboard」は macOS と iPad で動きます。配信への接続はサブスクが必要ですが、初めての方は 2 週間無料で試せます(Apple アカウントごとに 1 回)。過去の配信の見返し・見本の配信・設定はサブスクなしで使えるので、まず見本で窓の振り分けを眺めてから、無料の期間で自分の配信につないでみてください。仕組みの詳しいところはサイトのヘルプにあります。
コメントの本文は、第三者(視聴者)の発言なので記事には載せていません。手元でも、記録と分類し直しの結果はリポジトリに入れない運用にしています。
-
この記事での「当てすぎ」は、あるカテゴリに、本来そうでないコメントまで入れてしまうことです(「当てる」=そのカテゴリと判定する)。たとえば競馬のレース中の応援を「配信者への指示」に入れるのがそれです。正解ラベルを付けていないので、厳密には「そのカテゴリの件数が、配信の内容からして多すぎる」という意味で使っています。減った分が本当に誤りだったかは確かめていません。 ↩