Kristopher Baker iOSを土台に · プロダクトシステム · AI支援ワークフロー
← KiFinder

wip · 2026.07.08 · 約3分

サンドボックスが顔認識をこっそり止めていた

KiFinderをApp Storeに出す準備は、App Sandboxを有効にすることを意味した。前回はそれをほとんど事務作業のように書いた。そんなことはなかった。サンドボックスをオンにしたあと、スキャンは終わるのに何も見つけなくなった。顔は検出されず、写真にスコアも付かず、娘たちのマッチが並んでいたはずのグリッドが空になった。それでいて全部が動いているように見える。いちばんたちの悪い壊れ方だ。

原因はハードコードされた一つのパスだった。KiFinderの顔モデルはCoreMLで動き、CoreMLは実行前にモデルを一時ディレクトリにコンパイルする。私はそのディレクトリを /private/tmp/kifinder-coreml、つまりアプリのサンドボックスコンテナの外に向けていた。サンドボックスの前ならそれで問題なかった。オンにしたあとはそのディレクトリに書き込めず、CoreMLセッションの生成が失敗し、しかもその失敗が try? に飲み込まれるので、あらゆるembeddingの呼び出しが静かにnilを返し、スキャンは顔ゼロのマニフェストを生んだ。サンドボックスが入る直前まで動いていたし、それを捕まえられたはずのオンデバイスのスモークテストは後回しにしていた。修正自体は小さく、スクラッチディレクトリをシステムのtmpから導出してコンテナの中に収めるだけだ。ただ、信用できたのは、自分のkeep済みの写真で使い捨てのライブエンジンテストを回して、embeddingが修正前のゼロから修正後の5や6に変わるのを見てからだった。何度も学び直す教訓がある。後回しにしたチェックこそ、そのリグレッションを捕まえたはずのものだ。

残りの期間は、エンジンをより静かに、より読み取りやすくする作業で、すべてSparraを通した。keepやskipのたびにアルバム全体を再スコアするのはファンを回していたので、毎回の判断で走らせるのをやめ、手動の「Find new matches」ボタンの裏に移した。再スコアそのものも、すべての顔をすべての参照に対して回すスカラーのコサイン計算から、アルバムごとに一回のバッチ行列積に変えた。いちばん気になっているのはFace Spaceだ。アクティブな人物のembeddingを主成分二つに落とした2Dの散布図で、参照とkeepした顔、skipで教えたネガティブ、レビュー候補を一緒にプロットする。なぜある写真がマッチするのかが見え、他を引っ張っている外れ値の参照に気づける。まだ内部フラグの裏にあってオンデバイスでは未検証で、出荷した機能というよりマッチャーが見ているものを見るための手段だ。それでも、スコアを信じるだけでなくembedding空間そのものを眺められるのは、正しい方向に思える。