Big Project · AI's EYE 14

카메라별 맞춤 규칙으로 직원 판정 정확도 높이기

직원 구역 안에 있는 사람을 직원으로 분류하는 규칙 하나면 모든 CCTV에 적용할 수 있을 것 같다. 왜 카메라마다 임계값과 ID 제한이 달라졌는지 궁금하다.

근거 · 프로젝트 문서 · 코드 · 테스트

1장: 보편적 규칙의 예측 불가능성

솔라는 태블릿 화면에 떠 있는 한 줄짜리 평가 요약을 손가락으로 툭툭 건드리고 있었다. 「직원 ROI 공통 규칙을 카메라별 임계값과 10초 가림 보정으로 바꾼 평가.」 제목은 명료했지만, 솔라는 오히려 그 명료함이 마음에 걸렸다. 하나의 개념을 잘 정의해서 하나의 규칙으로 만들면 가장 효율적이지 않을까? ‘직원’이라는 개념은 어느 카메라에서나 동일할 텐데, 왜 이렇게 복잡한 맞춤 규칙들을 만들어야만 했을까.

“언니, 이것 좀 봐. ‘직원’을 판정하는 규칙을 만든다면서 결국 카메라마다 다른 규칙을 적용했대. 처음부터 그냥 잘 만든 공통 규칙 하나를 쓰는 게 낫지 않았을까? ‘직원 구역 안에 있는 사람’이라는 정의는 어디서나 똑같잖아. 이걸 복잡하게 만드는 게 오히려 정확도를 떨어뜨릴 것 같은데.”

태블릿 빛이 솔라의 미간에 가는 그림자를 만들었다. 솔라의 말에는 단순하고 보편적인 원칙에 대한 믿음이 묻어났다.

루나는 소파 맞은편에서 조용히 책을 읽다 고개를 들었다. 솔라가 내민 태블릿을 잠시 들여다본 루나는 시선을 다시 솔라에게로 옮겼다.

“솔라 네 말이 맞아. 그들이 가장 먼저 시도했던 것도 바로 그거였어. 모든 카메라에 적용할 수 있는 하나의 공통 규칙.”

“그렇지? 그게 당연한 순서잖아. 그런데 왜…”

“그 규칙이 실패했기 때문이야.”

루나의 대답은 짧았다. 솔라의 얼굴에 떠오른 ‘그럴 리가’ 하는 표정을 읽은 루나가 덧붙였다.

“아주 심하게 실패했어. 결과 보고서에 따르면, ‘공통 bbox 30% 규칙’을 적용한 첫 번째 검증에서 ‘심한 과대 판정’이 나타났다고 해.”

“과대 판정이라고? 직원이 아닌 사람을 직원으로 봤다는 거네. 30% 규칙이 뭐길래?”

솔라는 금세 흥미가 동한 얼굴로 물었다. 예상 밖의 실패는 언제나 호기심을 자극했다.

루나는 빈 공간에 손으로 사각형을 그리며 설명했다.

“간단한 규칙이야. CCTV 영상에서 시스템이 사람을 인식하면 그 주위에 네모난 상자, 즉 ‘바운딩 박스(bbox)’를 그리잖아. 그리고 우리는 미리 ‘이 구역은 직원만 있는 곳’이라고 지정해 둬. 이걸 ‘관심 영역(ROI)’이라고 부르지. ‘공통 bbox 30% 규칙’은, 어떤 사람의 바운딩 박스가 직원 ROI와 30% 이상 겹치면 그 사람을 직원으로 판단하는 거야.”

“어, 그건 합리적인데?”

솔라는 고개를 갸웃했다. 30%면 몸의 일부가 확실히 구역 안으로 들어왔다는 뜻이니, 규칙 자체에는 문제가 없어 보였다.

“그럼, 가상의 매장을 한번 상상해 보자.”

루나는 손짓으로 솔라의 상상을 이끌었다.

“매장 안쪽에 카운터가 있고, 그 카운터 뒤 공간이 직원 ROI로 설정되어 있어. 그리고 카메라는 매장 전체를 넓게 비추는 각도로 천장에 달려 있다고 해보자. 이제 고객 한 명이 카운터 앞 통로를 지나가. 직원이 아니지.”

“응, 그냥 지나가는 고객이지.”

“그런데 그 고객이 잠시 멈춰서서 카운터 위에 놓인 상품을 보려고 허리를 살짝 숙였어. 또는, 카메라 각도 때문에 카운터 앞에 서 있는 고객의 모습이 카운터 뒤 직원 구역과 겹쳐 보일 수도 있겠지. 자, 이때 시스템의 눈에는 이 장면이 어떻게 보일까?”

솔라는 눈을 감고 그 장면을 머릿속에 그렸다. 고객의 모습, 그를 둘러싼 사각형 바운딩 박스. 그리고 저 멀리 배경처럼 존재하는 직원 구역. 고객의 상체가 카운터 위로 기울어지자, 고객의 바운딩 박스 윗부분이 직원 ROI 영역을 침범하기 시작했다. 카메라의 원근감이 없는 평면적인 시야에서는 고객이 단순히 구역 ‘앞’에 서 있기만 해도, 그를 감싼 박스가 배경의 ROI와 겹쳐 보일 수 있었다.

“아…”

솔라의 입에서 나지막한 탄성이 터져 나왔다.

“고객은 구역에 들어가지 않았지만, 그 사람의 바운딩 박스는 30%는커녕, 어쩌면 그 이상도 직원 ROI와 겹칠 수 있겠구나. 그럼 시스템은 이 고객을 ‘직원’으로 판정하겠네.”

“맞아. 그런 고객이 한두 명이 아니라면?”

“계속해서 잘못된 판정이 쌓이겠지. 이게 ‘심한 과대 판정’이구나.”

이제야 솔라는 모든 조각이 맞춰지는 것을 느꼈다. 문제는 ‘직원’이라는 개념 정의에 있었던 게 아니다. 하나의 보편적인 규칙이 각기 다른 카메라가 설치된 ‘물리적 환경’의 특수성을 전혀 감당하지 못했던 것이다. 같은 30%라도 어떤 카메라에서는 합리적인 기준이었을지 모르지만, 고객 동선과 직원 구역이 자주 겹쳐 보이는 다른 카메라에서는 재앙이었을 터였다.

보편적 규칙은 예측 가능하고 안정적일 거라는 솔라의 초기 믿음이 깨지는 순간이었다. 오히려 그것은 특정 환경과 만났을 때 어디로 튈지 모르는 예측 불가능한 변수였다.

“그럼… 카메라마다 규칙을 다르게 만들 수밖에 없었겠네.”

솔라는 태블릿 화면의 제목을 새로운 눈으로 다시 읽었다. 이제 ‘카메라별 임계값’이라는 단어가 더 이상 불필요한 복잡함이 아니라, 피할 수 없는 해결책처럼 보였다.

“하나의 규칙이 실패했다는 건 알겠어. 그럼 그들은 이 문제를 어떻게 해결한 거야? 예를 들어, 카운터가 직원의 발을 가리는 카메라랑, 고객과 직원이 자꾸 겹쳐 보이는 카메라는 완전히 다른 문제일 텐데. 각각의 환경에 맞는 규칙은 어떻게 찾아낸 거지?”

2장: 카메라 5: 가림과 ROI 중첩률의 재조정

솔라의 질문에 루나는 바로 대답하는 대신, 손에 든 태블릿을 조작했다. 화면에 떠 있던 보고서 제목이 옆으로 밀려나고, 단순한 도면 하나가 나타났다. 매장의 평면도 위에 CCTV 아이콘과 부채꼴 모양의 시야각이 그려져 있었고, ‘카메라 5’라는 라벨이 붙어 있었다. 시야각 안에는 기다란 직사각형의 ‘카운터’와 그 바로 뒤에 음영 처리된 ‘직원 ROI’ 영역이 표시되어 있었다.

루나는 말없이 손가락으로 카운터 바로 뒤, 직원 ROI 안쪽 깊숙한 곳에 작은 사람 모양 아이콘을 하나 그려 넣었다. 아이콘은 카운터에 하반신이 가려져 상체만 보이는 형태였다. 이전 장에서 나눴던 대화의 막연한 상상이 구체적인 시각 정보로 눈앞에 펼쳐지자, 솔라의 질문도 더 날카로워졌다. 모든 카메라의 문제를 한 번에 해결할 방법을 찾는 대신, 눈앞의 이 ‘카메라 5’라는 하나의 과제에 집중하게 된 것이다.

“이게 바로 그 카운터가 있다는 카메라구나. 직원이 저 위치에 서 있으면, 시스템이 사람으로 인식하고 바운딩 박스를 그릴 거 아냐. 그리고 그 박스는 당연히 직원 ROI 안에 있을 테고. 그럼 직원으로 판정하면 끝나는 거 아닌가? 30% 규칙이 고객을 직원으로 잘못 보는 과대 판정이 문제였지, 진짜 직원을 놓치는 문제는 아니었잖아.”

솔라는 자신이 이미 문제를 이해했다고 생각했다. 가려진 부분이 있더라도, 시스템은 어쨌든 보이는 부분을 기반으로 사람의 존재를 인식할 테니 말이다.

“그럴까?”

루나가 짧게 반문하며, 솔라가 그린 사람 아이콘 위로 반투명한 사각형, 즉 바운딩 박스를 겹쳐 그렸다. 그런데 그 박스는 사람의 키 전체를 감싸는 모양이 아니었다. 카운터 위로 드러난 상반신만 딱 맞게 감싸는, 위아래로 짧은 형태였다.

“시스템은 눈에 보이는 것만으로 판단해. 카메라 5의 시야에서 직원은 항상 허리 위쪽만 보여. 발이 카운터에 가려져 있으니까. 그럼 시스템이 그리는 바운딩 박스는 어떻게 될까?”

“아…”

솔라는 루나가 그린 짧은 바운딩 박스와 그 아래 넓게 펼쳐진 직원 ROI 영역을 번갈아 보았다. 머릿속에서 빠르게 계산이 이루어졌다. 직원은 분명히 ROI 안에 100% 존재한다. 하지만 그를 둘러싼 ‘바운딩 박스’의 면적은 실제보다 훨씬 작아졌다. 그리고 그 작은 박스가 ROI 영역과 겹치는 면적의 비율을 계산하면…

“상황에 따라서는… 30%가 안 될 수도 있겠구나.”

솔라는 허를 찔린 듯한 표정을 지었다. 이전 장에서는 고객의 바운딩 박스가 ROI를 ‘침범’해서 문제였다면, 이번에는 진짜 직원의 바운딩 박스가 ROI를 ‘충분히 채우지 못해서’ 문제였다. 같은 30% 규칙이 어떤 환경에서는 과대 판정(False Positive)을, 다른 환경에서는 미판정(False Negative)을 일으키는 원인이 될 수 있다는 사실을 깨달았다. 보편적 규칙의 예측 불가능성이 다시 한번 드러나는 순간이었다.

“맞아. 그래서 카메라 5만을 위한 새로운 규칙이 필요했어. 단순히 30%라는 임계값을 올리거나 내리는 것만으로는 해결할 수 없는 문제였지.”

루나는 보고서의 한 구절을 화면에 띄웠다. 「카메라 5는 카운터가 직원 발을 가려 bbox 하단의 직원 ROI 중첩률 80% 이상을 보완 근거로 사용했다.」

“80%? 엄청나게 기준을 높였네. 그런데 ‘bbox 하단’의 중첩률은 또 뭐야?”

“단순히 전체 박스 면적 대비 겹치는 비율을 보는 게 아니야.”

루나는 태블릿 화면의 짧은 바운딩 박스 하단 테두리를 굵게 강조했다.

“이 박스의 바닥 부분이 직원 ROI에 얼마나 깊숙이 들어와 있는지를 보는 거지. 이 규칙은 이렇게 말하는 것과 같아. ‘이 카메라에서는 사람의 하반신이 보이지 않는다는 걸 알고 있다. 하지만 보이는 신체의 가장 아랫부분, 즉 바운딩 박스의 밑변이 직원 구역에 80% 이상 걸쳐 있다면, 보이지 않는 발도 그 구역 안에 있을 것이라고 강하게 확신하겠다.’고 말이야.”

이제야 솔라는 복잡해 보이는 규칙 뒤에 숨은 명쾌한 논리를 이해했다. 그것은 물리적 환경의 제약을 데이터로 번역한 결과물이었다. ‘카운터에 가려져 발이 보이지 않는다’는 현실 세계의 관찰이 ‘bbox 하단의 중첩률 80%’라는 시스템의 언어로 치환된 것이다. 이는 단순히 숫자를 조정한 것이 아니라, 판정의 근거가 되는 ‘시점’을 바꾼 것이나 다름없었다.

“특정 환경의 가림 문제를 해결하기 위한 맞춤형 ROI 규칙이구나. 단순히 숫자를 바꾸는 게 아니라, 어디를 기준으로 삼을지 자체를 바꾸는 거네.”

솔라는 고개를 끄덕였다. 하나의 퍼즐 조각이 제자리를 찾은 기분이었다. 하지만 그녀의 머릿속에는 여전히 풀리지 않은 다른 퍼즐 조각이 남아 있었다.

“좋아, 카운터처럼 고정된 장애물 문제는 이렇게 해결했다고 쳐. 그런데 그때 말했던 다른 문제는? 고객이랑 직원이 마구 겹쳐서 누가 누군지 헷갈리는 카메라도 있다고 했잖아. 거기서는 이렇게 엄격한 규칙을 적용하면 오히려 필요한 직원까지 놓치게 되는 거 아닐까?”

3장: 카메라 21: 고객 혼동과 ID 제한

솔라의 마지막 질문이 남긴 여운 위로, 루나는 태블릿 화면을 옆으로 쓸어 넘겼다. 카메라 5의 정적이고 명확한 구조도—카운터와 그 뒤의 직원 구역—가 사라지고, 새로운 도면 ‘카메라 21’이 나타났다. 이전과는 사뭇 다른 풍경이었다.

카메라 21이 비추는 곳은 훨씬 더 복잡하고 동적인 공간이었다. 넓게 트인 계산대 주변이었는데, 직원 구역(ROI)이 카운터 안쪽뿐만 아니라 고객이 카드나 현금을 건네기 위해 손을 뻗거나, 잠시 기댈 수 있는 공간의 일부까지 포함하고 있었다. 고정된 장애물로 공간이 나뉜 것이 아니라, 사람들의 동선이 자연스럽게 겹치는 구역이었다. 이전 장에서 다룬 카메라 5의 문제가 단단한 벽을 통과하려는 것과 같았다면, 카메라 21의 문제는 쉴 새 없이 섞이는 물줄기 속에서 특정 물 한 방울을 가려내는 일처럼 보였다.

“좋아, 카운터처럼 고정된 장애물 문제는 그렇게 해결했다고 쳐. 그런데 그때 말했던 다른 문제는? 고객이랑 직원이 마구 겹쳐서 누가 누군지 헷갈리는 카메라도 있다고 했잖아. 거기서는 이렇게 엄격한 규칙을 적용하면 오히려 필요한 직원까지 놓치게 되는 거 아닐까?”

솔라는 눈앞의 새로운 도면을 보며 정확히 자신의 질문에 해당하는 상황임을 직감했다. 그녀는 방금 배운 ‘가림 대응 ROI’라는 도구를 새로운 문제에 바로 적용해 보고 싶었다.

“이 카메라는 문제가 다르네. 여긴 고객이랑 직원이 물리적으로 겹칠 수밖에 없는 구조야. 그럼 아까처럼 80% 같은 높은 중첩률 규칙을 쓰면 안 되겠네. 고객 때문에 직원을 놓칠 수도 있으니까. 반대로 너무 낮추면, 1장에서처럼 지나가는 고객을 전부 직원으로 볼 거고… 결국 적절한 중간 값을 잘 찾는 게 관건이겠네. 50%라든가?”

솔라의 추론은 합리적이었다. 하나의 변수를 조정하여 최적의 지점을 찾는 것. 그것은 대부분의 문제 해결에서 통용되는 방식이었다.

루나는 대답 대신, 솔라의 상상이 더 구체적인 장벽에 부딪히도록 만들었다.

“그럼 이 장면을 생각해 봐. 직원이 계산대 안쪽에 서 있고, 고객이 계산을 하려고 카운터에 바짝 다가섰어. 고객이 지갑을 꺼내려고 몸을 숙이자, 고객의 바운딩 박스 일부가 직원 ROI와 겹쳤어. 약 25% 정도. 동시에 직원은 몸을 움직여서 고객의 물건을 받아들었어. 직원의 바운딩 박스는 ROI와 95% 겹쳐 있지.”

“그렇다면 중첩률을 40% 정도로 설정하면 되겠네! 그럼 고객은 걸러지고 직원은 정확히 판정되잖아.”

솔라는 자신 있게 말했다. 숫자로 명확히 구분되는 깔끔한 해결책이었다.

“바로 다음 순간은 어떨까? 이번엔 고객이 카드를 건네주려고 팔을 깊숙이 뻗었어. 이제 고객의 바운딩 박스가 45%나 겹쳐. 그리고 직원은 잠시 뒤로 물러나 다른 물건을 집었어. 직원의 바운딩 박스는 70%만 겹치게 됐지. 네가 정한 40% 규칙이라면, 이제 시스템은 고객을 직원으로, 직원은 여전히 직원으로 판정할 거야. 순식간에 직원이 두 명이 됐네.”

“어… 그건…”

솔라의 말문이 막혔다. 문제는 중첩률이라는 하나의 잣대로는 풀 수 없었다. 고객과 직원의 움직임은 너무나 유동적이어서, 어떤 고정된 ‘선’을 긋더라도 그 선을 넘나드는 예외는 항상 발생했다. 문턱 값을 높이면 진짜 직원을 놓치고(미판정), 낮추면 가짜 직원(고객)을 포함시키는(과대 판정) 시소게임에 갇힐 뿐이었다. 공간적 중첩만으로는 이들의 ‘역할’을 구분할 수 없었다.

그때 루나가 보고서의 다른 구절을 태블릿 화면에 띄웠다. 「카메라 21은 고객 bbox도 직원 ROI와 겹치므로 20% 후보를 사용하되 직원 ID를 한 명으로 제한했다.」

“20%? 이렇게 낮게? 이건 거의 모든 경우를 다 잡겠다는 거잖아. 그럼 과대 판정이 훨씬 심해지는 거 아니야?”

솔라는 의아해하며 문장을 다시 읽었다. 그러다 마지막 구절에 시선이 꽂혔다.

“…아. ‘직원 ID를 한 명으로 제한했다’.”

짧은 침묵 끝에 솔라의 얼굴에 깨달음이 번졌다.

“이건 완전히 다른 방식이잖아! 완벽한 중첩률을 찾는 걸 포기한 거구나. 대신, 중첩률 기준을 20%로 아주 낮춰서 ‘일단 후보가 될 만한 사람은 전부 다 목록에 올려!’라고 명령한 거야. 진짜 직원을 놓치는 일은 없도록. 그런 다음에….”

솔라는 자신의 발견에 흥분하며 말을 이었다.

“그런 다음에 완전히 다른 차원의 규칙을 적용한 거야. 공간(ROI) 규칙이 아니라, 논리(ID) 규칙을. ‘이 구역의 직원은 원래 한 명뿐이다. 그러니 후보가 몇 명이든, 가장 확실한 한 명만 남기고 나머지는 모두 버려라.’ 이렇게. 아마 가장 중첩률이 높은 사람을 진짜 직원으로 선택했겠지.”

정답이었다. 카메라 21의 해결책은 기하학의 문제를 논리학의 문제로 전환한 것이었다. 완벽한 ‘경계선’을 찾는 대신, ‘개수’라는 명확한 제약 조건을 활용했다. 공간적으로 모호하다면, 그 공간의 운영 규칙이라는 더 높은 수준의 정보를 가져와 판단의 근거로 삼은 것이다. 카메라 5가 물리적 환경의 특수성을 ‘보는 방식’을 바꿔 해결했다면, 카메라 21은 동선의 혼잡함을 ‘세는 방식’을 바꿔 해결한 셈이었다.

“단순히 ROI 값을 조정하는 게 아니었어. 아예 다른 종류의 규칙을 하나 더한 거구나. 문제가 복잡해지니까, 해결책의 차원도 달라져야 했던 거네.”

솔라는 고개를 끄덕였다. 카메라마다 다른 규칙이 필요하다는 사실을 이제는 몸으로 이해할 수 있었다. 하지만 문득 또 다른 질문이 떠올랐다.

“알겠어. 공간적인 문제는 이렇게 해결했어. 그런데, 아까 언니가 예시로 든 것처럼 상황은 계속 바뀌잖아. 직원이 잠깐 고개를 숙이거나 기둥 뒤로 1초 정도 사라지면 어떻게 되지? 시스템은 그 직원을 ‘놓쳤다’고 판단했다가, 다시 나타나면 ‘새로운 직원’으로 인식하려나? 이런 순간적인 깜빡임은 어떻게 처리하지?”

4장: 10초 보정: 일시적 가림과 판단 유예

이전 대화가 남긴 질문의 무게가 거실 공기 중에 남아 있었다. 공간의 문제를 해결하는 기하학적, 논리적 규칙들은 이제 솔라의 머릿속에 제 자리를 잡았다. 하지만 솔라의 마지막 질문, 즉 ‘시간’의 축 위에서 벌어지는 순간적인 깜빡임의 문제는 아직 해결되지 않은 채였다.

루나는 태블릿 화면에 떠 있던 복잡한 매장 도면을 모두 지웠다. 이전 장들에서 논의의 중심이었던 ‘공간’의 지도가 사라진 자리에, 루나는 검은 선 하나를 길게 그었다. 그리고 선 위에 일정한 간격으로 점을 찍어 나갔다. 마치 영상 편집 프로그램의 타임라인 같았다. 루나는 타임라인의 시작점에 ‘직원 등장’이라고 적고, 그 위로 작은 사람 아이콘을 그렸다.

솔라가 던졌던 질문—직원이 기둥 뒤로 1초간 사라졌다 나타나는—을 재현하려는 듯, 루나는 타임라인 중간에 짧은 구간을 비워두고 다시 사람 아이콘을 그렸다. ‘가시(Visible)’ 상태의 구간 사이에 명확한 ‘비가시(Invisible)’의 공백이 생겼다. 이전의 논의가 지도 위에서의 움직임이었다면, 이제 문제는 시간의 흐름 위에서 점멸하는 신호로 바뀌었다.

솔라는 그 단순한 그림이 자신의 질문을 얼마나 정확하게 요약하고 있는지 즉시 알아차렸다.

“바로 저거야. 시스템의 눈은 정직하잖아. 저 빈 공간, 그러니까 직원이 기둥 뒤에 숨은 1초 동안은 직원을 보지 못했으니 ‘직원 아님’이라고 판단해야 하는 거 아냐? 그게 맞는 거지. 매 프레임마다 본 것을 그대로 보고하는 게 정확한 시스템이니까. 잠깐이라도 보이지 않았으면, 그건 오류가 아니라 그냥 사실인 거지.”

솔라의 말에는 기계의 정직함에 대한 믿음이 담겨 있었다. 시스템은 본 것을 본다고, 보지 못한 것을 보지 못했다고 즉각적으로 판단해야 한다는 것. 그것이 그녀가 생각하는 ‘정확도’의 정의였다. 순간적인 판단의 오류는 어쩔 수 없는 한계로 받아들여야 한다고 생각했다.

루나는 솔라의 말을 가만히 듣고는, 타임라인 아래에 새로운 줄을 하나 더 그었다. 그리고 첫 번째 줄에는 ‘시스템의 원시 시각(Raw Vision)’, 두 번째 줄에는 ‘최종 판정(Final Judgment)’이라고 이름 붙였다.

루나는 첫 번째 줄, ‘원시 시각’ 타임라인을 채워나갔다. 직원이 보이는 구간은 초록색으로, 보이지 않는 1초의 공백은 빨간색으로 칠했다. [초록]—[빨강]—[초록]. 솔라가 말한 시스템의 ‘정직한’ 눈이 보는 세상이었다.

“네 말이 맞아, 솔라. 시스템이 매 순간 받아들이는 원시 데이터는 바로 이래. ‘직원 있음’, ‘직원 없음’, ‘직원 있음’. 이 깜빡이는 신호가 시스템이 보는 사실 그 자체지.”

루나는 펜 끝으로 빨갛게 칠해진 짧은 공백을 가리켰다.

“그런데 우리가 정말 원하는 정보가 ‘매 순간 직원이 카메라에 보이는가?’일까, 아니면 ‘이 구역에 직원이 근무 중인가?’일까?”

질문의 방향이 미묘하게 바뀌자, 솔라의 표정에도 변화가 생겼다. 매 순간의 시각적 사실을 기록하는 것과, 그 사실들을 종합하여 안정적인 상태를 판단하는 것은 다른 문제였다.

“만약 시스템이 이 빨간 공백을 마주할 때마다 ‘직원이 사라졌다!’고 경보를 울리고, 다시 초록색 구간이 시작될 때마다 ‘새로운 직원이 나타났다!’고 보고한다면 어떨까? 운영하는 사람 입장에서는 혼란스럽기만 할 거야.”

바로 그때, 루나가 보고서의 새로운 한 구절을 화면 한쪽에 띄웠다. 「같은 장면에서 잠깐 가려지는 경우에는 10초 보정을 적용했다.」

솔라는 짧은 문장을 몇 번이고 곱씹었다. ‘10초 보정’. 이 단어가 루나가 그린 타임라인과 겹쳐지면서, 새로운 그림이 머릿속에 그려지기 시작했다.

“잠깐만… 그럼 이건…”

솔라는 마치 수수께끼를 풀듯 천천히 입을 열었다.

“시스템의 원시 시각이 빨간색, 즉 ‘직원 없음’ 상태로 바뀌는 순간, 시스템은 즉시 결론을 내리지 않는 거야. 대신 속으로 타이머를 시작하는 거지. 하나, 둘, 셋… 그렇게 10초를 세는 동안, 만약 직원이 다시 나타나서 원시 시각이 초록색으로 돌아오면, 시스템은 ‘아, 잠시 가려졌던 거구나. 아까 그 직원이 맞네’라고 판단하고 아무 일도 없었다는 듯이 상태를 유지하는 거야.”

솔라는 루나가 비워둔 두 번째 타임라인, ‘최종 판정’ 줄을 손가락으로 쭉 그었다. 깜빡임 없이, 처음부터 끝까지 이어진 하나의 긴 초록색 선이었다.

[원시 시각]: [초록] — [빨강] — [초록] [최종 판정]: [초록 ————–—]

“10초라는 유예 기간을 둬서, 짧은 시각적 단절을 무시하고 상태의 연속성을 지켜주는 거구나. 공간 규칙(ROI)이나 논리 규칙(ID 제한)과는 전혀 다른, 시간의 차원에서 작동하는 규칙이네.”

솔라는 깨달았다. 이것은 정확도를 포기하는 것이 아니라, 오히려 더 높은 차원의 정확도를 추구하는 방법이었다. 매 순간의 픽셀 값에 대한 기계적 정확도가 아닌, ‘직원이 근무 중’이라는 실제 상황에 대한 운영적 정확도. 시스템은 ‘판단 유예’라는 도구를 통해 더 참을성 있고, 더 안정적인 관찰자가 되었다.

“카메라 5는 공간의 제약(가림)을 ‘어디를 볼 것인가’로 해결했고, 카메라 21은 관계의 복잡함(혼동)을 ‘몇 명을 셀 것인가’로 해결했어. 그리고 이 10초 보정은 시간의 단절을 ‘얼마나 기다릴 것인가’로 해결한 거구나.”

이제 솔라의 머릿속에는 각기 다른 문제 상황과 그에 맞는 다차원적인 해결책들이 하나의 정교한 시스템처럼 맞물려 돌아가고 있었다.

“좋아. 이제 정말 빈틈없는 규칙이 만들어진 것 같아. 각 카메라의 물리적 환경, 동선, 그리고 시간적 변수까지 모두 고려했으니까. 그런데… 이 모든 복잡한 규칙들이 정말로 효과가 있다는 건 어떻게 알지? 우리가 지금 책상 앞에서 상상한 것처럼 완벽하게 작동할 거라고 어떻게 장담해? 규칙을 만드는 것과, 그 규칙이 잘 돌아간다고 증명하는 건 다른 문제잖아.”

5장: 독립 검증: 맞춤 규칙의 최종 입증

솔라의 마지막 질문은 이전과는 조금 다른 무게를 지니고 있었다. 그것은 무언가를 몰라서 묻는 질문이라기보다, 정교하게 조립된 기계의 마지막 나사를 조이며 모든 것이 완벽한지 확인하는 엔지니어의 점검에 가까웠다. 공간의 가림 문제, 동선의 혼잡 문제, 시간의 단절 문제까지. 각각의 난관을 돌파하는 맞춤형 규칙들이 솔라의 머릿속에서 하나의 거대한 흐름도로 완성되고 있었다. 이제 남은 것은 이 설계도가 현실에서도 도면처럼 작동할 것이라는 확신뿐이었다.

루나는 말없이 태블릿 화면을 쓸어 넘겼다. 복잡한 타임라인과 도면들이 사라진 자리에, 두 개의 영상 파일 썸네일이 나란히 나타났다. cam_data_01.mp4cam_data_02.mp4. 루나는 첫 번째 영상을 손가락으로 가리켰다.

“우리가 지금까지 이야기한 카메라 5의 가림 문제, 카메라 21의 혼동 문제를 분석하고, ROI 중첩률 80% 규칙, ID 1명 제한 규칙, 10초 보정 규칙을 만든 사람들이 사용한 영상이 바로 이거야. cam_data_01.”

그리고 루나의 손가락이 두 번째 영상으로 옮겨갔다.

“이건 cam_data_02. 같은 카메라들로, 다른 날 다른 시간대에 촬영된 5분짜리 영상이지. 우리가 만든 그 정교한 규칙들은 이 영상을 한 번도 본 적이 없어. 자, 솔라. 이 새로운 영상에 우리의 규칙들을 적용하면, 결과는 어떨까?”

“당연히 잘 되겠지!”

솔라는 조금의 망설임도 없이 대답했다. 그녀의 목소리에는 자신이 쌓아 올린 논리에 대한 강한 자신감이 묻어났다.

“우리가 그냥 감으로 규칙을 만든 게 아니잖아. 카운터에 발이 가려지는 물리적 현실, 고객과 직원의 동선이 겹치는 공간의 특수성, 잠깐 사라졌다 나타나는 시간의 문제까지 다 고려해서 만든 빈틈없는 규칙인데. 어떤 영상이든 상관없이 잘 작동해야 정상 아니야? 그게 바로 좋은 규칙의 증거지.”

솔라의 대답은 명쾌했다. 잘 만들어진 이론은 어떤 시험 문제에도 통용되어야 한다는 믿음. 그녀는 검증 과정을 복잡한 규칙들의 성능을 당연하게 확인하는, 일종의 축하 행사처럼 여기고 있었다.

루나는 솔라의 자신감 넘치는 얼굴을 잠시 바라보다가, 나지막이 물었다.

“혹시… 규칙들이 cam_data_01에 너무 ‘최적화’되었을 가능성은 없을까? 마치 시험에 나올 문제의 정답만 달달 외운 학생처럼 말이야.”

“정답을 외웠다고?”

“우리는 cam_data_01 영상에서 나타난 문제들을 해결하기 위해 규칙들을 만들고 다듬었어. 카메라 5의 직원이 하필이면 ROI와 75% 겹치는 순간이 많아서, 기준을 80%로 올렸을 수도 있고, 카메라 21의 고객이 유독 15% 정도만 ROI를 침범해서, 기준을 20%로 낮췄을 수도 있지. 우리의 규칙은 어쩌면 그 영상 속의 특정한 패턴에만 과하게 맞춰진 ‘맞춤 정장’일지도 몰라. 다른 체형의 사람, 즉 cam_data_02 영상에게는 맞지 않을 수도 있다는 뜻이야.”

루나의 비유에 솔라의 표정이 미세하게 굳었다. ‘최적화’라는 단어가 긍정적인 의미가 아니라, ‘편향’이나 ‘과적합’이라는 부정적인 뉘앙스로 다가왔다. 완벽하다고 믿었던 규칙들이, 실은 특정 데이터에만 들어맞는 ‘족집게 과외’의 결과물일 수 있다는 생각은 한 번도 해보지 못했다.

바로 그때, 루나가 보고서의 마지막 결과 부분을 화면에 띄웠다. 솔라가 보았던 것과는 다른, 숫자들로 가득한 표였다.

규칙 검증 결과 (Held-out Test Set: cam_data_02)

  • 검증 대상: 규칙 설정에 사용하지 않은 두 번째 5분 영상
  • 카메라 5: 96.667% (60개 표본 중 58개 성공)
  • 카메라 21: 98.333% (60개 표본 중 59개 성공)
  • 합계 (120개 표본): 97.500% exact accuracy

“아…”

솔라의 입에서 짧은 탄식이 흘러나왔다. 그녀는 ‘규칙을 만들고 적용했다’는 과정이 아니라, ‘설정에 사용하지 않은’이라는 전제 조건의 진짜 의미를 이제야 깨달았다. 이것은 축하 행사가 아니라, 혹독한 실전 시험이었다. 개발자들이 한 일은 솔라가 상상했던 것과 정반대였다. 그들은 규칙을 만든 데이터(cam_data_01)로는 성능을 자랑하지 않았다. 대신, 규칙이 전혀 본 적 없는 미지의 데이터(cam_data_02)를 가져와 칼같이 평가했다.

“규칙을 만드는 것과, 그 규칙을 검증하는 것을 철저하게 분리했구나. 일부러, 규칙이 모르는 문제로만 시험을 본 거야.”

솔라는 숫자를 다시 한번 찬찬히 뜯어보았다. 97.5%. 100%는 아니었지만, 이 숫자는 솔라가 상상했던 막연한 ‘완벽함’보다 훨씬 더 단단하고 신뢰할 수 있는 무게를 지니고 있었다. 이것은 특정 문제의 정답을 맞힌 점수가 아니라, 어떤 문제가 나와도 높은 점수를 받을 수 있다는 ‘실력’을 증명하는 숫자였기 때문이다. 정답을 외운 게 아니라는 가장 확실한 증거. 이것이 바로 ‘미학습 데이터 검증’의 힘이었다.

이제 솔라는 처음 태블릿을 보았을 때의 자신과는 완전히 다른 사람이 되어 있었다. 보편적 규칙에 대한 막연한 믿음은 깨졌고, 그 자리는 각기 다른 환경의 특수성을 존중하는 맞춤형 규칙들로 채워졌다. 그리고 그 규칙들을 맹신하는 대신, 독립적인 검증을 통해 그 유효성을 냉정하게 입증해야 한다는 마지막 조각이 맞춰졌다.

루나가 미소 지으며 솔라에게 새로운 노트를 한 장 건넸다. 노트 상단에는 ‘새 매장 CCTV 규칙 설계안’이라고 적혀 있었다.

“자, 솔라. 새로운 매장을 연다고 상상해 봐. 이번엔 창고 문을 비추는 ‘카메라 33번’이야. 문제는, 직원들뿐만 아니라 택배 기사님들도 물건을 놓으러 자주 드나든다는 거야. 어떻게 ‘직원’만 정확하게 판정할 규칙을 만들고, 그게 잘 작동한다고 증명할래?”

솔라는 잠시 생각에 잠겼다. 그리고는 망설임 없이 펜을 들어 노트에 적기 시작했다. 그녀는 특정 ROI 값이나 임계값을 먼저 적지 않았다. 대신, 계획의 단계를 써 내려갔다.

  1. 오전 영상(설정용)오후 영상(검증용)을 따로 확보한다.
  2. 오전 영상을 분석해, 택배 기사와 직원의 동선 차이를 관찰하고, 이를 바탕으로 ROI 규칙과 ID 제한 같은 후보 규칙들을 만든다.
  3. 만들어진 규칙을 오후 영상에만 적용하여 정확도를 측정한다.
  4. 이 검증 정확도가 목표치(예: 95%)를 넘었을 때, 비로소 이 규칙을 실제 운영에 적용한다.

솔라는 자신이 쓴 계획안을 조용히 내려다보았다. 더 이상 하나의 완벽한 답을 찾으려 하지 않았다. 대신, 신뢰할 수 있는 답을 찾아 나가는 ‘과정’을 설계하고 있었다. 그것이 이 길고 복잡한 여정의 끝에서 그녀가 얻은 가장 중요한 도구였다.