brunch

You can make anything
by writing

C.S.Lewis

by JejuGrapher Aug 25. 2020

달고나 8. 학습, 테스트 그리고 추론

Practice: Training, Test and Inference

멘티의 인턴 과제는 도달수 (Reach)를 예측하는 모델을 개선하는 거였다. 도달수 예측이란 광고주가 설정한 타게팅 조건과 일 예산 범위 내에서 해당 광고가 노출될 유니크 사용자수를 추정하는 거다. 타게팅 모수는 타게팅 조건에 부합하는 모든 사용자의 규모를 알려주는 정적인 수치라면, 도달수는 실제 광고를 본/볼 사용자수를 의미하며 광고가 전달되는 환경에 따라 변하는 동적인 수치다 (도달수 <= 타게팅 모수). 그리고 도달수에 사용자당 평균 노출회수를 곱하면 해당 광고의 전체 노출수 impression이 된다. 정의에서 알 수 있듯이 도달수가 종속 변수 (Y)가 되고, 예산과 타게팅 조건이 중요 독립 변수 (X)가 된다. 모바일 DSP를 준비하면서 조금 급하게 만들었던 예측 모델의 검증과 개선을 겸해서 이 과제를 선정했다. 


6주 간의 시행착오 끝에 기존 모델보다 더 정확한 모델이 나와서 나름 만족했지만… 처음 문제와 데이터를 검토할 때 바로 떠오르는 생각으로 완벽한 모델을 만들 수 없다. (물론 멘티의 최종 모델은 내가 애초에 이 문제를 접했을 때 생각했던 방법에서 크게 벗어나지 않았다. 이후에 다른 방법론도 구상했지만 구현과 실험은 하지 못했다.) 문제 자체를 재정의하거나 데이터나 모델 (알고리즘)을 바꿔가면서, 때론 하이퍼-파라미터를 바꿔가면서 수많은 시행착오를 거쳐 모델이 완성된다. 그런 시행착오 과정 중에 한번 언급/점검했었는데 최종 모델을 검증할 때 결정적인 것을 놓쳐버렸다. 이걸 무시한다면 결과가 좋지만 이게 고려됐을 때도 같은 결과가 나왔을지는 조금 의문이다.


주어진 데이터를 학습과 테스트 데이터로 분리해서 모델을 만들고 검증하는 건 데이터 과학의 기본이다. 때론 (데이터의 양이 충분히 많을 때) 학습 training, 검증 validation, 테스트 test 3개 파트로 구분하기도 하지만, 검증과 테스트를 같은 의미로 종종 사용하니 편의상 글에서는 테스트 데이터로 통칭한다. 데이터의 양에 따라서 학습과 테스트 데이터는 보통 7:3이나 9:1 정도로 구분하고, 양이 적을 때는 (5/10-fold) cross-validation을 시행하거나 배깅/랜덤샘플링을 반복하며 모델을 학습하고 성능을 평가한다. 그리고 시계열성이 있는 데이터는 시간상 앞쪽의 데이터를 학습으로, 뒤쪽을 테스트로 구분하는 게 일반이다. 이렇게 구분해서 과학습되지 (over-fitted) 않은 최적의 모델을 결정한다.  


여기까지 이렇게 진행했다면 훌륭하다. 이런 프랙티스가 몸에 배었다면 제대로 훈련받았다고 본다. 그런데 실전에서는 문제의 소지가 있다. 주어진/같은 데이터 (X-Y)를 스플릿했기 때문에 학습 데이터와 테스트 데이터는 형태상, 의미상 동일하지만, 실제 서비스에서 사용될 데이터는 다를 수 있다. 테스트 데이터 상으로 정확한 예측 모델을 만드는 것이 목적이 아니라, 그걸 기반으로 실제 환경에서 정확하게 예측하는 것이 데이터 과학의 목적이다. 실제 서비스에서 제대로 작동해야 한다. 실 서비스를 고려하면 모델 구축 과정은 학습, 테스트, 그리고 추론 (inference)로 나눠야 한다. 학교의 수업/연구나 kaggle 같은 경연에서는 테스트 정확도가 높으면 끝나지만, 실전에서는 테스트 정확도가 높은 것에 더해서 실제 서비스에서 정확해야 한다. 즉, 모델과 데이터를 정하고 학습할 때 추론을 염두에 둬야 한다. 


인턴 과제로 돌아가서 중간에 어떤 데이터와 변환으로 독립 변수로 정할지를 고민할 때 아래 그림처럼 X와 Y를 학습, 테스트, 추론에서 어떤 형태로 지정되는지를 점검했었다. 편의를 위해서 타게팅은 제외하고 예산만으로 도달수를 예측한다고 하자. 어떤 광고주가 예산 (Budget) 10만 원 등록했지만 실제 과금 (ChargeAmount)은 10만 원이 딱 떨어지지 않는다. 노출량이 적으면 예산에 못 미치고 허용 범위 내의 오버스펜딩으로 예산이 초과되기도 한다. 그래서 모델 학습과 테스트에는 광고주가 설정한 예산 (B)이 아니라, 실제 과금했던 과금액 (CA)을 독립 변수로 사용한다. 그런데 추론 시에는 (존재하지 않는) 과금액이 아니라, 광고주가 설정한 일예산 (B)를 사용해야 한다. 과금액과 예산은 문제가 단순해서 별로 이견이 없는데, 멘티가 사용한 타게팅 인코딩에서는 문제가 있었다. 이 부분을 최종 점검할 때 놓쳤다는 점에서 아직은 더 노력하고 발전해야 한다고 나름 반성하고 있다. 


문제를 단순화하기 위해서 타게팅 조건은 성별 (남녀), 나이대, 그리고 시/도 레벨의 지역으로 한정했다. 하루 단위로 광고별로 이를 본 사용자들의 속성 (성, 연령, 주요 출몰 지역)을 로그 (LOG)에서 가져와서 다음과 같은 긴 데이터를 만들었다. [광고ID - 과금 총액 - 속성1 여부 - 속성2 여부 - … - 속성n 여부 - UV] 그런데 ‘속성i 여부’를 그냥 Boolean (0/1)로 표현하니 정확도 개선이 충분치 못해서 이걸 '(광고별) 전체 노출수 대비 개별 속성의 출현 빈도’의 비율로 변환해서 데이터를 만들었다. 이렇게 데이터를 가공해서 학습 / 테스트 데이터로 나눠서 진행했더니 운 좋게도 Boolean보다 훨씬 좋은 성능을 보였다. 여기까지만 보면 해피엔딩이다. 


그런데 앞서 길게 언급했듯이 추론에서 문제가 발생한다. 학습과 테스트 데이터는 기존 로그에서 각 속성의 노출 비율을 집계해서 사용할 수 있지만, 추론에서는 이 비율을 얻을 수 없다. 광고주가 DSP에 새로운 광고를 등록할 때 타게팅 조건과 예산을 등록한다. 예산 (B)은 과금액과 문제없이 호환되지만, 타게팅 조건은 속성별로 0 또는 1로 표현되기 때문에 앞서 학습/테스트에서 사용한 비율과 차이가 있다. 0 ~ 1 사이 값으로 학습한 모델에 0 또는 1만 넣으면 당연히 결과가 좋을 리 없다. 추론 과정을 고려하지 않은 데이터 정의 또는 예측 모델이다. 서비스를 위한 데이터 과학은 늘 실 서비스, 즉 추론을 염두에 두고 설계해야 한다. 타게팅 조건을 비율로 변환하는 새로운 로직이나 데이터 작업이 필요하다. 이게 불가능하다면 조금 덜 정확한 Boolean 변수로 회귀해야 한다. 


불행 중 다행은 대부분의 경우 추론 데이터가 학습, 테스트 데이터와 같거나 호환된다는 점이다. 하지만 늘 그렇지는 않다.

매거진의 이전글 달고나 7. 데이터 과학자의 발표 자료
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari