얼굴 인식 모델 선정 가이드: 1:1·1:N 테스트와 임계값 결정
FRVT 방법론에 맞춘 실무 가이드입니다. InsightFace 인식 모델을 선정하고, 1:1·1:N 벤치마크를 설계하며, 임계값을 결정하고, InsightFace 오픈소스 팩에서 상용 모델로 전환할 시점까지 다룹니다.
이 가이드에서 구축할 내용
얼굴 인식 시스템의 사고는 코드보다 모델 선정과 임계값 조정 단계에서 더 많이 발생합니다. 공개 리더보드 상위 모델이라도 운영 포인트, 인구 분포, 촬영 품질, 갤러리 규모가 다르면 실제 데이터에서 다르게 동작할 수 있습니다.
본 가이드는 NIST FRVT 방법론에 맞춘, 벤더 중립적인 평가 프레임워크를 제시합니다. 1:1 검증과 1:N 식별의 차이, 실제로 보고해야 하는 지표, 재현 가능한 테스트 설계, InsightFace 오픈소스 팩의 공개 수치 수준, 그리고 InsightFace 상용 모델이 합리적인 선택이 되는 조건과 그 "더 높은 정확도"가 구체적으로 어떤 수치를 의미하는지 다룹니다.
시작하기 전에
- insightface Python 패키지 또는 ONNX Runtime을 통해 얼굴 검출, 정렬, 임베딩 추출을 직접 실행할 수 있는 수준.
- 운영 트래픽의 인구 분포, 연령대, 자세, 조명, 가림(마스크·안경·머리카락), 카메라 품질, 촬영 거리를 대표하는 검증 데이터셋.
- ROC, DET, 유사도 분포 분석을 위한 numpy와 scikit-learn 기본 활용 능력.
- 단순 정확도 %가 아니라 FMR 또는 FPIR로 명시된 목표 운영 포인트(예: FMR = 1e-5).
1. 1:1 문제인지 1:N 문제인지부터 가른다
1:1 검증은 "이 사람이 본인이 맞는가?"에 답하는 작업입니다. 프로브 템플릿 1건과 등록 템플릿 1건을 비교하고 유사도 점수와 동일/비동일 판정을 반환합니다. 대표 사례는 단말 잠금 해제, KYC(셀카 vs 신분증), 결제 확인, 재인증입니다.
1:N 식별은 "등록된 N명 중 이 사람이 누구인가, 혹은 누구도 아닌가?"에 답하는 작업입니다. 프로브 1건을 N건의 갤러리와 비교해 후보 리스트를 반환합니다. 대표 사례는 출입 게이트, 워치리스트 알림, 출퇴근 관리, 중복 등록 검출입니다. 1:1 LFW에서 상위인 모델이 10^5나 10^6 규모의 1:N 갤러리에서도 자동으로 상위인 것은 아니며, NIST가 FRVT 1:1과 FRVT 1:N을 별개의 보고서로 발행하는 이유가 바로 여기에 있습니다.
- 1:1 트래픽은 동일인 비교가 다수이며, 오인식 비용은 트랜잭션 단위로 발생합니다.
- 1:N 트래픽은 비동일인 비교가 다수이며(특히 워치리스트는 대다수 프로브가 갤러리에 없습니다), 같은 임계값에서도 오인식률은 갤러리 규모 N에 비례해 증가합니다.
- 워크로드를 먼저 정합니다. 같은 backbone이라도 1:1과 1:N에서 임계값은 달라집니다.
2. FRVT 스타일 지표를 채택한다
단일한 "Accuracy" 수치로 평가하는 방식을 버립니다. FRVT 보고서는 고정된 운영 포인트에서 두 가지 상호 보완적인 오류율을 함께 보고하고, 트레이드오프가 보이도록 곡선으로 시각화합니다.
1:1에는 FMR(False Match Rate)과 FNMR(False Non-Match Rate)을 사용합니다. 목표 FMR(보통 1e-4, 1e-5, 1e-6)을 정한 뒤 그 지점의 FNMR을 보고합니다. 1:N에는 FPIR(False Positive Identification Rate)과 FNIR(False Negative Identification Rate)을 사용합니다. 갤러리 규모 N, 랭크, 그리고 closed-set(프로브가 항상 갤러리에 있음) 또는 open-set(없을 수 있음) 여부를 반드시 함께 명시합니다.
- 보고 수치에는 항상 임계값을 함께 표기합니다. FMR이 빠진 FNMR, FPIR이 빠진 FNIR은 의미가 없습니다.
- ROC 대신 DET(Detection Error Tradeoff) 곡선을 그립니다. 낮은 오류율 영역에서 더 잘 읽힙니다.
- 전체 평균만이 아니라 인구 계층별로 수치를 보고합니다. FRVT의 인구학적 효과 연구와 같은 사고방식입니다.
3. 방어 가능한 테스트셋을 설계한다
동일인 페어와 비동일인 페어는 각각 따로 샘플링합니다. 1:1에서 FMR = 1e-6을 통계적으로 신뢰성 있게 추정하려면 대략 10 / FMR = 10^7 수준의 비동일인 비교가 필요합니다. 동일 프로브를 여러 페어에 재사용해도 무방하지만, 유효 표본 크기는 정직하게 표기해야 합니다.
인구 그룹, 촬영 기기, 실내/실외, 등록과 프로브 간 연령 차이, 가림 유형, 머리 자세 등으로 계층화하고, 평균만이 아니라 계층별 수치를 보고합니다. 학습·파인튜닝·사전학습(Glint360K, WebFace42M, MS1MV3 등)에 사용된 데이터와 테스트셋은 엄격히 분리하고, 출처와 동의 여부를 문서화합니다.
- 최소한 10 / 목표 FMR 만큼의 비동일인 비교를 사용합니다. 그보다 적으면 FMR 추정의 신뢰구간이 너무 넓어집니다.
- 테스트셋은 동결합니다. 계속 튜닝 대상으로 사용되는 테스트셋은 사실상 검증셋이 됩니다.
- 모델이나 전처리를 바꿀 때마다 다시 돌리는, 작고 잠긴 "골든 셋"을 별도로 유지합니다.
4. 임베딩, 유사도, 임계값 계산
패키지의 공식 전처리를 그대로 사용합니다. 검출은 RetinaFace 또는 SCRFD, 5점 정렬, 112x112 RGB 크롭, 인식 팩에 동봉된 mean/std입니다. 전처리 불일치는 공개 수치가 재현되지 않는 가장 흔한 원인입니다.
L2 정규화 임베딩에 대한 코사인 유사도로 통일합니다. InsightFace Python API의 face.normed_embedding이 정확히 이를 제공합니다. 임계값은 검증 분할에서 정해 동결한 뒤 테스트셋에서는 평가만 합니다. 테스트셋에서 임계값을 고르면 결과가 부풀려집니다.
- InsightFace 인식 팩의 1:1 임계값은 FMR = 1e-4 ~ 1e-5 구간에서 대체로 코사인 0.30 ~ 0.45에 위치합니다. backbone, 학습 데이터, 운영 인구에 따라 달라지므로 항상 다시 계산하세요.
- 배포 환경 간 갤러리 분포가 달라지면 z-norm·t-norm 같은 점수 정규화가 도움이 됩니다.
- 파인튜닝을 했다면 임계값도 반드시 다시 산정합니다. 모델 버전 간에 절대 전용하지 않습니다.
import numpy as np
from insightface.app import FaceAnalysis
app = FaceAnalysis(
name="buffalo_l",
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
)
app.prepare(ctx_id=0, det_size=(640, 640))
def embed(image_bgr):
faces = app.get(image_bgr)
if not faces:
return None
# use the largest detected face
face = max(faces, key=lambda f: (f.bbox[2] - f.bbox[0]) * (f.bbox[3] - f.bbox[1]))
return face.normed_embedding.astype(np.float32) # already L2-normalized
def cosine(a, b):
return float(np.dot(a, b)) # both vectors are already L2-normalizedimport numpy as np
# scores collected on a held-out validation split
genuine = np.array(genuine_scores) # same person pairs
impostor = np.array(impostor_scores) # different people pairs
# pick the operating point you must defend in production
target_fmr = 1e-5
# threshold = score above which (1 - target_fmr) of impostors fall
threshold = float(np.quantile(impostor, 1.0 - target_fmr))
fnmr = float(np.mean(genuine < threshold))
print(f"threshold = {threshold:.4f}")
print(f"FNMR @ FMR = {target_fmr:.0e} -> {fnmr:.4f}")import numpy as np
# gallery_emb: (N, d) L2-normalized embeddings of enrolled identities
# probe_emb: (P, d) L2-normalized embeddings of probes
# probe_label: (P,) ground-truth gallery index, or -1 for non-mate probes (open-set)
scores = probe_emb @ gallery_emb.T # (P, N) cosine similarity
top1_idx = scores.argmax(axis=1)
top1_score = scores.max(axis=1)
# choose threshold from validation, then evaluate FPIR / FNIR
threshold = 0.40
mate = probe_label >= 0
non_mate = ~mate
fnir = float(np.mean(
(top1_idx[mate] != probe_label[mate]) | (top1_score[mate] < threshold)
))
fpir = float(np.mean(top1_score[non_mate] >= threshold))
print(f"FNIR = {fnir:.4f}, FPIR = {fpir:.4f} at threshold {threshold:.2f}")5. InsightFace 오픈소스 모델 벤치마크
insightface Python 패키지는 검출기와 인식 backbone을 묶어 즉시 쓸 수 있는 모델 팩을 배포합니다. 가장 많이 쓰이는 인식 팩은 buffalo_sc·buffalo_s(모바일/엣지), buffalo_m(균형), w600k_r50 헤드의 buffalo_l(서버 기본), glintr100 헤드의 antelopev2(대형 서버)이며, Model Zoo에는 R50·R100 ArcFace의 원본 가중치도 공개되어 있습니다.
표준 학술 벤치마크(LFW, CFP-FP, AgeDB-30, IJB-B, IJB-C)에서의 공개 수치 기준으로, 이들 팩은 대략 다음 수준대에 위치합니다. 참고용이며 자체 데이터에서 반드시 재측정하세요.
- LFW 1:1 정확도: 99.50%(모바일 MBF) ~ 99.85%(R100, w600k_r50). LFW는 포화되어 있어 헬스 체크 용도 이상의 의미는 없습니다.
- CFP-FP(정면 vs 측면): 라인업 전반 96 ~ 99%, 측면에서는 R100 급이 명확히 앞섭니다.
- AgeDB-30: 라인업 전반 96 ~ 98.5%, 대형 팩이 연령차에 더 강합니다.
- IJB-C TAR @ FAR = 1e-4: MBF/모바일 약 90 ~ 93%, R50 약 95 ~ 96%, R100·w600k_r50·glintr100 약 96 ~ 97.5%.
- MFR(Multi-racial Face Recognition, ICCV-21·22 챌린지 프로토콜로 African·Caucasian·East Asian·South Asian·Mixed 코호트를 FMR = 1e-6 / 1e-5에서 평가): 모델이 작아질수록 최우수와 최약 코호트의 TAR 격차가 벌어집니다. R100급(w600k_r50, glintr100)은 코호트 간 격차가 보통 수 퍼센트포인트 이내, R50은 한 자릿수 중반대까지 벌어지며, 모바일 MBF는 가장 어려운 코호트에서 두 자릿수 격차를 보일 수 있습니다. 운영 포인트를 확정하기 전에 반드시 자사 인구 분포에서 직접 재현해 보세요.
- 처리량(단일 GPU, batch 32, FP16): MBF는 초당 수천 임베딩, R100은 초당 수백 수준. 반드시 운영 하드웨어에서 측정합니다.
6. 워크로드에 맞는 오픈소스 팩 선택
대부분의 제품 개발에서 선택지는 두 가지 오픈소스 팩으로 충분합니다. 모바일·엣지에는 buffalo_s(보다 가벼운 변형 buffalo_sc 포함), 서버에는 buffalo_l을 사용합니다.
buffalo_s·buffalo_sc는 온디바이스 얼굴 잠금 해제, 모바일 SDK 통합, 임베디드 박스 등 절대 정확도보다 지연 시간과 바이너리 크기가 더 중요한 워크로드에 적합한 기본값입니다. buffalo_l(w600k_r50)은 1:1 검증, 수십만 ID 규모까지의 1:N 식별, 목표 FMR 1e-5 수준 등 모든 서버 측 인식의 기본값입니다.
- 모바일·엣지: buffalo_s를 선택하고, 메모리나 연산 예산이 더 빠듯하면 buffalo_sc를 선택합니다.
- 서버: buffalo_l을 선택합니다. 당사가 제공하는 가장 강력한 오픈소스 인식 팩으로, 협조적 촬영 기반의 검증·식별 시나리오 대부분을 충분히 커버합니다.
- 협조적 촬영 환경에서 FMR >= 1e-5 수준으로 운영하는 대다수 제품 기능에는 오픈소스 팩으로 충분합니다. 그 이상 요건은 다음 절을 참고하세요.
7. InsightFace 상용 모델로 전환해야 할 시점
InsightFace 상용 인식 모델은 훨씬 더 크고 다양한 ID 셋과 자체 손실 함수·학습 레시피로 학습되며, 명시적인 운영 포인트와 서명된 모델 아티팩트를 함께 제공합니다. "오픈소스 모델에 파라미터만 더 늘린" 것이 아닙니다.
구체적인 수치로 보면, 인구 균형이 맞는 사내 1:1 프로토콜의 FMR = 1e-6에서 상용 모델은 가장 강한 오픈소스 팩 대비 FNMR을 통상 2 ~ 5배 낮춥니다(예: 마스크·큰 자세·저해상도 등 어려운 부분집합에서 FNMR이 약 5 ~ 8%에서 1 ~ 2%로 감소). 갤러리 100만 명 이상의 인구 균형 1:N 프로토콜에서도 고정 FPIR 기준 FNIR이 비슷한 비율로 감소하며, 엄격한 운영 포인트에서 최우수와 최약 인구 부분집단 사이의 격차가 좁혀집니다.
전환 결정을 자사 데이터에서 손쉽게 검증할 수 있도록, 사전 협력 계약(NDA·파일럿 계약) 체결 후 상용 인식 모델에 대한 2주간 무료 평가를 제공합니다. 평가 기간 동안 상용 모델 아티팩트 또는 호스팅 API에 기간 한정으로 접근할 수 있으며, 본 가이드에 설명된 FRVT 방식의 1:1·1:N 테스트를 그대로 수행하고, 현재 사용 중인 오픈소스 팩과 수치를 직접 비교한 후 정식 상용 계약 여부를 결정할 수 있습니다.
- FMR <= 1e-6 수준에서 운영해야 하는 경우(국경 통제, 결제 인가, 규제 KYC 등)에는 상용 모델을 선택합니다.
- 갤러리가 10만 ~ 100만 명을 넘고 Rank-1 안정성이 중요한 경우 상용 모델을 선택합니다.
- 공정성 감사에서 엄격한 운영 포인트의 인구 부분집단 간 격차를 좁혀야 하는 경우 상용 모델을 선택합니다.
- 운영 환경에 강한 가림, 큰 자세, 저해상도(눈동자 간 거리 약 48 픽셀 미만), 비협조적 촬영 같은 어려운 조건이 포함되는 경우 상용 모델을 선택합니다.
- 엔터프라이즈 SLA, 온프레미스 라이선스, PAD/라이브니스 통합, 서명된 모델 아티팩트, 계약 기반 보호 조항이 필요한 경우 상용 모델을 선택합니다.
- 사전 협력 계약 체결 후, 정식 상용 계약 이전에 자사 데이터로 2주간 무료 평가를 진행해 보세요.
8. 운영 배포와 지속 평가
모델 아티팩트(암호학적 해시), 전처리 코드 경로, 임계값, 지표 정의를 하나의 릴리스 단위로 함께 잠급니다. 전처리 변경은 FMR을 조용히 이동시키므로 가중치 못지않게 전처리의 버전 관리가 중요합니다.
최소 분기 1회 이상, 최신 운영 샘플로 다시 평가합니다. 가장 중요한 라이브 지표는 운영 임계값에서의 FMR(새로운 임포스터 셋 기준)이며, 비즈니스에 약속한 운영 포인트가 지금도 유지되고 있는지를 보여줍니다.
- FMR/FNMR 드리프트, 오경보율, 운영자 오버라이드율, 인구 부분집단 간 격차를 함께 추적합니다.
- 롤백 계획을 둡니다. 임계값과 모델은 함께 버전 관리하며, 둘 중 하나만 롤백해서는 안 됩니다.
- 모델을 교체할 때는 임계값을 다시 산정하고 운영 포인트를 재공지한 뒤에 운영 트래픽을 전환합니다.