[ローカルLLMで生活ファイアウォール]-リアルタイムTVCMフィルタ
以前「内面世界のファイアウォールとしてのローカルLLM」として、「ローカルLLMを自分の絶対的味方にして外界から入る雑多な情報から自分の身を守る」という話を書きました。
今回はそのアイデアを具現化するリファレンスデザインを思いついたのでとりあえず作ってみることにします。
TV/動画配信のCMをリアルタイムでミュートする「リアルタイムTVCMフィルタ」です。
注意:
上記のように書いていますが、TVCMの検出とフィルタリングは皆が期待するほどの精度はありません。最近のCMはCMなのか番組なのかは人だって一目では分からないものが多いと思います。あくまで「内面世界のファイアウォールとしてのローカルLLM」の実装サンプルとしてのおもちゃです。ただこれはおもちゃであってもLLMはこういうものも作れるポテンシャルがあることを示します。
とりあえずの背景
皆さん思っていると思いますが、昔に比べてどの広告メディアもうざったくなってきました。TV番組はそれとなく商品を売り込むし、深夜番組はTVショッピングだらけになりました。動画配信は特に顕著で、露出だけを強調した連呼や射幸心ビジネスのCMなどちょっとどうだろうと思うものが多いです。
(以下グチグチ言っているのでショートカットしてよいです。。)
デジタルサービスも広告付き無料のようなフリーミアムの形式が入ってきたら何から何まで広告が付いてくるようになりました。私はニュースアプリ内で動画が流れるのは大嫌いです。ニュースは本来自分の目のスピードで読んでいくことで内容を掌握していくものだと思っているので、読んでいる横で何かの絵が動いたらまったく読めなくなります。ニュースアプリではなくなってしまうのです。
そのためすでに2,3本はニュースアプリを捨てましたし、Xもこの前止まらない動画広告が出たのでもうWebでしか見ません。
露出は物品の売り上げに影響を与えるのである程度は仕方ないと思っているのですが、動く広告、汚い写真で目を引かせる広告、射幸心の高いギャンブル広告(ゲームも含まれると思っている)、サラ金広告、グレーぎりぎりの広告が目の邪魔、耳の邪魔になる形で連呼されているとさすがに勘弁してくれと思います。とりわけ連呼する広告はすでに広告じゃなくて刷り込みでしょう。。
いやなら止めればいいじゃないと言うでしょうが、あなた方は広告付き無料サービスを出してきたとき、無料を振り回して有償サービスをなぎ倒してきたではないですか。有償サービスが息絶えた後にジワジワ広告をえぐくしていくのはひどくありませんか。
でも、あまり本気で思っている訳ではありません。時代の潮流なんですし本気でなんとかしようと思っている訳ではないです。そもそも見るな、が正解なんだと思いますし。
ローカルLLMを自分の絶対的な味方にして情報武装するという現実実装を試して見たいのです。
「ドラ○も~ん、TVCMがうざったいんだよ~なんとかしてー」的な感じです。
機能目標
もう歳なのでTVをじっくり見るということはほとんどなくなりました。静かすぎないようにBGMとしてTVを付けておくみたいなみかたがほとんどです。
でもだからこそ「奇音、奇声を連呼してくるCM」はちょっと勘弁して欲しい。
CMの刷り込み奇声を抑えるという目的なので「TVを流しているときにCMだったらミュートにする」という機能が目標です。チャネルを変えたり電源を切ったりすると話の流れが飛んだり画面の点滅がうるさくなるなど別の意味で邪魔になるので消音のみで対応します。
CMは人が見てもCMと判別できないようなものも多いし、TV番組もCMっぽく見えるシーンはあるので、誤動作は大甘に考えます。消音は誤動作がある程度起きても邪魔になりにくいのです。
システム構成
まずはTV番組が相手なのでTV放送の受信機器が必要です。これは手持ちの既存のTV機器を使います。
今回使う入力ソースは「TV,DVDプレーヤー(地デジ受信機能あり),Amazon Fire Stick(複数の動画配信)」です。TVが出力端子付きなら一番よかったのですがそういう機能があるTVはめったにないようです(ブラウン管テレビ時代は出力端子があるTVもまれにあった) ですので地デジ映像はDVDプレーヤーの地デジチューナーから取得します。
TV画像をキャプチャーするのに小型のhdmiビデオキャプチャー機器(USB出力)を使います。
TVをミュートにするのに赤外線リモコンボード(ここは本筋でないので出来合キットです)を使います。
それらを制御するのにRaspberry pi Zero 2 Wを使います(別用途で買っていたものの流用です。ちなみにWalker1で使ったものはさらに別のものに使用予定)。
画像を認識させて広告かどうかを判定させるのにマルチモーダルAIのLLaVAとそれを走らせているubuntuサーバー(miのLLM処理兼用)を使います。
入力画像はDVDプレイヤーの地デジ放送とAmazon Fire Stickに入っている複数の動画配信サイトです。入力の切替も必要ですし出力の分岐も必要です。hdmi入力の切替機は元々持っていたものを使い、出力のアクティブ分岐器などは買いました。
CMの音を消すだけで大層な構成ですね。。
うちで一番働いているLLMはLLaVA
何をさせるかというと以下の形の処理です。
hdmlビデオキャプチャーを使ってTV画像を取得する。
LLaVAで認識させてその画像がCMかどうかを判定する
CMであったらTVを消音にする赤外線リモコン信号を出す。CMでなくなったらボリュームアップ/ダウンの赤外線リモコン信号を出す。
あっけらかんと思われるほどシンプルな作りです。そしてこの機能の要になっているのはLLaVAです。
私は旅bot達とかいろいろ変なLLMを動かしていますが、うちで一番仕事しているLLMはLLaVAです。
以前の記事にあるように、日中や休みのときにAI絵日記として自分から見える日常風景をAIで再加工した画像を定期的に上げています。
外出時のAI絵日記は通信コストの問題もあるので大きなデータ転送は基本1時間に1回、数ファイル分です(ポーリングは1分に1回程度、不定期には30分に1,2回のデータ転送は別途ある)
しかし室内時は実は15秒に1回(大きな変動を検出したときは4秒に1回くらい)の結構ハイピッチな頻度で画像認識をさせており、これを使って今いる場所がどの部屋なのか台所なのかのロケーション検出に使っています。
ざっくり計算しても4*60*8=1920で1日2000回くらいLLaVAを使っているのです。ChatGPTやStable-Diffusionの使用回数の比ではないのです。
(サーバー電力の無駄遣いと言われればぐうの音も出ないですが。。)
本当にLLaVAは使いやすいマルチモーダルLLMだと思ってます。
クラウドのマルチモーダルAIのほうがきっと賢いのでしょうが、これだけ多数回処理するのでクラウドのAPIだと課金が無視出来ないと思うし、CM認識のためにTV画像をクラウドAPIにアップすれば「インターネットへの違法アップロード」とか言われかねないですし。
TV画面の広告を認識させるまで
さてそういいつつも実際にLLaVAでCM画像かどうかの判定ができなければ計画は振り出しです。ある程度試行錯誤をしつつ組み立ててみました。
まずは本当にやれそうか確認
さて抽出した画像をLLaVAがCMかどうかを判定できるのか確認してみます。これが的外れな回答だったら計画は中止です。
ビデオキャプチャーの画面を撮りながらプロンプトを調整します。文がぶれにくいようにtempとtop_pを0にします。
174444:2:False: Yes, the image appears to be an advertisement. It features a dish of pasta with a sauce that looks like it could be cheese or cream, and there is a discount offer indicated by the text "50% OFF" in the upper right corner. The presence of the discount suggests that this is meant to attract customers to purchase the product at a reduced price.
174458:2:False: Yes, the image appears to be an advertisement. It features a character in a costume with text overlaying it, which is typical for promotional materials.
174503:2:False: Yes, the image appears to be an advertisement. It features a character from a movie or TV show with text overlaying it, which is typical for promotional materials.
145014:0:False: No, this image is not an advertisement. It appears to be a piece of artwork or fan art depicting an animated character in a sleeping pose.
180748:0:False: No, this image is not an advertisement. It appears to be a photograph of a group of workers engaged in some sort of construction or repair work, possibly related to water infrastructure given the presence of pipes and hoses. The image includes text overlaying it, which suggests that it may have been shared on social media or as part of a news report.
結構きちんと認識しました。もちろんCMの冒頭など、ぱっとみドラマと違いが分からないような画像は無理なのですが、商品が押し出されて商品ロゴや宣伝ロゴが舞っているような画面はほぼ広告と認識できています。
なにより驚くべきは「Is this image advertisement? Tell me only Yes or No」というプロンプトで検出できているということです。画像検出するのにyoloまでだったら椅子とか本とか画像オブジェクト名はせめて必要です。
「広告ですか?」だけで通るのはちょっと驚きでした(学習時に広告というタグは入っているのでしょう)
これならいけるかも。
画像キャプチャーの試行錯誤
画面キャプチャー部分はかなり試行錯誤しました。ffmpegで動画ストリーミングで転送してサーバー側ストリームから画像を取り出すか、画像をキャプチャーして1枚ずつサーバーに送るか など。LLaVAが早いからといっても認識に1~2秒はかかりますのであまり高頻度で画像を必要とする訳ではない。ストリーミングにしてしまうほうが後々技術的にはまとまりやすいのですがキャプチャー処理にはRaspi Zero 2 Wを今回使用しており重い処理はかなり厳しいです。CMを検出して消音まで持ち込むのは極力早いほうがよいので今回はOpenCVのVideoCapture()で1枚1枚画像を撮って、送る形にしました。 1枚ずつ画像を送る形は現在のWalker端末と近いのでノウハウがかなり流用できソフト実装上も楽です。
キャプチャーデバイスがすごく重い問題に悩みこむ
ところがキャプチャー画像がなぜか15秒くらい古い画像しか取れません。。
やはりRaspi Zero 2 Wでは無理なのか、と思って想定外支出でRaspi 5を購入しました(どうせそのうち別用途で買うはず、買うはずと数日悩みました。。)
ですがRaspi 5でもなぜか同じくらいの時間がかかってしまう?
ネットで調べてなんとか解決
この手のデバイス特性的な問題はやはり分野の専門の人でないとなかなか分からないものです。ネットをぐぐりまくりました。そうしたらいくつか解と思える話が出てきました。
簡単に言うと「元々動画用キャプチャーの仕組みなので読み取り指示していないときにも内部で画像のキャプチャーをバッファ記録している。そのため静的に画像を取りたいならバッファ記録している分の画像を一旦まとめて読み取らないとバッファに記録している古い記録がreadされてしまう」とかいう話しらしいです。
いやこれは知ってる人でないとわからない。。たぶんChatGPTに聞いても出てこない。本当に助かりました。
readをまとめて多数発行するようにしました。これで画像抽出の遅延が1, 2秒程度になりました。OpenCVとかに詳しい人ならもうちょっと早く出来るかもですがまずはこれで行きます。
Walker端末での画像転送、LLaVA認識の仕組みを流用して調整して、赤外線ボードのサンプルソースを取り込んで、画像取得から検出して赤外線で制御するまで5~6秒という遅延です。ぎりぎりうざったいCMを中断させられるかなくらいの状態です。
ちょっと遅延がきつめなのですが、とりあえずはRaspi上でpythonで画像をサーバーに送り、LLaVAでCMを検出して結果からTVを消音する動作が動きました。
番組・CMの種類による検出精度の幅
予想はしていたのですがCMの作り次第で検出の精度はかなり変わります。
ドラマ仕立てで展開するCMの冒頭はかなり見逃します。これは今のやり方だと仕方ない。ただそういうCMでも最後付近は商品ロゴが大きく出るので、そのシーンまで行くとかなり確実にCMと検出出来ます。
冒頭から宣伝ロゴが飛びまくるようなチラシのようなCMだとかなり精度良く検出します。
番宣CMの場合、中身が番組の一部のままなのでこれも結構見逃しますが番組ロゴが出る付近だと結構検出できます。
しかしCMが一番うざったいのは、だいたい商品ロゴが飛び回って、商品名を大声で読み上げる最後のシーンです。ドラマ仕立てCMでもCM中盤くらいには商品説明ロゴが出始めるのでそこで検出出来る場合がかなりあり、結果として一番うざったい最後のシーンは聞かずに済むケースが多いです。
現状「思ったよりよくCMのうざったい部分はミュート出来てるかも」という感じです。
逆に番組内でミュート誤動作はどのくらい起きるでしょうか。
バラエティ番組など、料理を接写でバンと出したり、説明吹き出しとかが舞ったりするシーンは結構ミュートされます。
ドラマなどはほぼ誤ミュートはないです。たまに接写シーンとかが誤ミュートされるくらい。
アニメだとほぼ誤ミュートは起きないようです(まったく起きない訳ではないですが)
時間を遡る追加判定処理を入れてみる
CMは形式が本当に多彩で、静止画像からだけでCM判定をすることは人でも不可能と思います。おそらく一番確実な方法は以前の記憶から「このCMは以前に見たよね」と判断することです。現状のLLMでの判定方法でもCMの一番最後のシーンはかなりの精度でCMと判定できています。CMは15秒のものが多いので、判定してから5~15秒前の画像はCMの可能性が高いです。
CMの可能性が高い画像を多量にため込んで、現在の放送画像と同じか比較するという手はおそらく有効でしょう。
ですがCMをミュートさせるためだけに数秒に1回画像を撮影して何万枚もTV画像を蓄積するとかちょっと。。。
ここはLLMで画像を認識させているのですから、どういう画面なのかを説明したテキストが出てきています。それをembedding LLMでベクトル化して、そのベクトルを蓄積してそれを使って画面比較をすれば大幅に量を減らせます。
減らせますが、、
画像認識テキストだと「二人の人がいます(ドラマ)」と「二人の人がいます(CM)」とほぼほぼ同じ認識テキストになることが多々あると考えられ、安定に識別出来るとはちょっと思えないです。。
まぁあくまで現実フィルタLLMの実装例おもちゃですのでやるだけやってみます。。embedding LLMとvector検索は想起LLMの件で組み込んだのでそれを使い回します。
結果だけ言うと「検出精度はわずかに上がるが誤検出がすごく上がる」でした(体感測定ですが)。。文章レベルで1回LLaVAレベルで誤検出してそれをvector dbに登録してしまうと以降同様の文が誤検出されだして、それが蓄積していくので番組シーンを誤検出されるケースが増えていきます。
いくつか手続き的な例外操作(認識テキストにtextが入っていない場合はCMと見なさないなど)を入れると誤検出はかなり減りますが誤検出が増えるのはある程度仕方ないようです。
本気でやるなら以下の改良は考えられます。
全体的に高性能化して画像から消音までの遅延時間を極力小さくする
マルチモーダルLLMでの画面解析をより詳細にして、embedding-vector検索での判定ミスを減らす
マルチモーダルLLMを広告検出用にfine-tuningする(動画マルチモーダルLLMだとなおよいと思われる)
音声まで認識させてLLM判定またはNGワードをdb検索で判定
遅延時間の分、TV側信号をhdmi遅延器で遅らせる
LLaVAによる広告検出は静的画像的には十分に当たっていると言えるので遅延時間を短くするのが一番効果的です。
ただその方法だけだと「静的画像では人にも判定できないCMの冒頭画像」には効果がないので、画像の内容をより詳細に説明させてそれをembeddingベクトル検索するなどになるでしょう。動画としてマルチモーダルLLM出来るのなら完全に出来るかもしれません(CM検出させるためだけに動画でLLMを学習させるとかかなり道楽ですが)
それらとは別に音声認識まで入れると判定精度は上がると思います。喋らないCMもあるにはありますが、大半は宣伝文句を言いまくるものですし、音声認識が安定していれば嫌いなCMの冒頭文言をNG登録して狙い撃ちできると思います。
さらに別案として、TV側信号をhdmi遅延器で遅延する時間の分遅らせれば実質上認識時間は0になるので遅延影響は減らせるはずです。ただhdmi遅延器ってプロ向け機器みたいで結構高いようですが。。
気に入るかはその人次第
実際にCMフィルタとして機能しているかといわれるとかなり微妙です。
例えば15秒の長さのCMではこの表示中に2~3回認識をする訳ですが、仮に全てを正しくCMと認識したとしても消音の開始は認識遅延分の約5秒遅れます。CM冒頭のCMミュージックは聴かされる訳ですから「CMが消音出来た」というには微妙です。実際にはドラマ仕立てCMの場合冒頭を認識出来ることはまれなので10秒くらいはCMを聴かされます。CMが連続している場合は真ん中の消音も出来るケースもかなりありますが、一方で番組本編の冒頭5秒くらいは認識時間ずれで消音されてしまいます。番組をガチ見している場合は厳しいという気がします。
ただ一番セールス文言がうるさい最後の5秒を消音するのは結構できており、連呼CMによる刷り込み的なうるささは結構減らせます。
せめて現時点の認識-消音時間を2秒以下に抑えられるようになれば快適と思う人も出てくると思います。
入力ソースを選ばない/リアルタイムなのも強みです。昔のVTRのCMスキップは音声トラックのステレオ/モノラルでやっていたらしいですが、そういう属性は使わずにLLMが見た画像でリアルタイムで判別するので、地デジ放送でも動画配信でもビデオでもリアルタイムで消音します(もうちょい反応が早いとよいのだが。。)
自分としてはしばらく使ってみようと思います。CMの終盤の商品推しの大声/連呼がミュートが出来ているので案外快適なのです。もう少しチューニングをしてみるのも技術的に面白そうです。ただ上記に上げたようなガチチューニングはやらないかな。。それに時間とお金使うくらいなら別のアイデア物を作ることを考えたほうが楽しそうですし。
人に勧められるか? 現状ではまず勧めないです。検出精度が微妙なのでがっかりされるのがオチです。それに機材0から作ったらLLMを動かしているPCサーバー代も含めて結構な額になります。
ローカルLLMで自分が触れる情報を自分好みに情報改変する、というと大げさかもしれませんが、生成AIの延長上でなんとなくそういうことが可能になってくるかもしれないと思います。
世界を自分好みに改変する、とか中二っぽいことを言い出すより現実的ではありませんか。
追記2024/10/01:判定時間を1.5~2秒に改善
キャプチャー処理を調整した結果、判定時間ループを1.5~2秒くらいまで短縮することが出来ました。消音もよく効くようになりましたが、一方でドラマ仕立てCMや番組宣伝CMでの検出の微妙さはあまり変わらずです。
見る番組がドラマやアニメだと誤検出そのものが少ないので、1回検出したら固定で15秒消音でもよいかもです。