InsightFace 非公開モデルのプライベート評価テスト手順
MOU、画像準備、Python クライアント、プライバシー要件まで含めた、自社データで InsightFace のオープンソース/非公開認識モデルを評価するための実践ガイドです。
このガイドで作るもの
InsightFace は商用契約に進む前のお客様向けに、オープンソースおよび非公開の認識モデルをホスト型の特徴抽出 API として提供し、自社データでの精度評価を可能にしています。
このガイドでは、API エンドポイントの受領方法、画像の前処理、最小構成の Python クライアント、当社のプライバシー / データ取り扱い方針、無償評価期間の契約スコープまでを通しで説明します。
始める前に
- 協力意向、評価期間、共有するモデル識別子に関する秘密保持の範囲を定めた MOU が締結済みであること。エンドポイント URL は MOU 締結後にのみ発行されます。
- Python 3.9 以上、numpy、requests、OpenCV (opencv-python) がインストール済みであること。
- RetinaFace や SCRFD などの検出結果(バウンディングボックス)を持つ、本番分布を反映した検証セット。
- 明確な評価用データセットと正解ラベル、ならびに科学的な評価手法。
1. MOU の締結とアクセス申請
プライベートモデルテストは、必ず MOU の締結から始まります。MOU では協力意向、評価期間、当社が共有するモデル識別子に関する秘密保持の範囲を定めます。
API エンドポイント URL、利用可能なモデル名(MOU で許可されたオープンソースまたは非公開モデル)、レート制限は、MOU に記載された技術担当者宛にメールで送付します。エンドポイントは公開されることはなく、契約上の担当者以外には共有しないでください。
- 無償評価期間はエンドポイント発行日から最長 2 週間です。それ以上の継続利用は商用契約が必要です。
- MOU で許可されたモデル名のみがアンロックされ、それ以外のモデル名でのリクエストはサーバーで拒否されます。
- テスト期間終了などでエンドポイントを更新する場合、新しい URL は同じ担当者宛にメールで送ります。
2. 代表性のある検証セットの準備
プライベートモデルは認識バックボーンであり、検出器ではありません。1 リクエストにつき 1 人の顔の大きめのクロップを 1 枚渡し、1 つの埋め込みベクトルが返ります。お客様側でまず顔検出を行い、クロップを 1 枚ずつ送信してください。
ただしサーバー側でも、送信された顔写真に対して二次的な顔検出とアライメントを行ったうえで埋め込みを抽出するため、多少のフレーミング誤差は許容されます。
- 1 画像 1 顔。元フレームに複数人いる場合は、必ず 1 顔ずつファイルに分けてください。
- MOU のデータ条項に従い、すべての画像について同意と適法根拠をドキュメント化してください。
3. 顔画像のクロップとエンコード
検出ボックスに少しマージンを加えてからアップロードしてください。0.2(左右上下にそれぞれ 10% ずつ)程度の expansion factor を加えると、髪の生え際、顎、耳など認識精度に効くコンテキストを保持できます。アップロードを軽くするために、最長辺の上限(例: 256 ピクセル)を設けても構いません。
必ず PNG など可逆フォーマットで送信してください。JPEG や低品質 WebP のような非可逆フォーマットは、目や口の周辺に圧縮ノイズを生じさせ、顔認識の類似度に測定可能な低下を起こします。下のヘルパーをひな形として、自社検出器のボックス形式に合わせて使ってください。
- 検出ボックスの周りにマージン(expansion factor)を加えてください。ボックスぴったりのクロップは精度を下げます。
- アップロード前に PNG で保存してください。API 呼び出し前に JPEG で再エンコードしてしまうことが、想定外の低スコアの最大要因です。
import cv2
def crop_face_with_expansion(image, bbox, expansion_factor=0.2, max_side=256):
"""
Crop a single-person headshot with a small margin around the detected
face box, and optionally downscale so the longest side is <= max_side.
image: input image as a numpy array (BGR or RGB).
bbox: face bounding box [x, y, width, height] from your
detector of choice (RetinaFace, SCRFD, etc.).
expansion_factor: total margin ratio (0.2 means +10% on each side).
max_side: if set, the longest side of the result is bounded.
"""
img_h, img_w = image.shape[:2]
x, y, w, h = bbox
# 1. Margin distributed evenly to both sides.
dw = int(w * expansion_factor / 2)
dh = int(h * expansion_factor / 2)
# 2. Expanded box, clamped to image bounds.
x1 = max(0, x - dw)
y1 = max(0, y - dh)
x2 = min(img_w, x + w + dw)
y2 = min(img_h, y + h + dh)
face_img = image[y1:y2, x1:x2]
# 3. Optional bounded downscale with a high-quality filter.
if max_side is not None:
curr_h, curr_w = face_img.shape[:2]
longest = max(curr_h, curr_w)
if longest > max_side:
scale = max_side / longest
new_w = int(curr_w * scale)
new_h = int(curr_h * scale)
face_img = cv2.resize(
face_img, (new_w, new_h), interpolation=cv2.INTER_AREA,
)
return face_img
# Save the crop with a lossless format (PNG) before sending it to the API.
# Lossy formats (JPEG, WebP at low quality) introduce compression artifacts
# that can measurably reduce face recognition accuracy.
# cv2.imwrite("probe.png", crop)
4. 特徴抽出 API の呼び出し
API は multipart/form-data POST を受け付けます。image フィールドに画像 1 枚、model_name に文字列を指定し、レスポンスとして model_name と feature(その顔の L2 正規化済み埋め込み)を含む JSON を返します。各埋め込みを numpy の .npy として保存しておけば、後段でコサイン類似度を自由に計算できます。
下のサンプルクライアントは本番プロトコルに完全準拠しています。そのまま動かすことも、extract_feature を自社の評価パイプラインに import することもできます。メールで送付されたエンドポイント URL は --server-url で渡し、共有リポジトリにコミットされるスクリプトにはハードコードしないでください。
- model_name は MOU に記載された値のみ受け付けます。記載外の名前はサーバーで拒否されます。
- feature が空配列のときはクロップから顔が検出されていません。バウンディングボックスとマージンを再確認してください。
- L2 正規化済みベクトルに対するコサイン類似度で比較してください。クライアント側で再正規化する必要はありません。
"""Example client for the private InsightFace feature extraction service.
Uploads a single-person face image to the test endpoint, reads the returned
embedding, and saves it locally with np.save for offline evaluation.
"""
import argparse
import os.path as osp
import numpy as np
import requests
def extract_feature(image_path, output_path, url, model_name, timeout=120.0):
filename = osp.basename(image_path)
data = {"model_name": model_name}
with open(image_path, "rb") as infile:
files = {
"image": (filename, infile, "application/octet-stream"),
}
try:
resp = requests.post(
url=url, files=files, data=data, timeout=timeout,
)
resp.raise_for_status()
except requests.RequestException as ex:
raise SystemExit(
"request failed: %s: %s" % (type(ex).__name__, str(ex))
)
payload = resp.json()
feature = payload.get("feature")
if not isinstance(feature, list):
raise SystemExit("server response feature must be a list")
if len(feature) == 0:
raise SystemExit(
"server returned no features; verify the image contains a "
"detectable face"
)
feat = np.asarray(feature, dtype=np.float32)
np.save(output_path, feat)
print("saved feature:", output_path, feat.shape, payload.get("model_name"))
return feat
def main():
parser = argparse.ArgumentParser(
description=(
"Upload a face image to the private InsightFace test server and "
"save the embedding with np.save."
),
)
# The --server-url value is delivered to evaluators by email.
parser.add_argument(
"--server-url", required=True,
help="Feature extraction API URL (sent privately by InsightFace)",
)
# The set of choices below is illustrative; the models actually unlocked
# for your account are listed in your MOU and may evolve over time.
parser.add_argument(
"--model-name", required=True,
choices=["buffalo", "dingo", "eagle"],
help="Recognition model to evaluate (must match an entry in your MOU)",
)
parser.add_argument("--image", required=True, help="Input face image path (PNG recommended)")
parser.add_argument("--output", required=True, help="Output .npy file path")
parser.add_argument("--timeout", type=float, default=120.0, help="HTTP timeout in seconds")
args = parser.parse_args()
extract_feature(
args.image, args.output, args.server_url, args.model_name,
timeout=args.timeout,
)
if __name__ == "__main__":
main()
5. プライバシーとデータの取り扱い
アップロードされた画像はリクエスト処理中に埋め込みを計算して返すためだけに利用されます。レスポンス送出後に元画像を保持することはなく、評価トラフィックを学習やファインチューニングに使用することもありません。
- エンドポイント URL、モデル名、取得スコアは MOU 記載の関係者以外と共有しないでください。
- エンドポイントや認証情報の漏えいが疑われる場合、24 時間以内に InsightFace 担当者に連絡してください。
6. 評価範囲と次のステップ
無償評価期間はエンドポイント発行から最長 2 週間です。期間内であればレート制限の範囲で何度でも呼び出せます。エンドポイント発行前にテストセット、前処理、指標定義を確定させ、期間中は数値の取得に集中することをお勧めします。
テスト終了後は、できるだけ早く結果を評価し、商用協業に関する結論を共有してください。