발단
의대간 고교친구 S가 갑작스럽게 이 대회를 하자고 연락했다.
솔직히 연락을 처음 받은 순간에는 거절하고자 하는 마음이 더 컸다.
스누포 앙상블 등으로 한창 바쁘던 시기가 막 끝난 시점이었고, 조금은 휴식의 시간을 갖고 싶었었다.
인공지능이라고는 고교때 잠깐 끄적여본 기본적인 인공신경망이 전부였다. '의료' 해커톤인 점 또한 망설이게 만들었다. 과연 내가 이 대회에 유의미한 기여를 할 수 있을까..? 하는 의문이 컸다고 할 수 있겠다..
하지만 내가 항상 그렇듯 일단 일을 벌리고 본다.
고민해보고 답장을 주겠다는 연락을 보낸 순간, 난 이미 할일 스택에 이 대회를 올려놓았을거다.
전개
나와 친구 S, 그리고 친구의 선배 P로 Team Softmax가 구성되었다.
올해 신설된 AI 트랙이라 그런지 대회 방식이나 안내사항 등에서 미숙한 점이 많이 보였다.
특히 데이터 관련 공지의 경우, 거의 뭐가 뭔지 도통 알 수 없는 수준이어서 여러 편의 문의 메일을 주고받은 후에야 갈피를 잡았다.
$666$명의 환자 데이터가 있는데, 각각에 대해 feature $17$개의 집합 $X$가 주어지고, 약물치료 여부 $A$와 생존시간 $Y$가 주어진다. 해커톤의 목표는 $X$만 주어진 테스트 데이터 $286$명에 대해 치료 진행 여부를 결정짓는 것이다. 제출은 대회 종료일까지 하루에 다섯 번씩 가능했고, 매 제출마다 $286$명 중 올바르게 결정된 치료여부의 개수가 리턴되었다.
카페에서 처음으로 팀이 모여 문제 해결의 방향성을 논의한 결과, KNN 방식으로 판별하고자 하는 환자와 유사한 전례들을 살펴보고, 치료여부와 생존시간을 살펴봄으로써 action(치료여부)를 결정하자는 방법이 제시되었다.
위기
KNN 접근의 스코어가 부진했다. Neighbour를 뽑는 기준, 거리와 개수에 따른 가중치 등 여러 값들을 조정해가며 제출해보았지만, 미세한 진전만 있을 뿐, 스코어 $200$을 넘지 못했다.
대회를 진행하면서 이 시점이 제일 시상으로부터 거리가 멀게 느껴졌던 때 같다.
당시 스코어보드를 리딩하고 있는 팀들은 벌써 $250$ 이상의 값들을 찍고 있었다.
하지만 우리에게는 $200$의 벽도 너무 크게 느껴졌다.
Cox regression을 통해 생존 시간과 $X$의 상관관계를 살펴보는 시도가 시작된 것이 이때이다.
처음 P 선배가 제시했던 방법은 action과 $X$가 $Y$에 주는 영향을 분석하는 것이었다. 이러한 분석 방법은 Cox regression에서 일반적인 듯 하다. 하지만 분석 방법에 대해 카톡을 나누던 중, action에 따라 환자들을 두 군으로 나눈 후 X의 각 feature의 영향을 살펴봐야 한다는 생각이 들었다. 치료 여부에 따라 $X$가 $Y$에 영향을 주는 방식이 다를 것이라고 생각했기 때문이다. 그래서 Cox regression을 기반으로, 치료 여부가 주어지면 $X$로부터 기대 생존시간을 계산하는 모델을 만들었다. 이제 치료 여부를 판단하는 로직은, 단순히 그 환자를 치료했을 시의 기대 생존시간과 치료하지 않았을 경우의 기대 생존시간의 대소비교로 간단하게 할 수 있게 되었다.
이렇게 2-model 접근을 시도한 첫 제출은...
놀랍게도 $255$의 스코어를 받았다.
절정
Cox regression을 이용한 모델의 성공은, 치료한 환자와 그러지 않은 환자를 나누어 트레이닝하는 2-model approach에 대한 확신으로 이어졌다.
다음으로 시도해봐야 할 일은 명확했다.
바로 신경망의 도입이다.
Cox 모델의 성공은, $X$로부터 $Y$로 가는 적당한 함수가 존재함을 시사했다.
Cox regression은 proportional hazards function이라는 가정을 두고 fitting을 진행한다.
하지만 인공신경망은 그런 가정 없이, 임의의 비선형 함수를 fitting할 수 있다.
Pytorch를 처음 써봤다. 신경망으로 모델을 구현해야겠다는 다짐을 한 지 3시간만에 빠른 구글링을 통해 첫 모델을 만들어낼 수 있었다. 가장 단순한 시그모이드 MLP로, 3년 전 고2때의 프로젝트에서 사용된 것과 사실상 동일한 신경망이었다. 결과는 $270$의 스코어였다. 모두가 방법에 대해 확신한 순간이다.
이 이후의 과정은 신경망 하이퍼파라미터 튜닝과 학습의 연속이었다.
수능 끝나고 맞춘 비싼 데스크탑을 드디어 본 목적에 맞게 쓰고 있었다 ㅋㅋㅋㅋ
우리의 점수는 만점인 $286$을 향해 수렴해 나갔고, 신경망의 하이퍼파라미터 또한 최적의 값으로 하나씩 맞춰졌다.
결말
1등을 했다.
시그모이드 활성화함수, 은닉층 3개에 17-64-32-16-1의 노드수를 가지는 fully connected 신경망 32쌍을 앙상블해 만든 우리의 모델은 만점을 달성했다. 만점 팀이 하나 더 있었지만, 비공개 테스트케이스로 추가 검증을 한 결과, 우리 팀의 모델이 더 정확했다고 한다...
하지만 찝찝했다. 이토록 간단한 모델이 1등을 한다고???
데이터의 정체를 알게되자 의문이 풀리게 되었다.
생존시간 데이터는 시뮬레이션에 의해 만들어진 것이었으며, X에 가중치를 곱한 후 시그모이드 함수를 통과시킨 값을 exponential에 올린 결과가 생존 시간이었던 것이다 ㅋㅋㅋㅋㅋ
우리의 모델은 무려... 생존 시간에 로그를 취하고, 시그모이드 함수를 통과시키기 전 가중치들을 학습하는 신경망 모델이다... 시그모이드 함수로 시그모이드 함수를 근사한 꼴이다. (ReLU 함수보다 Sigmoid의 성능이 높게 나온 이유를 대회가 끝나고서야 알았다.)
데이터의 정체를 알게되니 뭔가 허탈하긴 하지만, 등록한 22팀 중에서 1등을 한 사실은 변하지 않는 것이긴 하다...
다들 너무 복잡하게 생각한걸까?
후기
음... 뜻밖에 얻어가는 것이 많은 대회가 되었다.
일단 제일 소중한 것은 파이토치 사용법을 익히고 신경망 하이퍼파라미터 튜닝을 제대로 해본 것이다.
덩달아 numpy와 pandas같은 라이브러리 또한 더 잘 알게 되었다.
대상과 상금을 받은 것은 그 다음으로 소중한 것 같다.
크진 않은 금액이지만, 대회에서 벌어들인 첫 돈인 만큼 의미가 있다고 본다.
2018년에 데스크탑을 맞추면서, "이 데탑을 맞추는데 들어간 비용만큼의 가치를 창출하면 되지!!!" 라고 생각했었는데, 일단 이번 대회에서는 확실히 가치를 창출해냈다.
대회에 대해 평가하자면... 음... 내년에는 진짜 데이터를 가지고 처음부터 명확한 공지와 함께 진행해줬으면 한다 ^^
어찌됐든, 내가 좋아하는 Nelson Mandela의 quote를 이뤄낸 또 한번의 사례가 되었다.
"It always seems impossible until it's done."
보너스
내가 그려본 스코어보드 순위변동 그래프이다.
대회 종료 시점까지 반영되어있지는 않다.
2-model 채택 이후 255까지 상승한 스코어가 인상적이다.