8,319장에서 우리 둘만 —
AI가 찾은 27장, 그리고 못 찾은 것들
제주 바다와 오름을 3일 동안 달린 2026 제주국제트레일러닝 대회. 끝나고 공식 사진 폴더를 받았는데 — 8,319장이었어요. 수백 명 러너가 섞인 그 더미에서 "우리 둘만 나온 사진"을 찾는 일에 AI 얼굴인식을 붙여봤어요. 되는 것과 안 되는 것이 생각보다 선명하게 갈렸고, 최종은 27장이었어요. 그 과정에서 건진 게, 사실 사진보다 더 재밌었고요.
018,319장의 벽
트레일 대회엔 공식 사진사가 코스 곳곳에 서 있어요. 그중에서도 제주국제트레일러닝 대회는 사진이 잘 나오기로 유명해요. 거친 코스 위에서도 러너의 표정과 순간을 기가 막히게 담아주거든요. 3일 동안 세 스테이지를 돌며 찍힌 사진이 참가자 모두에게 공유됐는데, 열어보니 8,319장이었어요. 한 장 한 장이 좋아서, 오히려 버리기가 더 아까웠죠.
그 안에서 제가 찾고 싶었던 건 딱 하나 — 둘이서만 나온 사진이었어요. 다른 러너 수백 명 사이에서요. 8천 장을 눈으로 넘기는 건 현실적으로 무리였고, 그렇다고 포기하긴 아까웠어요. 그래서 생각했죠. 이거야말로 AI한테 시켜볼 일이다.
02일단 도구를 만들었어요
방향은 단순했어요. 오픈소스 얼굴인식 모델(ArcFace 계열 — 얼굴을 숫자 벡터로 바꾸는 방식이에요)로 8,319장을 전부 훑어 얼굴을 검출하고, "우리 둘"의 얼굴과 닮은 사진만 추리는 것. 사적인 사진이라 어디에도 올리지 않고 노트북 안에서만 돌렸어요.
얼굴인식이라고 하면 마법 같지만, 원리는 의외로 담백해요. AI 모델이 얼굴 사진 한 장을 받으면, 그걸 512개짜리 숫자 목록(벡터, '임베딩'이라고 불러요)으로 바꿔요. 같은 사람의 얼굴은 비슷한 숫자로, 다른 사람은 다른 숫자로 나오도록 학습돼 있죠. 얼굴을 좌표로 옮긴다고 보면 돼요.
두 사진이 닮았는지는, 이 두 숫자 목록이 얼마나 같은 방향을 가리키는지(코사인 유사도)로 재요. 1에 가까울수록 닮은 거예요. 그리고 "이 값 이상이면 같은 사람"이라고 정하는 경계가 바로 임계값이고요.
사실 이건 여러분이 매일 쓰는 기능이에요. 구글 포토, 아이폰·맥 '사진' 앱의 '인물별'(또는 '사람들') 앨범 — 얼굴을 숫자(임베딩)로 바꿔 비슷한 것끼리 자동으로 묶는, 똑같은 원리거든요. 다만 사용법이 반대예요. 그 앱들은 비슷한 얼굴끼리 알아서 묶어두고 이름은 나중에 붙이게 해요(군집). 저는 반대로 "이 사람을 찾아줘"라고 기준 얼굴을 먼저 준 거고요(검색). 같은 좌표 공간을 쓰지만, 한쪽은 묶고 한쪽은 찾는 거죠.
먼저 나온 숫자 하나가 좌표가 됐어요 — 얼굴이 정확히 2명인 사진이 2,210장. "둘만 나온 사진"이라면 무조건 이 안에 있어야 하니까요. 8,319장이 갑자기 2,210장으로 줄었어요. 여기서부터 좁히면 되겠다 싶었죠.
03선명한 셀카가 안 통했어요
두 사람을 알려주려면 "기준 얼굴"이 필요했어요. 저는 당연히 제일 잘 나온 정면 사진 몇 장을 골라 줬죠. 그런데 매칭 결과가 스무 장 남짓에서 더 안 늘어나는 거예요. 참가자가 3일 동안 뛰었는데 사진이 스무 장이라니, 이상했어요.
그래서 기준을 점점 느슨하게 풀어봤어요. 그런데 아무리 풀어도 결과가 거의 안 변했어요. 바로 여기서 첫 교훈을 얻었어요 — 기준을 바꿔도 결과가 안 움직이면, 그건 기준 문제가 아니다. 다른 데 원인이 있다는 신호죠. 이걸 모르면 숫자만 만지며 한참을 헤매게 돼요.
진짜 원인은 반직관적이었어요. 선명한 정면 셀카일수록, 달리며 찍힌 실제 사진과는 오히려 안 맞았어요. 얼굴인식은 얼굴을 숫자 묶음으로 바꿔서 비교하는데, 깔끔한 정면과 — 측면으로 돌아가고 역광에 표정까지 일그러진 현장 컷은 그 숫자가 너무 멀더라고요. 우리가 "잘 나왔다"고 아끼는 사진일수록 현장과 동떨어진다는 게, 좀 얄궂었어요.
흐릿한 더미에서 특정 인물을 찾을 땐, 깨끗한 사진 한 장이 아니라 각도·상황이 제각각인 기준을 여러 장 줘야 해요. 그리고 설정을 바꿔도 결과가 안 움직이면, 더 만지지 말고 원인을 의심하세요.
04"둘 다"를 조건으로 걸었더니
한 사람만 맞히려 하면 닮은 러너가 자꾸 끼어들었어요. 기준을 낮출수록 오탐이 쏟아졌고요. 그런데 발상을 바꿨어요 — "두 사람이 동시에 들어있는 사진"만 찾으면 어떨까?
이게 의외로 강력한 안전장치였어요. 한 명을 잘못 맞힐 확률은 있어도, 두 사람을 한 사진에서 동시에 잘못 맞힐 확률은 거의 0이거든요. 그래서 "둘 다 맞아야 한다"는 조건을 걸어두면, 기준을 과감히 낮춰도 오탐이 안 생겨요. 두 신호를 동시에 요구하는 것만으로 정밀도가 확 올라가는 거죠.
한 사람을 잘못 맞힐 확률이 10%라고 해볼게요. 그럼 사진 한 장에서 두 사람을 동시에 잘못 맞힐 확률은, 대략 그 둘을 곱한 값이 돼요.
그래서 임계값을 조금 낮춰 한 명당 오탐이 늘더라도, "둘 다 맞아야"라는 조건이 그걸 곱으로 눌러줘요. 느슨하게 풀면서도 깨끗하게 건지는 비결이죠. (두 사람이 서로 독립적으로 틀린다는 가정이 깔려 있긴 해요.)
그렇게 확신할 수 있는 커플 사진이 모이면, 이번엔 그 사진 속 진짜 현장 얼굴을 다시 기준에 보탰어요. 깔끔한 셀카 대신, 실제로 달리며 찍힌 얼굴로 기준을 채워나간 거예요. 그러자 한 구간에 갇혀 있던 매칭이 다른 구간으로 조금씩 번지기 시작했어요.
오탐이 무서워 기준을 못 낮추겠다면, 두 가지가 동시에 맞아야 하는 조건(AND)을 안전벨트로 거세요. "동시에 틀릴" 확률은 곱으로 작아져서, 더 과감하게 풀 수 있어요.
05'시간으로 찾자'가 막힌 곳
여기서 좋은 아이디어가 떠올랐어요. 사진사는 한 사람을 몇 초간 연속으로(버스트) 찍어요. 그러니 내 사진이 찍힌 시각을 알면, 그 ±몇 초 안의 사진은 다 나일 거잖아요. 얼굴이 안 보여도 시간으로 잡을 수 있겠다 싶었죠.
그런데 함정이 있었어요. 제가 가진 사진의 시간 정보가 찍은 날(4월)이 아니라 저장한 날(5월)로 덮여 있었어요. 사진을 다운로드하거나 다시 저장하면, 원본 촬영시각이 날아가고 그 자리에 저장 시각이 들어오거든요. "시간으로 찾자"는 시작도 못 하고 막혔죠.
사진 파일 안에는 픽셀(그림)만 있는 게 아니에요. 언제·어떤 기기로·어떤 설정으로 찍었는지가 함께 적혀 있는데, 이 메모를 EXIF라고 불러요. 그중 '촬영 시각'이, 사진을 시간순으로 묶을 때 쓰는 값이고요.
문제는 — 사진을 다운로드하거나 다른 앱으로 다시 저장하면 이 촬영 시각이 사라지거나 '저장한 시각'으로 덮이는 경우가 많다는 거예요. 그래서 원본 아카이브에선 멀쩡하던 시간이, 내 손에 온 사진에선 엉뚱한 값이 돼 있었던 거죠.
다행히 아카이브 원본의 시각은 멀쩡했어요. 그래서 이미 확신한 사진을 기준 삼아 ±몇 초 버스트를 끌어왔는데 — 이번엔 반대 문제가 터졌어요. 사람이 몰리는 체크포인트에선 그 몇 초 사이 지나간 다른 러너까지 한 무더기 딸려왔거든요. 사진은 늘었지만 "남"이 잔뜩이었어요. 그래서 이 방식은 도로 물렸어요.
사진의 시간으로 뭔가 하려면, 그 시각이 '촬영'인지 '저장'인지부터 확인하세요(다운로드하면 덮여요). 그리고 — 많이 찾는 게 잘 찾는 건 아니에요. 양을 욕심내다 "남"이 섞이면, 후퇴할 줄도 알아야 해요.
06안 되는 건 안 되더라고요
마지막 벽은 해변이었어요. 물장구 치고 점프하는 컷들 — 얼굴이 작고, 숙여지고, 물보라에 가려 있었어요. 얼굴인식은 여기서 손도 못 댔어요. 시간으로도(위의 함정), 배경이 비슷한 장면끼리 묶는 방법으로도 두 사람만 콕 집어내질 못했고요.
왜 끝내 다 못 잡았는지엔 기술적인 이유가 있어요. 앞에서 "이 점수 이상이면 같은 사람"의 경계를 임계값이라고 했죠. 그 경계를 어디 두느냐가 결과를 통째로 바꾸는데 — 정답이 없어요.
대부분의 진짜 매칭은 점수가 높게 나와 '다른 사람'과 깔끔히 갈려요. 그런데 측면으로 돌거나, 흐릿하거나, 얼굴이 작게 찍힌 진짜 내 사진은 점수가 뚝 떨어져, '닮은 남'과 같은 구간으로 내려와요. 해변 컷이 딱 여기였죠.
그래서 저는 컷을 감으로 찍지 않았어요. 진짜 매칭과 노이즈의 점수가 실제로 어디서 갈리는지 분포를 직접 떠본 뒤, 그 골짜기에 경계를 놓았죠. 그래도 한계는 또렷해요 — 경계를 높이면 어려운 내 사진을 놓치고(못 찾음 · 재현율↓), 낮추면 닮은 남이 섞여요(오탐 · 정밀도↓). 한쪽을 줄이면 반대쪽이 느는 시소, 머신러닝에서 말하는 정밀도-재현율 트레이드오프예요. "전부 다 찾으면서 한 장도 안 틀리게"는 어떤 얼굴인식도 못 해요. 구글 포토·애플 사진이 같은 사람을 두 명으로 쪼개거나, 다른 사람을 한 명으로 합쳐버린 적 있죠? (그래서 수동으로 '병합'하게 해주고요.) 그게 바로 이 시소예요. 그래서 앞서 섹션 04의 '둘 다'처럼, 점수 하나에만 기대지 않는 안전장치로 시소를 통째로 기울이는 거예요.
한참 알고리즘을 쥐어짜다가, 결국 인정했어요. 안 되는 건 안 되더라고요. 그런데 그 지점에서 더 중요한 걸 배웠어요 — 자동화의 끝은 "끝까지 자동으로"가 아니라, 사람에게 넘길 자리를 정확히 아는 것이라는 거요.
다행히 그 해변 컷 몇 장은 우리가 이미 따로 저장해둔 게 있었어요. 그래서 얼굴인식이 끝내 못 잡은 그 자리는, 손에 있던 사진을 그대로 더했어요. 기계가 8천 장의 큰 더미를 훑고, 기계가 놓친 몇 장은 사람이 채우는 — 그렇게 역할을 나누니 오히려 깔끔했어요.
그러고 보니, 더 쉬운 단서가 코앞에 있었어요 — 가슴에 단 배번(참가 번호)이요. 얼굴 대신 그 숫자로 찾았다면 어땠을까? 실제로 큰 대회 사진 서비스들은 얼굴만이 아니라 이 번호를 기계로 읽어(OCR) 사진을 분류해요. 정면에 읽으라고 큼직하게 박힌 숫자라, 흔들리고 가려지는 얼굴보다 안정적이거든요. 제가 처음부터 번호로 좁혔다면 한결 수월했을지도 몰라요. 다만 — 트레일에선 자켓·조끼·물보라에 번호가 가려지기 일쑤고, 달리는 사진 속 숫자를 읽는 건 책 글자 읽기보다 훨씬 어려워서, 이것도 "82% 확신"처럼 점수로 나오는 또 하나의 불완전한 단서예요.
그래서 결론은 같아요 — 한 가지 단서에만 기대지 않는 것. 구글 포토·애플 사진도 얼굴이 안 보이면 다른 걸로 메워요(구글은 촬영 시각·같은 옷을, 애플은 상체까지). 제가 손을 뻗은 '시간으로 찾기'도 같은 맥락이었고요. 거대 기업도 '얼굴만으론 부족'한 벽은 똑같아서, 여러 단서를 겹쳐 쓸 뿐이에요. (애플은 그걸 전부 기기 안에서 — 온디바이스로 — 처리해 사진이 밖으로 안 나가요. 제가 노트북에서만 돌린 것과 같은 결이고요.)
알고리즘이 한계에 부딪히면, 무리하게 밀어붙이지 마세요. 기계가 큰 더미를 훑고, 그래도 못 잡는 몇 장은 사람이 채우면 돼요. "전부 자동"을 고집하지 않는 게 더 빠를 때가 많아요.
078,319장에서, 우리 둘만 27장
정리하면 이런 여정이었어요. 8,319장 → 얼굴이 둘인 2,210장 → 얼굴매칭으로 추린 21장 → 닮은 사람 오탐을 빼고, 같은 컷 중복을 정리하고, 얼굴인식이 못 잡은 해변 컷을 직접 더해 → 최종 27장.
27장이 적어 보일 수 있어요. 그런데 이건 수백 명이 뒤섞인 공용 아카이브에서 "우리 둘"만 솎아낸 숫자예요. 그리고 솔직히, 진짜로 남은 건 사진 27장이 아니었어요.
제가 건진 건 이런 감각이에요 — 얼굴인식은 셀카엔 강하고 추억엔 약하다는 것, 깔끔한 기준일수록 현장과 멀어진다는 역설, "둘 다"라는 조건이 주는 안전함, 그리고 안 되는 지점에서 멈추는 법. 이런 건 설명으로 들으면 그냥 흘러가요. 직접 8천 장에 부딪혀봐야 몸에 남더라고요. 정보로 아는 것과 겪어서 아는 것은 정말 다르거든요.
그리고 이건 요령이 아니에요. 막히고, 우회하고, 또 막히길 반복하면서 찾은 제 리듬에 가까워요. 다음 대회 사진이 또 한 무더기 쌓이면, 이번에 만든 걸 그대로 다시 꺼내 쓸 거예요. 한 번 끝까지 겪어봤다는 게, 그런 값을 하더라고요.
마지막으로 — 애초에 골라낼 사진이 이렇게 많았던 건, 거친 코스를 3일 동안 함께 달리며 우리의 순간을 멋지게 남겨준 제주국제트레일러닝 대회 덕분이에요. 이렇게 사진으로 추억을 남겨주셔서 진심으로 감사해요. 덕분에 우리 둘의 제주가 27장으로 남았어요. 🙏
얼굴인식은 셀카엔 강하고 추억엔 약해요. 그래도 8천 장을 27장으로 줄여준 건 충분히 고마웠고요. 무엇보다 — 이런 건 직접 부딪혀봐야 체감돼요. 안 써본 도구로 오늘 한 번, 그냥 부딪혀보세요.