InsightFace 비공개 인식 모델 프라이빗 테스트 가이드
MOU 요건, 이미지 전처리, Python 클라이언트, 프라이버시 규칙까지 포함해 자체 데이터로 InsightFace 오픈소스/비공개 모델을 평가하는 단계별 가이드입니다.
이 가이드에서 구축할 내용
InsightFace는 상용 계약 전에 고객이 자체 검증 데이터로 정확도를 평가할 수 있도록 오픈소스/비공개 인식 모델을 호스팅형 특징 추출 API로 제공합니다.
이 가이드는 평가 전 과정을 다룹니다: 엔드포인트 수신 방법, 이미지 준비, 최소 구성 Python 클라이언트, 당사의 프라이버시·데이터 처리 규칙, 무료 평가 기간의 계약적 범위까지 포함합니다.
참고: 이 호스팅 API는 초기 평가 용도로만 제공됩니다. 최종 라이선스 산출물은 ONNX 모델 파일이며, 자체 인프라에 오프라인으로 직접 배포할 수 있습니다. 실제 운영은 이 엔드포인트에 의존하지 않습니다.
시작하기 전에
- 협력 의향, 평가 기간, 그리고 공유되는 모델 식별자에 대한 비밀유지 범위를 정의한 서명된 MOU. 엔드포인트 URL은 MOU 체결 후에만 발급됩니다.
- Python 3.9 이상에서 numpy, requests, OpenCV (opencv-python)이 설치된 환경.
- RetinaFace, SCRFD 등의 검출 결과(바운딩 박스)를 포함한, 운영 분포를 반영하는 검증 셋.
- 명확한 평가용 데이터셋과 정답 레이블, 그리고 과학적인 평가 방법론.
1. MOU 체결 및 액세스 신청
모든 비공개 모델 테스트는 귀사와 InsightFace 사이의 서명된 MOU에서 시작됩니다. MOU는 협력 의향, 평가 기간, 그리고 당사가 공유하는 모델 식별자에 대한 비밀유지 범위를 정의합니다.
API 엔드포인트 URL, 귀사가 권한을 받은 모델 이름(MOU에서 허용된 오픈소스 또는 비공개 모델), 계정별 레이트 리밋은 MOU에 명시된 기술 담당자에게 이메일로 발송됩니다. 엔드포인트는 공개되지 않으며, 권한 있는 담당자 외에는 공유해서는 안 됩니다.
- 평가 기간은 엔드포인트 발급일로부터 최대 2주입니다. 이후 사용은 상용 계약이 필요합니다.
- 각 MOU에 명시된 모델 이름만 활성화되며, 다른 이름의 요청은 서버에서 거부합니다.
- 엔드포인트가 교체되어야 하는 경우 새 URL은 동일한 담당자 목록에 다시 발송됩니다.
2. 모델 시리즈: dingo와 eagle
InsightFace 테스트 엔드포인트는 현재 dingo와 eagle 두 가지 비공개 인식 모델 시리즈를 제공합니다. 두 시리즈 모두 오픈소스 buffalo_l 인식 모델의 정확도 향상 후속 모델이며, 귀사 계정에서 실제로 활성화되는 시리즈와 모델은 MOU에 따라 결정됩니다.
배포 예산에 맞춰 시리즈를 선택하세요. dingo는 이미지당 연산량을 buffalo_l 인식 백본 수준으로 유지하면서 정확도를 높이고, eagle은 연산량을 크게 늘리는 대신 까다로운 시나리오에서 명확히 더 높은 정확도를 제공합니다.
- dingo — buffalo_l 인식 모델과 비슷한 연산량으로 정확도는 명확히 향상됩니다. 레이턴시 예산을 바꾸지 않고 수치만 끌어올리고 싶을 때 드롭인 교체용으로 적합합니다.
- eagle — 연산량이 크게 증가하지만 정확도도 명확히 더 높습니다. GPU 추론과 최고 수준의 얼굴 인식 정확도가 필요한 시나리오에 적합합니다.
- eagle과 eagle-2 — eagle 시리즈의 두 가지 모델로 정확도와 연산량은 비슷하지만 특징 벡터 길이가 다릅니다. 평가 단계에서 둘 다 테스트해 보고 저장·검색 파이프라인에 맞는 임베딩 크기를 선택하세요.
3. 대표성 있는 검증 셋 준비
비공개 모델은 인식 backbone이며 검출기는 포함되어 있지 않습니다. 한 번의 요청에는 단일 인물의 타이트하게 잘린 얼굴 한 장이 들어가고, 그에 대응하는 임베딩 한 개가 반환됩니다. 먼저 자체 검출기를 돌리고 각 크롭을 한 장씩 전송하세요.
다만, 서버에서도 제출된 헤드샷에 대해 임베딩을 추출하기 전에 2차 검출 및 정렬을 수행하므로 약간의 프레이밍 오차는 허용됩니다.
- 이미지당 얼굴 1개. 원본에 여러 명이 있으면 각각 별도의 파일로 잘라서 전송하세요.
- MOU의 데이터 조항에 따라 사용된 모든 이미지의 동의와 합법적 근거를 문서화하세요.
4. 얼굴 이미지 크롭 및 인코딩
전송 전에 검출 박스 주위에 약간의 마진을 더하세요. 0.2 정도의 expansion factor(좌·우·상·하 각 10%)를 더하면 헤어라인, 턱, 귀처럼 인식에 유용한 컨텍스트가 보존됩니다. 업로드 용량을 줄이고 싶다면 가장 긴 변을 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)
5. 특징 추출 API 호출
API는 multipart/form-data POST를 받습니다: image 필드에 이미지 한 장, model_name에 문자열을 넣어 보내고, 응답으로 model_name과 feature(L2 정규화된 임베딩)를 포함한 JSON을 받습니다. 각 임베딩은 numpy .npy로 저장하면 오프라인에서 cosine similarity 계산이 자유롭습니다.
아래 예시 클라이언트는 운영 프로토콜을 그대로 반영합니다. 그대로 실행하거나 extract_feature를 자체 평가 파이프라인에서 import하여 사용하세요. 이메일로 받은 엔드포인트 URL은 --server-url로 전달하고, 공유 저장소에 커밋되는 스크립트에 하드코딩하지 마세요.
- model_name은 MOU에 명시된 값만 허용되며, 그 외의 이름은 서버에서 거부됩니다.
- feature가 빈 배열이면 크롭에서 얼굴이 검출되지 않은 것입니다. 박스와 마진이 실제로 얼굴을 포함하는지 확인하세요.
- 이미 L2 정규화된 벡터에 대한 cosine similarity로 비교하세요. 클라이언트에서 추가로 정규화할 필요는 없습니다.
"""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.
Example invocation (model_name: eagle-2):
python client.py \
--server-url <URL delivered by email> \
--model-name eagle-2 \
--image probe.png \
--output probe.npy
"""
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", "eagle-2"],
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()
6. 프라이버시와 데이터 처리
업로드된 이미지는 요청 처리 동안 임베딩을 계산해 응답으로 돌려주는 데에만 사용됩니다. 응답 이후에는 원본 이미지를 보관하지 않으며, 평가 트래픽을 모델 학습이나 fine-tuning에 사용하지 않습니다.
- 엔드포인트 URL, 모델 이름, 반환 점수는 MOU에 명시된 인원 외에 공유하지 마세요.
- 엔드포인트나 자격 정보 유출이 의심되면 24시간 이내에 InsightFace 담당자에게 알려주세요.
7. 평가 범위 및 다음 단계
무료 평가 기간은 URL 발급일로부터 최대 2주입니다. 기간 내에는 레이트 리밋 범위에서 자유롭게 호출할 수 있습니다. 엔드포인트 발급 전에 테스트 셋, 전처리, 지표 정의를 미리 정해 두면 기간을 수치 산출에 집중해서 사용할 수 있습니다.
테스트가 끝나면 결과를 평가하여 가능한 한 빨리 상용 협력에 대한 결론을 공유해 주세요.
이 벤치마크를 프라이빗 모델로 실행하기
프로덕션용 프라이빗 인식 모델을 평가 중이라면 구조화된 엔터프라이즈 평가 프로세스를 통해 프라이빗 API 또는 온프레미스 가이드에 액세스할 수 있습니다.