상용 적용을 위한 검출기 교체에는 결과 품질도 따라와야 했다

AI Commons의 LatentSync 런타임은 립싱크 전에 얼굴을 검출하고 정렬한다. 교체의 출발점은 이 단계에서 쓰던 InsightFace buffalo_l 가중치의 상용 이용 조건이었다. 당시 검토 기록은 라이브러리의 MIT 코드와 비상업 연구용 가중치를 구별했고, 유료 제품에 적용하기 전에 초기 이미지 001·002의 가중치를 대체해야 할 대상으로 정했다.

기록에 남은 선택지는 상용 이용 문의, 검출기 교체, 기능 유예였다. 선택한 MediaPipe 0.10.11은 이미 런타임 의존성에 있었다. 레거시 mp.solutions API는 패키지에 포함된 모델을 이용할 수 있어 실행 중 외부 다운로드를 막는 구성에도 맞았다. 패치 파일을 빌드 때 상류 얼굴 검출기 위치로 복사하고 호출부를 유지해, 기존 추론 흐름 안에서 검출부를 바꿨다.

첫 교체 이미지 003은 잡이 성공으로 끝나고 당시 디코딩·길이 QC도 통과했지만 입 움직임이 거의 없었다. 출력 배열의 형태를 맞춰도 다음 모델에 잘못된 입력을 줄 수 있었다. 교체 판단에는 호출부가 기대하는 좌표와 프레임 간 움직임, 실제 립싱크 결과를 함께 확인해야 했다.

106행 배열에서 정렬에 쓰는 것은 세 중심점이었다

호출부는 InsightFace와 같은 106행 좌표 배열을 기대한다. 그러나 정렬에 쓰는 값은 이미지 왼쪽 눈썹, 오른쪽 눈썹, 코의 중심 세 점이다. 여러 인덱스의 평균을 각각 한 점으로 만들어 아핀 정렬에 사용한다.

호출부가 정렬 중심을 읽는 인덱스
정렬 기준106점 배열의 인덱스패치의 채움 방식
이미지 왼쪽 눈썹43, 48, 49, 51, 50피사체 오른쪽 눈썹의 가중 중심
이미지 오른쪽 눈썹101부터 105피사체 왼쪽 눈썹의 가중 중심
코74, 77, 83, 86선택한 코 주변 점의 평균

패치는 이 슬롯들에 의미 있는 좌표를 넣고 나머지는 얼굴 중심으로 채운다. 별도로 73번도 코 중심으로 채워 크롭의 세로 기준에 사용한다. 106개 얼굴 특징점을 모두 복원한 구현은 아니다. 상류가 새 슬롯을 읽기 시작하면 예외 대신 얼굴 중심값을 받아 조용히 틀어질 수 있다. 반환 형태를 유지하는 비용이 호출부의 실제 인덱스를 추적하는 의무로 남는다.

좌우 이름도 그대로 연결할 수 없다. MediaPipe의 왼쪽 눈썹은 피사체 기준이고, 정면 얼굴에서는 이미지 오른쪽에 보인다. LatentSync 호출부는 이미지 기준을 사용한다. 패치가 좌우를 의도적으로 교차시키는 이유다. 이름이 같다는 것보다 최종 좌표에서 왼쪽 점의 x가 오른쪽 점보다 작은지가 유효한 계약이다.

새 검출기가 맞춰야 할 대상은 이상적인 템플릿이 아니었다

003은 정렬 템플릿에 맞추려 코 중심을 콧대 쪽에서 골랐다. 하지만 학습 때 쓰인 InsightFace의 실제 세 점도 템플릿과 정확히 일치하지 않았다. 이전 검출기가 남긴 정렬 변형을 모델이 이미 보고 학습했다면, 새 검출기의 좌표를 템플릿에 가깝게 만드는 것이 같은 입력 분포를 만드는 방법은 아니다.

같은 얼굴을 비교했을 때 눈썹 사이 간격 대비 눈썹에서 코까지의 비율은 003이 0.358, InsightFace가 0.753이었다. 템플릿의 0.488을 사이에 두고 두 입력의 세로 변형 방향이 달라졌다. 이 수치는 해당 얼굴 비교의 결과이며 모든 얼굴의 고정 비율은 아니다. 기록은 이 차이로 모델이 학습 때와 다른 정렬 얼굴을 받았던 것을 입 움직임 회귀의 원인으로 설명한다.

보정은 코끝 주변의 점으로 코 중심을 옮기고, 눈썹 전체 평균 대신 안쪽 윗점에 가중치를 줬다. 전체 눈썹의 상·하 점을 같은 비중으로 평균하면 이전 검출기보다 중심이 아래쪽에 놓이는 편향이 있었다. 크롭 범위에는 전체 눈썹과 얼굴 윤곽을 계속 사용하고, 정렬 중심의 점 선택만 따로 둔다. 얼굴을 포함하는 사각형과 모델에 넣을 정렬 좌표는 같은 목적의 값이 아니기 때문이다.

좌표 평균 오차가 작아도 영상에서는 떨릴 수 있다

한 장의 얼굴에서 세 점이 비슷한 위치에 있는지를 확인하는 것만으로 충분하지 않았다. 상류는 아핀 행렬을 시간축으로 평활한다. 각 프레임의 검출 좌표가 불규칙하게 흔들리면 그 흔들림도 후속 영상에 영향을 준다. 패치는 static_image_mode=False로 독립 이미지 처리 대신 추적 모드를 선택했다.

당시 교수 클립 200프레임에서 반올림 전 정렬 3점 좌표의 2차 차분 크기 중앙값은 MediaPipe 독립 처리가 0.572, 추적 처리가 0.368, 이전 InsightFace가 0.285였다. 추적이 MediaPipe의 프레임 간 떨림을 줄였지만 이전 검출기보다 수치가 더 낮아진 것은 아니다. 이 비교를 “교체 후 모든 품질이 개선됐다”로 옮길 수 없다.

추적은 호출 순서에 의존한다. 당시 상류 파이프라인은 프레임을 하나의 반복문에서 순서대로 넘겼다. 앞으로 프레임을 섞어 병렬 처리하거나 한 검출기 인스턴스를 여러 영상에 공유하면 이 전제가 깨진다. 상태 없는 검출기와 같은 방식으로 사용할 수 없는 비용이 생겼다.

결함을 넣어도 통과하는 합성 얼굴은 검증이 아니었다

빌드 검증은 실제 패치 모듈을 임포트하고 MediaPipe 그래프를 구성해 모델 로드를 확인한다. 검은 프레임에서는 얼굴 없음 결과를 검사한다. 좌표 변환은 실제 얼굴 사진 대신 정답을 정한 합성 랜드마크로 검사한다. 모델을 실제로 구성하는 검사와 좌표 규칙을 고립해서 검사하는 부분의 범위가 다르다.

처음 합성 입력은 콧대와 코끝을 구별하지 못해 잘못된 인덱스를 골라도 같은 좌표가 나왔다. 크롭도 “코보다 위에 있다” 같은 느슨한 조건만으로는 퇴화 후 폴백 박스를 통과시킬 수 있었다. 최종 검증은 콧대와 코끝의 높이를 다르게 놓고, 코 y가 400이고 턱 y가 600일 때 크롭 상단이 정확히 200인지 확인한다.

코 위치·눈썹 대 코 비율·눈썹 가중·추적 모드의 네 검사를 추가하고 양방향 변이로 확인했다. 잘못된 값에서 실패하는지와 정상 값에서 통과하는지를 함께 본 것이다. 다만 추적 모드 검사는 설정값을 고정하는 검사다. 실제 영상의 떨림을 매번 측정하거나 새로운 얼굴에서 립싱크 품질을 보증하지는 않는다.

회귀를 고쳤다는 것과 이전 모델보다 낫다는 것은 다르다

상류 eval_sync_conf의 SyncNet 신뢰도
비교 클립002 · InsightFace005 · 보정한 MediaPipe
상류 데모 쌍8.348.14
교수 와이드6.916.24
클로즈업4.804.90

세 클립의 방향은 일정하지 않다. 005를 이전 모델보다 우수한 검출기라고 결론낼 근거는 없다. 별도로 기록된 003의 교수 와이드 값은 4.54였다. 보정한 005의 6.24는 이 회귀에서 벗어난 비교 결과로 읽을 수 있지만, 세 클립의 점수가 모든 입력의 품질이나 사용자 만족도를 대표하지는 않는다.

성공 리포트와 길이 QC는 입 움직임을 검사하지 않으므로 모델 교체 때는 실제 추론 결과와 립싱크 평가가 추가로 필요하다. 외부 리포트의 런타임 검증은 미확인 필드를 성공으로 받아들이는 문제를 막는다. 여기에 적절한 필드가 모두 있는 결과의 시각적 품질까지 대신 판정하지는 못한다. 유효 결과와 비용의 관계는 아바타 영상 비용 기록으로 이어진다.

마지막 경계는 실행 환경이다. 후속 문서는 005 이미지와 배치 잡 정의 개정 6이 만들어졌다고 기록하면서도, 실제 실행 설정이 그 개정을 가리키는지와 001·002 옛 이미지 정리를 남은 일로 적었다. 소스와 새 이미지가 준비됐다는 사실만으로 모든 실행 환경의 교체가 끝났다고 판단할 수 없다. 부품 교체의 완료 조건에는 호출 좌표, 시간축, 결과 품질, 실제 선택된 런타임을 함께 넣어야 했다.