Big Project · AI's EYE 11
YOLO 인원 계수를 카메라별 Precision·Recall·MAE로 다시 읽은 평가
같은 YOLO 모델을 사용하면 CCTV 위치가 달라도 비슷한 정확도를 낼 것처럼 보인다. Precision이 높은 카메라가 왜 실사용에 부적합할 수 있는지도 혼란스럽다.
근거 · 프로젝트 문서 · 코드 · 테스트
1장: Precision이 높은데 왜 쓸 수 없다는 거야?
솔라는 모니터 옆에 붙여둔 인원 계수 모델 성능 평가표를 보며 들뜬 목소리로 말했다. 카페 여러 지점에 설치된 카메라에서 데이터를 받아 YOLO 모델의 성능을 테스트한 결과였다.
“언니, 이거 봐. ‘068번 카메라’ 성능. Precision이 95.9%야! 모델이 사람이라고 예측한 건 거의 다 진짜 사람이었다는 거잖아. 이 정도면 거의 완벽한 거 아니야?”
솔라의 손가락이 가리킨 곳은 표의 한 칸이었다. 068_2층_2라는 이름의 카메라 옆에 적힌 ‘Precision: 95.9%’라는 숫자는 단연 눈에 띄었다. 다른 카메라들의 지표와 비교해도 월등히 높은 수치였다. 이 정도면 당장 서비스에 적용해도 문제없을 것 같았다.
루나는 솔라가 가리키는 숫자를 잠시 바라보더니, 시선을 그 옆 칸으로 옮겼다. 그리고는 말없이 마우스 휠을 움직여 해당 카메라의 상세 분석 폴더를 열었다.
“그 옆에 있는 숫자도 같이 볼까?”
루나의 말에 솔라는 고개를 갸웃하며 시선을 옮겼다. Precision 숫자 바로 옆, ‘Recall’이라고 적힌 열에는 ‘58.1%’라고 쓰여 있었다. 방금 본 95.9%와는 너무나 대조적인 숫자였다.
“Recall… 58.1%? 이건 무슨 뜻이지? 일단 숫자가 너무 낮은데.”
“이 카메라가 실제로 촬영한 영상 한번 보자.”
루나는 길게 설명하는 대신, 평가에 사용된 영상 파일을 화면에 띄웠다. 화면에는 2층 창가 자리에 앉아있는 사람들과 창밖 풍경이 함께 보였다. 유리창에는 실내조명과 바깥 풍경이 미세하게 겹쳐 보였다. 루나는 모델이 사람을 탐지한 결과가 네모 상자로 표시된 영상을 재생했다.
솔라는 눈을 가늘게 뜨고 화면을 지켜봤다. 모델이 예측한 초록색 상자들은 틀림없이 사람들의 머리 위를 정확하게 감싸고 있었다. 상자 안에 사람이 아닌 다른 것이 들어간 경우는 거의 보이지 않았다.
“봐봐. 모델이 ‘이건 사람이야’라고 한 건 정말 다 사람이잖아. Precision 95.9%라는 게 이런 의미구나.”
솔라는 자신의 처음 판단이 맞았다고 생각하며 자신 있게 말했다. 하지만 루나는 영상을 잠시 멈추고 솔라에게 물었다.
“좋아. 그럼 이제 솔라 네가 직접 사람을 세어볼래? 저기 저 창가에 앉은 사람들 말이야. 모델이 놓친 사람이 몇 명이나 있는지.”
그 말에 솔라는 화면 구석부터 꼼꼼히 사람을 세기 시작했다. 한 명, 두 명, 세 명… 어? 화면 속에는 분명 사람이 있는데, 모델이 표시한 상자가 없는 곳들이 눈에 들어오기 시작했다. 특히 유리창 빛 반사가 심한 곳이나 다른 사람의 어깨에 살짝 가려진 사람들은 거의 탐지되지 않았다.
“잠깐만… 하나, 둘, 셋… 넷. 여기 네 명이나 있는데 모델은 아무 표시도 안 했어. 저쪽에도 두 명 더 있고. 화면 전체를 보면… 실제로는 열 명이 있는데, 모델은 여섯 명만 찾아냈네.”
솔라는 자신이 직접 세어본 결과에 놀랐다. 모델이 ‘사람’이라고 예측한 여섯 번은 모두 정답이었지만, 찾아내야 할 사람 열 명 중 네 명은 아예 존재조차 인식하지 못했던 것이다.
그제야 솔라는 ‘Recall 58.1%’라는 숫자가 무엇을 의미하는지 몸으로 깨달았다. 실제 존재하는 사람 열 명 중 약 여섯 명만 찾아냈다는 뜻이었다. 인원 계수를 위한 시스템이라고 생각하면, 100명이 있는 공간을 58명만 있다고 알려주는 셈이었다.
솔라는 다시 성능 평가표를 바라보았다. 아까는 자랑스럽게 빛나 보였던 ‘Precision 95.9%’라는 숫자가 이제는 다르게 보였다. 그 숫자만으로는 이 카메라가 쓸모 있는지 판단할 수 없다는 사실이 명확해졌다.
“아… 그러니까 모델이 사람이라고 예측한 건 거의 다 맞지만(Precision), 애초에 찾아내야 할 사람의 40% 이상을 그냥 놓쳐버린 거구나(Recall). 사람 수를 세는 게 목적인데, 이렇게 많이 놓치면… 정확한 계수는 불가능하겠네.”
고개를 끄덕인 솔라는 혼잣말처럼 중얼거렸다. 높은 숫자 하나에 흥분했던 자신이 조금 부끄러워졌다. 이제는 숫자 하나만 보고 섣불리 결론 내리지 않으리라 다짐했다. 중요한 건 전체적인 맥락이었다.
“그럼 언니, Precision이랑 Recall은 항상 같이 봐야 하는 거네. 둘의 관계가 정확히 뭐고, 이런 인원 계수 같은 문제에서는 왜 둘 다 중요한 거야?”
2장: Precision, Recall, MAE는 인원 계수에서 어떻게 다른가?
솔라의 질문이 끝나자, 루나는 대답 대신 옆에 있던 작은 메모 패드를 끌어당겼다. 익숙하게 펜을 들더니, 망설임 없이 간단한 그림 두 개를 그렸다. 첫 번째 그림은 과녁의 정중앙에 화살들이 촘촘히 박혀있는 모습이었다. 두 번째 그림은 과녁 전체에 화살들이 넓게, 그러나 꽤 많이 꽂혀있는 모습이었다.
루나는 첫 번째 그림 아래에는 ‘정밀하지만, 놓친 과녁이 많음’이라고 적었고, 두 번째 그림 아래에는 ‘과녁을 많이 맞혔지만, 빗나간 것도 많음’이라고 썼다. 솔라는 그 그림들을 말없이 들여다보았다. 어렴풋이 어제 보았던 카메라 영상과 숫자들의 관계가 떠올랐다.
“솔라 네가 던진 질문을 이 그림으로 다시 생각해 볼까? 우리가 맞혀야 할 목표는 ‘실제로 있는 모든 사람’이야.”
루나는 과녁 그림을 가리키며 말했다.
“Precision은 ‘내가 쏜 화살이 과녁에 꽂혔을 때, 얼마나 중앙에 가깝게 꽂혔는가’에 가까워. 즉, 모델이 ‘사람’이라고 예측한 것들이 얼마나 정확하게 실제 사람이었는지를 의미하지. 아까 본 068번 카메라처럼 예측 자체는 거의 다 맞았으니, 첫 번째 그림과 비슷해.”
솔라는 첫 번째 그림, 정중앙에 모인 화살들을 보았다. Precision 95.9%의 의미가 선명하게 다가왔다. 쏜 화살의 조준은 매우 정확했다.
“그럼 Recall은…?”
“Recall은 ‘과녁에 꽂혀야 할 화살 중, 실제로 몇 개나 꽂혔는가’를 따지는 거야. 아무리 정중앙을 맞혔어도, 쏴야 할 화살 10개 중 6개만 쐈다면, 나머지 4개는 아예 날아가지도 않은 거지. 두 번째 그림은 쏜 화살은 많아서 과녁에 많이 꽂혔지만, 빗나간 것도 꽤 있는 상황이고.”
루나의 설명에 솔라는 고개를 끄덕였다. 068번 카메라의 Recall 58.1%는, 찾아야 할 사람 100명 중 58명만 찾고 42명은 아예 ‘쏘지도’ 않았다는 뜻이었다.
“그렇구나. Precision은 ‘참이라고 한 것 중에 진짜 참의 비율’, Recall은 ‘실제 참인 것 중에 찾아낸 참의 비율’… 교과서에서 본 정의보다 훨씬 와닿는다. 그럼 인원 계수에서는 둘 중 뭐가 더 중요한 거야?”
“좋은 질문이야. 한번 시뮬레이션해볼까?”
루나는 메모 패드를 넘겨 새로운 페이지를 펼쳤다. 그리고 간단한 표를 그리기 시작했다.
“여기 100명의 사람이 있는 공간이 있다고 상상해 봐. 두 가지 다른 모델로 성능을 시험해 보는 거야.”
| 모델 예측 수 | 실제 사람 (TP) | 사람이 아닌 것 (FP) | 놓친 사람 (FN) | |
|---|---|---|---|---|
| 모델 A | 60개 | 59개 | 1개 | 41개 |
| 모델 B | 110개 | 95개 | 15개 | 5개 |
“모델 A는 Precision이 어떨까?”
솔라는 잠시 생각에 잠겼다. 모델 A는 총 60개를 ‘사람’이라고 예측했고, 그중 59개가 진짜 사람이었다.
“음… 60개 중에 59개가 맞았으니까, 59/60… 약 98.3%? Precision은 엄청 높네.”
“맞아. 그럼 Recall은?”
“실제 사람은 100명인데… 그중 59명을 찾았으니까. 59/100, 59%네. Recall은 낮구나. 딱 아까 그 카메라 상황이랑 비슷하네.”
“그럼 모델 B를 보자. Precision과 Recall은?”
“모델 B는 110개를 사람이라고 했는데, 그중 95개만 진짜 사람이었어. 그럼 Precision은 95/110이니까… 약 86.4%. A보다는 낮네. 대신 실제 사람 100명 중 95명을 찾았으니 Recall은 95%야. 훨씬 높아.”
솔라는 자신이 계산한 숫자를 보며 생각에 잠겼다. 모델 A는 예측의 ‘질’이 높았고, 모델 B는 예측의 ‘양’이 많았다. 인원수를 세는 목적이라면, 어느 쪽이 더 유용할까?
“모델 A는 실제 100명을 60명이라고 알려주고, 모델 B는 100명을 110명이라고 알려주는 셈이네. 둘 다 틀렸지만, 오차의 크기는 모델 B가 훨씬 작아.”
바로 그 순간, 솔라는 무언가 깨달은 듯 말했다.
“아! Precision이나 Recall만으로는 ‘그래서 총 몇 명인데?’라는 질문에 대한 오차를 직접 알 수가 없구나. 우리는 사람을 탐지하는 것뿐만 아니라, 그 ‘수’를 세는 게 중요하잖아. 그렇다면 이 ‘계수 오차’를 재는 별도의 지표가 필요하겠네!”
루나는 빙그레 웃으며 고개를 끄덕였다.
“정확해. 그래서 우리는 ‘인원 MAE(Mean Absolute Error)’라는 지표를 같이 보는 거야. 간단히 말해, ‘실제 인원수와 모델이 예측한 인원수의 차이’를 절댓값으로 구해서 평균 낸 거지. 방금 계산한 것처럼 모델 A의 오차는 40명, 모델 B의 오차는 10명이니까. 인원 계수 관점에서는 모델 B가 더 나은 예측을 했다고 볼 수 있어.”
루나는 덧붙였다. “물론, 우리가 어떤 예측을 ‘맞았다(True Positive)’고 판단하는 기준도 중요해. 이번 프로젝트에서는 단순히 바운딩 박스가 겹치는 비율(IoU)만 본 게 아니라, 박스 안에 ‘사람의 머리 좌표가 포함되었는지’를 기준으로 삼았어. 밀집된 환경에서 사람 수를 정확히 세려면, 몸이 아니라 머리를 기준으로 세는 게 더 정확하니까. 이런 기준이 Precision과 Recall 수치에 직접적인 영향을 주지.”
솔라는 이제 세 개의 지표가 왜 한 세트처럼 움직여야 하는지 이해했다.
- Precision (정밀도): 모델의 예측이 얼마나 믿을 만한가? (헛스윙 비율)
- Recall (재현율): 실제 대상을 얼마나 놓치지 않고 찾아냈는가? (놓친 공 비율)
- MAE (평균 절대 오차): 그래서, 최종 인원수 예측은 얼마나 차이가 나는가? (최종 스코어 오차)
“알겠다, 언니. Precision이 높아도 Recall이 낮으면 놓치는 사람이 너무 많아서 총 인원수가 틀리고, Recall이 높아도 Precision이 낮으면 없던 사람을 만들어내서 또 총 인원수가 틀리는구나. 그리고 그 최종적인 ‘계수 오차’를 MAE가 딱 잡아주는 거고. 이 세 가지는 항상 같이 봐야 의미가 있겠어.”
솔라는 자신이 정리한 내용을 되뇌며 만족스러운 표정을 지었다. 하지만 이내 새로운 궁금증이 고개를 들었다. 그녀는 다시 원래의 성능 평가표로 시선을 돌렸다.
“그런데 이상한 점이 있어. 이 모든 카메라에 똑같은 YOLO 모델을 썼잖아. 그런데 왜 카메라마다 Precision, Recall, MAE 값이 이렇게 제각각인 거야? 067_1층 카메라는 Precision 94%, Recall 82%로 균형이 좋은데, 왜 하필 068_2층_2 카메라는 Recall이 그렇게까지 낮게 나온 거지? 같은 모델인데도 말이야.”
3장: 카메라 위치, 유리, 밀집도가 어떻게 Precision·Recall·MAE에 영향을 미치는가?
솔라의 질문이 끝나기 무섭게, 루나는 대답 대신 조용히 마우스를 움직였다. 화면에 떠 있던 성능 평가표가 깜박이더니 순식간에 재정렬되었다. 원래 카메라 ID 순서로 나열되어 있던 목록이 두 개의 그룹으로 나뉘었다. 위쪽 그룹에는 ‘Good Balance’라는 작은 제목과 함께 067_1층 카메라가 보였고, 아래쪽 ‘Problematic’ 그룹에는 솔라에게 익숙한 068_2층_2 카메라와 그동안 눈여겨보지 않았던 055_외부 카메라가 함께 묶여 있었다.
솔라는 바뀐 화면을 보며 눈을 찡그렸다. 068_2층_2 카메라가 ‘문제 그룹’에 있는 것은 이제 이해가 갔다. Recall이 58.1%로 처참했으니까. 하지만 다른 하나는 낯설었다.
“‘Problematic’ 그룹? 055_외부 카메라는 왜? Recall은 91.2%로 괜찮은 편인데. Precision이 85.0%라 그런가? 90%가 넘는 다른 카메라들에 비하면 낮긴 하지만… 모델을 좀 더 학습시키면 해결될 문제 아니야?”
솔라의 시선은 ‘모델만 좋으면 다 해결될 것’이라는 기대를 담고 있었다. 같은 모델을 썼는데 왜 성능이 다른지 궁금해하던 참이었다. 환경 탓이라고 하기엔, 아직 모델의 능력을 더 믿고 싶었다.
“모델을 개선하기 전에, 이 카메라가 뭘 보고 있는지 먼저 확인해 보자.”
루나는 055_외부 카메라의 분석 폴더를 열어 영상을 화면 전체에 띄웠다. 영상은 카페 입구 바깥에서 대기 줄을 비추고 있었다. 유리문 안쪽으로 매장 풍경이 어렴풋이 보였고, 카메라의 시야 가장자리로는 행인들이 바쁘게 오가는 보도가 걸쳐 있었다.
“자, 솔라. 여기서 우리가 인원수를 세어야 하는 대상은 누구지?”
“당연히 저기 줄 서 있는 사람들이지.”
솔라는 명확하게 대답했다. 루나는 고개를 끄덕이고는 영상 위에 모델의 예측 결과를 겹쳐서 보여주는 옵션을 켰다. 초록색 네모 상자들이 사람들 머리 위로 나타나기 시작했다. 솔라는 처음엔 별문제를 찾지 못했다. 모델은 줄 서 있는 사람들을 제법 잘 찾아내고 있었다.
하지만 영상을 계속 보고 있자니, 이상한 점이 눈에 띄기 시작했다.
“어? 잠깐만. 저기… 줄 옆으로 그냥 지나가는 사람한테도 박스가 생겼어. 저 사람은 매장에 들어올 손님이 아닌데.”
그뿐만이 아니었다. 모델은 대기 줄 근처에 세워진 입간판에 그려진 사람 일러스트에도 초록색 상자를 그렸다. 심지어는 빠르게 지나가는 자전거 탄 사람의 실루엣에도 순간적으로 상자가 생겼다가 사라졌다.
그제야 솔라는 Precision 85.0%의 진짜 의미를 깨달았다. 모델이 ‘사람’이라고 예측한 100번의 판단 중 15번은 대기 줄의 손님이 아닌 행인, 포스터, 혹은 다른 무언가였다는 뜻이었다. 이것들은 전부 오탐지(False Positive)였고, 인원 계수의 정확도를 떨어뜨리는 직접적인 원인이었다.
“아…! 알겠다. 모델은 그냥 ‘사람처럼 생긴 형체’를 다 찾아낸 거구나. 그게 우리가 세어야 할 ‘대기 고객’인지, 아니면 그냥 ‘지나가는 행인 1’인지는 전혀 구분하지 못했던 거야.”
“맞아. 이 카메라의 환경은 모델에게 아주 헷갈리는 문제를 낸 셈이지. ‘사람’이라는 객체는 맞지만, 우리가 원하는 ‘맥락’ 속의 사람이 아닌 경우가 너무 많았던 거야. 그래서 헛스윙이 많아지고 Precision이 떨어진 거지.”
루나는 말을 이으며 이전 장에서 봤던 068_2층_2 카메라의 영상을 작게 띄웠다. 유리창 빛 반사가 심했던 그 영상이었다.
“그럼 이 두 ‘문제아’ 카메라를 다시 비교해 볼까? 055_외부 카메라는 ‘있어서는 안 될 것(배경)’을 너무 많이 봐서 Precision이 문제였어. 그럼 068_2층_2 카메라는?”
솔라는 두 영상을 번갈아 보았다. 하나는 헛것을 보는 카메라, 다른 하나는 있어야 할 것을 못 보는 카메라. 원인은 달랐지만, 결과적으로는 둘 다 인원 계수라는 목적에 실패하고 있었다.
“068_2층_2 카메라는 ‘있어야 할 사람’을 제대로 못 봐서 Recall이 문제였지. 유리창 빛 반사 때문에….”
솔라는 말을 잇다 말고 무언가 중요한 사실을 깨달은 듯 손뼉을 쳤다.
“결국 모델의 성능은 모델 자체만으로 결정되는 게 아니었어! 어떤 데이터를 ‘먹이’로 주느냐에 따라 결과가 완전히 달라지는 거였네. 그리고 그 데이터는 카메라가 어디에, 어떻게 설치되었는지, 즉 ‘환경’이 결정하는 거고.”
솔라는 머릿속에서 조각들이 맞춰지는 기분을 느꼈다.
- 유리창, 빛 반사, 가림 현상: 봐야 할 사람을 못 보게 만듦 → Recall 저하
- 복잡한 배경, 계수 대상 외의 인물: 헛것을 보게 만듦 → Precision 저하
- 사람들이 겹쳐 보이는 밀집 구도: 숨겨진 사람을 놓침 → Recall 저하
같은 YOLO 모델이라도 카메라의 구도, 유리창 유무, 배경의 복잡성에 따라 전혀 다른 성능 지표를 보일 수밖에 없다는 사실을 비로소 체감하게 된 것이다. 더 이상 “모델만 좋으면…” 같은 소리를 할 수 없었다. 중요한 건 환경과의 상호작용이었다.
“이제 알겠어, 언니. 왜 카메라마다 성능이 제각각이었는지. 그럼 우리는 뭘 해야 해? 067_1층처럼 운 좋게 환경이 딱 맞는 카메라만 골라서 써야 하는 거야? 문제가 있는 카메라들은… 그냥 다 포기해야 하나?”
4장: 다양한 카메라 환경별 성능 지표 분석 및 적용 가능성 판단
솔라의 질문이 남긴 공백을 채운 것은 루나의 키보드 소리였다. 루나는 이전 장에서 ‘Good’과 ‘Problematic’으로 나누었던 화면의 그룹명을 지웠다. 대신, 전체 성능 평가표를 다시 불러와 데이터를 다른 기준으로 정렬하기 시작했다. 이번에는 Precision이나 Recall 어느 한쪽이 아닌, 두 지표의 조화 평균을 나타내는 F1-score가 높은 순서였다.
맨 위로 올라온 것은 067_1층 카메라였다. 바로 그 아래에는 솔라가 ‘문제아’라고 생각했던 068_2층_2 카메라가 자리했다. 루나는 두 카메라의 행을 나란히 붙여놓고, 화면에 작은 메모장을 띄워 각 카메라의 핵심 지표를 옮겨 적었다. 마치 두 선수를 비교 분석하는 표처럼 보였다.
| 카메라 ID | 환경 특성 | Precision | Recall | F1-score | MAE |
|---|---|---|---|---|---|
067_1층 | 실내, 가림 없음, 선명 | 94.0% | 82.1% | 87.6% | 2.8명 |
068_2층_2 | 유리창 너머, 빛 반사 | 95.9% | 58.1% | 71.9% | 7.2명 |
솔라는 말없이 화면에 떠오른 두 개의 행을 응시했다. 지난 몇 시간 동안 자신을 혼란스럽게 했던 숫자들의 정면 대결이었다. 모든 환경 요인을 파악하고, 각 지표의 의미를 이해한 지금, 솔라는 이 표를 보며 결정을 내려야 했다. 좋은 카메라와 나쁜 카메라를 골라내고, 쓸모없는 것은 버려야 했다.
“그래서… 결국 어떤 카메라를 써야 하는 거야? F1-score가 높은 067_1층이 제일 좋은 거니까, 저걸 써야 하는 거지? Precision이 가장 높았던 068_2층_2는 그냥 포기하고?”
솔라의 목소리에는 명쾌한 답을 원하는 조급함이 묻어났다. 이제는 원리를 알았으니, 정답을 고르고 싶었다.
루나는 대답 대신 질문을 돌려주었다.
“‘어떤 카메라를 써야 하는가’라고 묻기 전에, 우리가 ‘무엇을 위해’ 이 시스템을 쓰려는지 다시 생각해 보자. 우리의 목표는 매장 안의 ‘실제 인원수’에 최대한 가까운 값을 얻는 거야. 그렇지?”
루나는 068_2층_2 카메라의 Precision 값인 ‘95.9%’를 마우스 커서로 가리켰다.
“이 숫자는 여전히 매력적이야. ‘모델이 사람이라고 한 예측은 96% 확률로 진짜 사람이다.’ 이 특성만 떼어놓고 보면 쓸모 있는 곳이 있지 않을까?”
그 말에 솔라는 잠시 생각에 잠겼다. 분명 Recall이 낮아 인원 계수에는 치명적이었지만, 예측의 ‘정확성’ 하나만큼은 최고 수준이었다.
“음… 예측이 틀리면 큰일 나는 상황? 예를 들어, VIP 고객의 얼굴을 인식해서 알림을 주는 서비스라면? 사람이 아닌데 VIP라고 잘못 알려주면 안 되니까… Precision이 극도로 중요한 상황에서는 유용할지도 몰라.”
“그럴 수 있겠네. 그럼 반대로 067_1층은 어떨까? Precision은 약간 낮지만, Recall과 균형이 좋고 MAE, 즉 평균 오차 인원도 2.8명으로 훨씬 작아.”
루나의 질문에 솔라는 두 카메라의 상황을 머릿속에 그렸다. 실제 100명이 있는 공간을 가정했다.
068_2층_2 카메라는 Precision이 높아 헛짚는 경우는 거의 없겠지만, Recall이 낮아 약 58명 정도만 찾아낼 것이다. 실제 인원수와의 오차는 42명.
067_1층 카메라는 Precision이 94%라 가끔 헛짚는 경우가 있더라도, Recall이 82%이므로 약 82명 정도는 꾸준히 찾아낼 것이다. 전체 예측 인원수는 실제 값에 훨씬 근접할 것이다.
그 차이를 상상하자 결론은 명확해졌다.
“아…! 알겠다. 우리는 지금 ‘한 명이라도 놓치면 안 되는’ 탐지 시스템이 아니라, ‘전체 인원 총합’이 중요한 계수 시스템을 만들고 있잖아. 그렇다면 한두 번 헛짚더라도(낮은 Precision) 전체 사람을 최대한 많이 찾아내는(높은 Recall) 편이 최종 오차(MAE)를 줄이는 데 훨씬 유리하구나. 그런 의미에서 067_1층 카메라가 보여주는 균형 잡힌 성능이 인원 계수 목적에는 훨씬 더 적합한 거였어.”
솔라는 F1-score 열을 다시 보았다. 87.6%. 단순히 높은 숫자가 아니라, Precision과 Recall 사이의 건강한 균형을 증명하는 값으로 보였다. 068_2층_2의 Precision 95.9%라는 단일 지표에 더는 현혹되지 않았다. 중요한 것은 여러 지표를 종합적으로 보고, 주어진 ‘목적’에 맞는지를 판단하는 능력, 즉 계수 적합성 판단이었다.
솔라는 이제 평가표를 어떻게 읽어야 할지 알 것 같았다. 먼저 MAE를 통해 실제 계수 오차가 서비스 허용 범위 안에 드는지 확인한다. 만약 MAE가 크다면, Precision과 Recall을 살펴 문제의 원인이 ‘헛것을 많이 봐서’인지, ‘있는 것을 못 봐서’인지를 진단한다. 그리고 그 원인을 카메라의 환경 특성과 연결해 분석하는 것이다.
스스로 생각의 흐름을 정리한 솔라는 만족스러운 표정을 지었다. 하지만 이내 새로운 의문이 떠올랐다. 이제 어떤 카메라가 ‘적합한지’는 판단할 수 있게 되었다. 그렇다면 ‘부적합한’ 카메라들은 어떻게 해야 할까?
“좋아, 언니. 이제 카메라마다 어떤 기준으로 평가하고 선택해야 할지는 알겠어. 067_1층처럼 균형 잡힌 카메라가 우리의 우선순위라는 것도. 그런데… 068_2층_2나 055_외부처럼 문제가 명확한 카메라들은 어떡하지? 그냥 ‘측정 불가’ 딱지를 붙이고 포기해야 해? 아니면 이 카메라들도 어떻게든 쓸모 있게 만들 방법이 있는 거야?”
5장: 측정 가능한 구역 (ROI) 설정과 카메라 재배치를 통한 서비스 적용 전략
솔라의 마지막 질문이 남긴 침묵을 깬 것은 루나의 조용한 움직임이었다. 루나는 대답 대신, 여러 카메라의 성능 지표가 나열된 화면을 잠시 바라보았다. 그리고는 평가표의 ‘부적합’ 딱지가 붙었던 두 카메라, 055_외부와 068_2층_2의 분석 폴더를 다시 열었다. 단순히 포기하기에는 그동안 들인 노력이 아까웠다.
먼저 화면에 가득 찬 것은 055_외부 카메라가 촬영한 영상이었다. 카페 바깥의 대기 줄과 그 옆을 스쳐 지나가는 행인들, 그리고 배경의 현란한 간판들이 다시 보였다. 낮은 Precision의 원인이었던 ‘헛것’들이었다.
“이 카메라를 어떻게든 쓰려면… 결국 모델을 더 똑똑하게 만들어야 하는 거 아닐까?”
솔라는 조심스럽게 자신의 생각을 꺼냈다. ‘부적합’이라는 결론에 쐐기를 박기 전, 마지막으로 가능한 해결책을 쥐어짜 내고 싶었다.
“예를 들면, 대기 줄에 서 있는 사람들의 특징만 따로 학습시키는 거지. 보도를 걷는 사람이나 간판 속 인물은 사람이 아니라고 가르치는 거야. 데이터를 더 모아서 모델을 재학습시키면 Precision을 올릴 수 있을지도 몰라.”
그것은 가장 직관적인 해결책이었다. 모델의 성능이 문제이니, 모델을 개선하는 것. 하지만 루나는 솔라의 제안에 바로 동의하지 않았다. 대신 마우스를 움직여 영상 위에 반투명한 편집 도구를 활성화했다. 그리고는 화면 위에 조심스럽게 사각형 하나를 그리기 시작했다. 사각형은 행인들이 지나다니는 보도와 배경 간판들을 모두 제외하고, 오직 고객들이 줄을 서는 대기 공간만을 정확히 감쌌다.
“모델을 바꾸기 전에, 모델이 풀어야 할 ‘문제’를 다시 정의해 보면 어떨까? 만약 모델이 이 세상 전부가 아니라, 오직 이 네모난 상자 안의 세상만 보도록 한다면 말이야.”
화면에는 루나가 그린 ‘관심 영역(Region of Interest, ROI)’이 선명하게 표시되어 있었다. 그 순간, 솔라의 머릿속에 번개가 쳤다.
“아…!”
문제의 본질이 바뀌는 순간이었다. 지금까지는 모델이 스스로 ‘대기 고객’과 ‘지나가는 행인’을 구분해주길 바랐다. 하지만 관심 영역을 지정하자, ‘지나가는 행인’이라는 오답 자체가 문제의 범위 밖으로 사라져 버렸다. 모델은 더 이상 어려운 구분 문제를 풀 필요가 없었다. 그저 네모 상자 안에 나타나는 사람의 수를 세기만 하면 되었다. 헛스윙을 유발하던 혼란스러운 배경이 원천적으로 차단된 것이다.
“이렇게 영역을 한정하면, 이 카메라의 Precision은 극적으로 올라가겠네! 우리가 관심 없는 영역에서 발생하던 오탐지(False Positive)가 전부 사라질 테니까.”
“맞아. 모든 카메라에 완벽한 성능을 요구하는 대신, ‘측정 가능한 구역’을 명확히 정의하고 그 안에서의 성능에 집중하는 거지. 이것이 모델을 밑도 끝도 없이 개선하려는 시도보다 훨씬 현실적인 첫 번째 대응이야.”
솔라는 이 새로운 관점에 완전히 매료되었다. 그렇다면 Recall이 문제였던 068_2층_2 카메라는 어떨까? 솔라는 스스로 질문을 던지며 루나가 했던 것처럼 068_2층_2의 영상 위에 가상의 네모를 그려보았다. 유리창 너머, 빛 반사가 심하고 사람들끼리 겹쳐 보이는 그 영상이었다.
“이 카메라는… 문제가 좀 다르네. 관심 영역을 설정해서 헛것을 보는 문제는 해결할 수 있지만, 애초에 사람이 안 보이는 문제는 그대로 남아있어. 빛 반사가 심한 구역을 ROI에서 제외하면… 그곳에 있는 사람은 아예 세지 않겠다는 뜻이 되잖아. 이건 우리가 원하는 게 아닌데.”
솔라는 스스로 문제의 핵심을 짚어냈다. 055_외부 카메라의 문제는 ‘너무 많이 봐서’ 생긴 것이라 영역을 ‘좁히는’ 것으로 해결 가능했다. 하지만 068_2층_2 카메라의 문제는 ‘제대로 못 봐서’ 생긴 것이었다. 소프트웨어적인 구역 설정만으로는 물리적인 한계를 극복할 수 없었다.
“그렇다면 이 카메라에 대한 진짜 해결책은… 모델 튜닝도, ROI 설정도 아니야. 근본적인 원인인 ‘환경’ 자체를 바꿔야 해. 즉, 카메라를 다른 위치로 옮겨서 빛 반사와 가림 현상이 없는 각도를 찾아야 하는 거구나.”
솔라는 마침내 흩어져 있던 조각들을 하나로 꿰어 맞췄다.
- Precision이 문제일 때: ROI를 설정해 혼란스러운 배경(오탐지 원인)을 제거한다. (소프트웨어적 해결)
- Recall이 문제일 때: ROI만으로는 한계가 명확하다. 카메라의 물리적 위치를 변경해 가림, 빛 반사 등(미탐지 원인)을 제거한다. (하드웨어/설치 환경적 해결)
모델의 이름이나 단일 지표에 매몰되는 대신, 카메라의 환경과 그에 따른 P/R/MAE 지표를 종합적으로 분석하여 최적의 대응 전략을 수립하는 것. 그것이 바로 이 복잡한 평가표 뒤에 숨겨진 진짜 교훈이었다. 이것이 바로 ROI 기반 개선 방안이었다.
“알겠다, 언니. 모든 문제를 모델 탓으로 돌리는 게 얼마나 단순한 생각이었는지. 어떤 문제는 똑똑한 모델이 아니라, 더 나은 ‘질문’을 던지는 것만으로도 풀리는 거였어.”
그때, 루나가 새 메모장을 화면에 띄우며 말했다.
“좋아, 솔라. 그럼 마지막 과제야. 새로운 카페 지점에 인원 계수 시스템을 도입하려고 해. 매장 구조는 이렇고, 천장에 카메라를 한 대 설치할 예정이야.”
화면에는 긴 복도 형태의 매장 도면이 나타났다. 한쪽 벽면 전체가 거울로 되어 있어 공간이 넓어 보이는 효과를 주고 있었다.
솔라는 더 이상 어떤 모델을 쓸지, 목표 정확도를 얼마로 잡을지 묻지 않았다. 대신, 펜을 들고 직접 보고서를 작성하기 시작했다. 마치 자신이 이 프로젝트의 책임자가 된 것처럼.
[신규 지점 인원 계수 카메라 설치 및 운영 방안]
1. 제안:
- 카메라 위치: 출입구 반대편 천장 모서리에 설치. 벽면 거울이 직접 비치지 않는 각도로 조정 필수.
- 초기 설정: 관심 영역(ROI)을 매장 내 실제 고객 동선으로 한정. 거울에 비친 허상 및 출입구 밖 영역은 제외.
2. 성능 검증 계획:
- 설치 후 일주일간 테스트 운영하며 P, R, MAE 데이터 수집.
- 판단 기준:
- MAE가 허용 오차(예: 3명) 이내인가?
- MAE가 클 경우, 원인 분석:
- Precision이 낮은 경우: ROI 영역 재조정으로 배경 노이즈 제거.
- Recall이 낮은 경우: 거울 반사 또는 물리적 가림이 원인일 가능성 높음. 카메라 재배치를 최우선 과제로 검토.
3. 최종 결론:
- 모든 환경에 동일한 성능을 기대하지 않는다. 환경 분석에 기반한 ROI 설정과 필요시 카메라 재배치를 통해 시스템의 측정 가능 범위를 명확히 하고, 그 안에서 신뢰도를 확보한다.
솔라는 자신이 작성한 짧은 보고서를 루나에게 보여주었다. 더 이상 숫자 하나에 흔들리거나, 막연히 모델 개선만을 외치던 모습은 없었다. 문제를 정의하고, 측정하고, 분석하고, 개선하는 전체 과정을 스스로 설계할 수 있게 된 것이다. 루나는 보고서를 조용히 읽어 내려가더니, 만족스러운 미소와 함께 고개를 끄덕였다.