問い合わせるのはフレームごとではなく、カードごとに1回
カードの認識は、すでに実用の域にあります。優れたモデルにトレーディングカードを見せれば、名前、セット、番号がおよそ0.5秒で返ってきます。それが崩れるのは、動画に対して回したときです。技術的な問題ではなく、純粋に量の問題として。
動画の大半は繰り返しです。1枚のカードを4秒間かざせば、毎秒15フレームなら同じカードの写真が60枚になります。識別エンドポイントに60回問い合わせても、返ってくるのは同じ答えが60回。素朴なストリーミングパイプラインはどれもまさにそれをやっていて、だからこそ配信のリアルタイム分析は「資金のあるプラットフォームにしか運用できないもの」だと思われてきました。
cardstream は、その繰り返しを消すために存在します。動画と認識呼び出しの間に置かれる小さなステートマシンで、そのほとんどは自力で算出できるシグナルだけで組み立てられています。画面は静止したか、これは少し前と同じカードか、そもそもフレームにカードは写っているか。本当に新しいカードが静止したときにだけ呼び出しが飛び、それ以外では飛びません。残りの処理はすべて、あなたが既に持っているハードウェアの上で動きます。
フレームごとではなく、カードごとに1回
毎秒15フレーム(このプロジェクトが検証しているレートの上限)で1時間の配信を行い、およそ100枚の異なるカードをレンズの前に出したとします。まったく同じ動画を分析する2つの方法:
回の識別呼び出し。フレームごとに1回で、その大半は少し前に答えが出た質問を繰り返しているだけです。
回の識別呼び出し。異なるカードごとに1回で、フレームレートがいくつでも、1枚のカードをどれだけ長くかざしても変わりません。
呼び出し回数は約540分の1。この差は数字のトリックではなく、設計そのものです。カードを静止させても回数は増えません。カメラのフレームレートを上げても回数は増えません。呼び出し回数が追いかけるのは、見せたカードの枚数であって、配信した時間ではありません。
誰が動かし続けているのか
認識サービスを実際に提供しているチームが開発
cardstream は、Ximilar のコレクティブル認識を手がけるチームから生まれました。cardstream が呼び出す識別エンドポイントは、私たちが本番環境で運用しているものそのものです。つまりクライアントとサービスは、同じ人間が保守しています。
開発はすべて公開
パッケージ全体が GitHub にあります。ステートマシン、2つのデプロイ形態、ブラウザ UI のすべてです。判断ロジックのどこも、中身を覗けないサービスの裏に隠されてはいません。
ネットワークなしでテスト可能
テストスイート全体がオフラインで動きます。モデルファイルと HTTP 呼び出しはフェイクで置き換えられています。APIキーのないノート PC でリポジトリをフォークしても、何かを壊したかどうかはちゃんと分かります。
コードが忘れてはならないこと
-
フレームごとではなく、カードごとに1回
すべての設計判断はここから始まります。ローカルで計算できるシグナルは、マシンの外へ出るたった1回の呼び出しより前に必ず走ります。
-
判断ロジックのコピーは1つだけ
「いつ呼び出すか」は、ただ1つのモジュールにあります。ドライバー、トランスポート、UI に散らばって3人が3通りに書き換えられる状態にはしません。1ファイル、一度に読み切れる長さです。
-
ドライバーは薄いまま
スケジューリング、ロギング、I/O はドライバーの仕事。何を新しいカードとみなすかはエンジンの仕事です。フレームの届き方を差し替えても、呼び出しが飛ぶタイミングが知らないうちに変わることはありません。
-
フレームループを止めるものはない
デコード、検出、HTTP、ディスク I/O はすべてループの外で動きます。識別が遅ければフレームが1つ落ちるだけで、配信の遅延が積み上がっていくことはありません。
-
プロバイダーへのロックインなし。私たち自身も含めて
識別呼び出しは、小さなインターフェースの裏にある差し替え可能な1ステップです。まったく別の場所に向けても、すべてのゲート、スロットル、キャッシュはそのまま動き続けます。
-
デフォルトでセルフホスト
あなたのハードウェア、あなたのキー、あなたの動画。クライアントサイドモードでは、配信を自分の Ximilar アカウントに保存することを選ばない限り、マシンの外へ出るのは異なるカードごとに1枚の切り抜き画像だけです。
カードが教えてくれたこと
このうちのいくつかは直感に反するので、次の人が見つけられる場所に書き残しています。リポジトリの中、それが制約するコードのすぐ隣に。
親切なヒントが精度を下げることがある
エンドポイントにカードのゲームを教えると、エンドポイント自身の文字体系分類器がオフになり、ラテン文字にフォールバックします。その結果、日本語版のカードが気づかないうちに英語版にマッチしてしまいます。これは推測ではなく計測した結果で、だからこそ文字体系を指定せずにゲームだけを指定することは誤りとして扱われます。
少し余裕のある切り抜きのほうがよくマッチする
カードぴったりに切り抜くと見た目は正しいのに、結果は悪くなります。送信される切り抜きには意図的に余白を持たせています。きれいな縁より、少しの周辺情報のほうが効くからです。
ごまかすより、立て直す
呼び出しがタイムアウトを過ぎても応答しないとき、パイプラインは来ないかもしれない結果を待ち続けるのではなく、自ら詰まりを解いて先に進みます。この制約は取り繕わずに、リポジトリに明記しています。
読んで、動かして、パッチを送る
リポジトリは公開されています。独立した extras を持つインストール可能な Python パッケージ1つと、ブラウザ UI です。ロケーターと埋め込みモデルの重みは私たちが学習させたもので、リリースと並べて Apache-2.0 で公開しています。Issue とプルリクエストを歓迎します。特に実際の配信からの報告は、どんなテスト環境でも見つからないことを教えてくれます。
認識そのものは Ximilar のエンドポイントであり、これからもそうです。カードのデータベースを背後に持つのがその部分だからです。その周りにあるものはすべて、自由に変えてかまいません。
オープンソース。セルフホスト。あなたの配信を、あなたのスタックで。
間に入るプラットフォームも、シートライセンスもありません。Ximilar API または独自の識別システムを接続すれば、cardstream はフレームごとではなく、異なるカードごとに1回だけ呼び出します。Whatnot でのブレイク、Fanatics Live 形式のショー、独自のライブコマース環境での配信——どんな形でも、今夜からお手持ちのハードウェアで cardstream を動かせます。