블로그에 글을 안 쓴지도 어언 5개월... 6개월이 되기 전에 글을 하나 써야겠다라는 생각은 했다. 그동안 꽤나 많은 게 바뀌었고 내 상반기는 나름 성공적이라고 할 수 있을 것 같다. 아니 대놓고 성공했다. 그래서 오늘은 그 성공의 가장 큰 부분을 차지한 AI RUSH 후기나 몇 자 적어보려 한다.
결론부터 적으면 1등했다! 1500만원! 예!
자기소개서는 '연구를 꿈으로 삼고 있는 희망 가득한 청년이지만 기업에서 실제 데이터를 갖고 모델을 설계하다보니 연구실 안과 밖의 괴리를 경험해 실제 데이터를 다루는 대회에 참가하고 싶다!' 라는 컨셉으로 썼다. 사실 자기소개서는 크게 중요하지는 않을 것 같아서 그렇게 세세하게 적지는 않았다. 대신 Github Repository를 본다고 했는데 AI 관련 해둔게 많아서 걱정은 안했었다.
프로젝트 생각보다 많이 했구나...
그 외에는 Computer Vision 관련 연구실에서 인턴하고 있고 그 당시에는 3D AI 관련 회사에서 일하고 있었다. 또 수상경력도 AI 서비스 기반 창업대회와 대학 연합 데이터톤 우승 경력이 있었다.
아무튼 군 전역하고 나서 1년 반 정도 AI에 인생을 갈아넣었기 때문에 스펙부분에서는 꿀릴게 없었고 또 작년에 내 친구가 AI RUSH 참가했었는데 걔는 뭐 없었는데도 붙었다고 해서 서류에서는 내가 떨어지면 누굴 뽑음? 이라는 마인드였다. 아무튼 그랬다.
서류는 무난히 합격을 했지만 참가만 해도 돈을 주는 이 어마무시한 대회는 코딩테스트도 봐야지만 참가를 할 수 있었다. 하지만 나는 자료구조 A0, 알고리즘분석 A+에 빛나는 우수 학생이기 때문에 걱정은 하지 않았다. 그래도 나처럼 오만함에 빠져 그냥 보러 갔다가 망한 케이스들을 주변에서 몇 개 봤기 때문에 한 이틀정도 프로그래머스 튜토리얼? 같은 문제를 풀어보면서 얼추 감을 잡아놨다.
문제는 어려웠다. 그 오픈채팅 같은데 들어가보니까 취준하는 사람들도 근래 코테 중 가장 어려웠다고 한다. 아니 AI 대회면은 알고리즘도 중요하지만 GPU-friendly한 pytorch 코드나 numpy 챌린지같은 걸 하면 어땠을까 하는 생각도 들었다.
그래도 일단 난 다 풀고 나오긴 했다. 난이도는 4번 > 1번 > 2번 = 3번 이었다. 사실 문제가 잘 기억은 안 나서 아래 후기는 다른 후기들을 좀 참조해서 적었다.
1번. 완전탐색 + 구현 이었다. 근데 구현 조건이 너무 길고 복잡해서 '아니 이게 1번이면 나머지 문제 어떻게 품?' 이었다.
2번. 문자열 + 구현. 파이썬이라 쉽게 풀었다.
3번. 구현. 제일 쉬웠다. 초반에 sort 하나 해놓으면 파이썬 기본 명령어로 다 풀리는 문제였다.
4번. DFS. 인데 이게 문제가 DFS인가? 라고 판단하고 문제를 그래프화 시키는 과정이 좀 어려웠다. 이거 풀 때는 패드 동원해서 그려보면서 풀었는데 마지막에 한 10분 남기고 테케 돌렸을 때 다 맞아서 되게 짜릿했다.
1번 때문에 좀 쫄긴 했으나 2,3번은 굉장히 쉬웠고 4번은 나름 멋있게 풀었다고 생각한다.
1차 대회가 가장 고비였다. 마지막에 Augmentation 안 건드렸으면 그대로 탈락할뻔했다.
AI RUSH 룰을 간단하게 설명해주면 우선 대회가 1,2차로 나뉘어져 있다. 기간은 둘 다 한달씩이다. 그리고 각 차수 별로 태스크가 여러 개 있고, 3주차 때까지는 자유롭게 하다가 4주차부터 인당 하나(2차는 2개)씩 자유롭게 골라서 1차에서는 태스크별 14등까지만 2차로 넘어가고 2차는 결과에 따라 이제 최종 수상을 하는 그런 구조였다.
평소 얼굴 관련 data를 자주 다루는 나이기에 1차 주제들 중 내가 고른거는 Face Age detection이었다. 사람 얼굴이 주어진 데이터셋에 대해서 0:아기, 1:청소년, 2:2-30대, 3:장년, 4:노년 으로 분류하는 태스크였다. 이렇게만 보면 그냥 단순 Classification 문제지만 실제로는 몇 가지 조건이 걸려있어서 이게 좀 까다로웠다.
그래서 결국은 imbalanced dataset을 lightweight model로 풀어봐라 라는 내용이었다.
일단은 3주차까지 성능이 0.3 밑이었다.(Accuracy) 진짜 모델도 바꿔보고 multi-class를 multi-label로도 바꿔보고 Focal Loss, LDAM Loss, reweight, resampling 기타 등등 동네방네 수소문해가며 imbalanced dataset에 좋다는 것들을 다 써봤는데 성능이 안올랐다. 진짜 아니 내가 뭘 애초에 잘못해놨나라고 까지 생각을 했었는데, 그게 맞았다.
옛날에 3DMM 과제했을 때 얼굴 데이터를 꽤나 다뤘었는데, 그때는 Crop + Align이 국룰이었다. 나는 이번에도 얼굴 관련 문제니까 얼굴을 당연히 Crop하고 Align해서 해야지! 라는 가정을 시작하자마자 하고 Crop&Align을 기본으로 박아놨었는데 이게 문제였다. 이걸 빼니까 성능이 우후죽순처럼 올랐다. 사실 아직도 잘 이해는 안 된다, 데이터를 까볼 수는 없으니 원인을 잘 모르겠고 실험할 상황도 아니었고... 원래는 이게 들어가야 하는 거 아닌가??? 라는 생각을 했지만 딥러닝은 이론적인 이해보다 데이터 기반의 실험적인 결과가 더 옳다고 생각하기에 순순히 실험결과를 따랐다.
결국, 나는 LDAM Loss랑 RSG를 사용한 ResNet18을 최종 모델로 제출했다. LDAM Loss, RSG에 대해서 간단히 설명을 해주면...
LDAM Loss: Label distribution을 기반으로 weighted Loss를 주는 기법이다. Focal Loss에 parameter를 distribution에 따라 다르게 적용시켰다 정도로 이해했다.
RSG: ResNet에서 마지막 블록전에 Feature Map 단에서 부족한 sample 들에 대해서 augmentation을 해줘서 imbalance를 해결한 방법론 정도로 이해했다.
1차 대회 끝나고 사람들이 많은 후기를 올렸고, 나 역시 아쉬움이 꽤나 많이 남았기 때문에 다른 사람들의 아이디어를 여럿 둘러봤다. 가장 인상깊게 본 아이디어는 rank system 이었다. 어찌됐든 0~4로 모델이 예측하게 한다면 이를 기반으로 순위가 생길텐데 Test set의 distribution이 20%씩이라는 걸 아니까 가장 높은 곳에서부터 20%로 잘랐다는 아이디어인데 보고서 '와 이거는 어떻게 보면 꼼수긴한데 Industry에서는 기가 막힌 아이디어겠구나' 라는 생각을 했었다.
1차 대회는 시작할 때 데이터에 대한 잘못된 bias로 망한 상태로 시작했다면 2차 대회는 시작하자마자 데이터부터 한 번 잘 뜯어보고 키포인트를 초기에 잡아서 되게 성공적으로 시작할 수 있었다.
2차 대회 주제는 원래 하려고 했던 Vision 주제가 사라져서 남은 Vision 문제인 Review Quality Assessment와 Landmark Detection를 고를 수 밖에 없었다.
Review Quality Assessment는 네이버 지도 가면 사람들이 장소에 대해서 리뷰를 해놓은 사진을 볼 수 있는데, 해당 사진이 리뷰에 도움이 되는 잘 찍은 사진인지 아니면 그냥 대충 찍거나 메뉴판만 올린 사진인지를 판단하는 문제였다. 이와 관련해서 Naver에서 자체적으로 만든 데이터셋을 제공해주다. 주제 자체가 되게 재밌고 간단해 많은 참가자들이 몰렸다.
Landmark Detection은 내 발표 ppt를 좀 빌리자면
말 그대로 서울시에 있는 Landmark 사진 데이터셋에 대해 해당 사진이 어느 Landmark이고 그 Landmark가 사진 내에 어디 있는 지를 알아내는 문제였다.
처음에는 두 문제를 투트랙으로 돌리다가 하나에 집중하기로 맘 먹고 2번에 올인했다.
2번 문제의 특이사항을 좀 보면 Scene당 object는 1개만 존재한다는 것! 그리고 이미지의 해상도가 높고 Landmark는 건축물이기 때문에 대체로 이미지 내에 물체의 크기가 크다는 점이었다. 그래서 정리를 하자면
그래서 아래와 같이 세팅을 해주었다. 물론 다시한번 Crop을 안 한다는 도박수를 택하긴 했지만 이번에는 실험을 먼저 해보고 Crop 안 하는게 더 좋다는 걸 확인한 후 Crop을 빼기로 결정했다.
여기서 특히 2번 idea가 메인이었는데 0.86의 수치에서 0.9까지 올라가는데 2번이 꽤나 초반 아이디어였는데 이 방식이 유효하게 작동을 해서 Image Resolution을 유지한 게 이번 대회에서 내 1등공신이었다.
이제 모델로 넘어가면 모델은 당시 PaperswithCode SOTA였던 DINO를 사용했고, Backbone은 Swin Transformer를 사용했다. 여기서도 좀 이슈가 있었던게 최대한 Resolution Image 유지하는 방향으로 모델을 선정하려다 보니 Swin Transformer를 제외하고는 죄다 백본에서 메모리가 터져버려서 사용을 못했다.(Swin Transformer는 이미지 해상도에 Linear하게 영향을 받고 나머지는 Quadratic으로 받는다) 해상도를 줄이면 돌아가기는 했지만 해상도를 늘린 Swin Transformer가 가장 실험적으로 성능이 좋았어서 해당 모델을 사용했다.
PostProcessing으로는 Ensemble과 TTA를 사용하려고 했었다. 근데 Ensemble하더니 성능이 떨어지는게 아닌가... 내 세상이 무너지는 기분이었다. 물론 두 모델의 성능이 0.9, 0.86정도로 어느 정도 성능차이가 있기는 했지만 그래도 하나는 CNN 기반, 하나는 Transformer기반이라서 오르면 올랐지 떨어질 줄은 몰랐다. 그래도 TTA는 다행히 얼추 작동을 해서 Horizontal Flipped Image 정도는 활용을 했다. 그리고 Detection Task에서는 Ensemble하는 방법도 다양해서 여러 방법을 사용해보고 WBF를 활용해서 최종 결과를 제출하였다.
이 대회는 쭉 2등을 하다가 마감 3일전에 1등을 따고 마지막날에 점수를 살짝 올렸는데 만약 마지막날에 점수를 올리지 못했다면 2등으로 마감할 뻔할 정도로 아슬아슬한 대회였다.
최종모델: DINO(Swin Transformer) with NMW
진짜 간당간당하게 우승을 할 수 있었고, 지금은 Conference에서 발표까지 다 마무리하고 상금 관련 서류까지 다 제출한 상태다. 정말 24시간 내내 돌아간다라는 시스템이 사람을 피말리게 하는 것 같다. 특히 리더보드, 경쟁에 진심인 K-ENTP인 나로써는 정말 심리적으로 넘모 힘든 2달이었다. 엉엉 그래도 결과가 꽤나 짜릿해서 끝나고 나서 그 해방감과 뿌듯함은 이루 말할 수 없었다. 하하하
특전은 상금 1500만원 + 네이버 동계 인턴 기회 + 네이버 정규 채용 서류&코테 면제(23년까지) 정도인데 인공지능을 평생의 업으로 삼으려면 학사보다 더 높은 학위가 필요할 거라 생각해 연구의 길을 택한 나는 네이버 인턴과 채용은 사용 안할 것 같고 1500만원으로만 만족하려고 한다.
상남자특) 네이버 인턴 거절함
개멋지다...