2022 NC Fellowship 후기

NCF 소개 및 팀 구성 (3 ~ 4월)

NCF는 NC SOFT에서 주최하는 인공지능 인재 육성 프로그램이다. Game AI track과 Neural Graphics track으로 운영되며, 각각에 대하여 참여 가능한 학교 및 동아리에서 2인 1팀으로 최대 2개 팀이 참여하게 된다. 게임의 종류는 매해 달라지며, 초대 대회는 미니 체스를 사용하였고 이후 대회부터는 스타크래프트를 기반으로 진행되었다. 나 같은 경우 기존에 대외 활동이 PS에만 몰려있는 점을 감안하여, 경험삼아 복학에 맞춰 학과 동기와 참가를 해보기로 결심하였다. 또한 19년도에 함께 ICPC를 나갔던 친구가 Game AI track에서 우승한 전력이 있으므로, 동일하게 스타크래프트를 기반으로 한다면 수상도 가능하겠다는 생각도 존재하였다.

하지만 예상과 달리 22년도는 게임의 종류가 NetHack으로 바뀌었고, 처음 생각한 방향과는 다르게 흘러가기 시작했다. 다만, 19년도에 친구가 우승할 당시에도 스타크래프트로 바뀐 첫해였다는 점을 감안하면, 오히려 모두에게 공평한 싸움이 됐다는 생각도 들었다. 따라서 가벼운 마음으로 우선은 참가에 의의를 두고 NCF를 시작하게 되었다.

+) 팀명은 동기가 제안한 이름으로 과거 삼성 육목대회의 팀명이 인상깊었기 때문에 우리도 중의적인 의미의 팀명을 정하고 싶었고, 츄라이를 AI와 덧붙여 적어 ChurAI가 되었다.

5 ~ 8월

해당 기간 동안은 NC SOFT로부터 기본적인 강화 학습에 대한 교육 자료를 제공받아 학습하였다. 강화 학습의 기본이 되는 MDP 부터 Q-Learning, DQN, MCTS, Epsilon-greedy 등 기초적이지만 꼭 필요한 내용에 대해 강의를 들을 수 있었다. 사실 3학년 1학기에 처음으로 인공지능 관련 강의를 학교에서 수강하고 있었기에 강화 학습 내용이 상당히 생소하게 다가왔다. 따라서 본격적으로 프로젝트를 시작하기에 앞서 개념적으로 이해를 하는 것을 목표로 세웠다. 8월에는 본격적으로 Competition을 진행할 학습 환경과 평가 방식에 대한 안내가 전달되었고, 중간 계획 발표를 해야 했다. 하지만 공교롭게도 발표 당일에 나와 팀원 모두 일정이 존재하였고, 단순히 계획 PPT를 전달하는 것으로 끝을 냈다. (사실 이날 어느 정도 대회 진행 방향성에 대한 공지가 이루어진 듯하지만, 나중에 큰 영향을 끼치진 않았다.)

9 ~ 12월초

이 기간 동안은 사실 학업과 ICPC 준비로 굉장히 바쁜 시기였다. 대회 주최 측에서도 학기 중에 학생들이 참여하기는 어려울 듯하고 방학 때 열심히 해주길 바란다는 말을 들은 만큼, 이 기간에는 NCF 관련해서는 공지 사항을 확인하고 어떤 변동 사항이 생겼는지만 주로 신경 썼던 것 같다.

12월말 ~ 2월초 (마무리)

3학년 2학기가 종강하고, 이젠 2월에 최종 프로젝트 제출이 남은 만큼 본격적으로 개발을 시작해야 할 시기가 다가왔다. 사실 이미 NC로부터 동아리 후원금 명목으로 100만원을 지원받은 상태였고, 참여가 미비할 경우 반납이 가능하다는 것을 알게 된 이후부터는 반납만은 막자는 마인드가 어느 정도 있었다. 여기서부터는 달별로 진행 방향과 결과를 적어보려고 한다.

12월

강화 학습이 어떤 것인지 개념적으론 알겠지만, 이를 코드로 짜서 AI를 제출하라니 굉장히 막막한 상황이었다. 사실 이전에 대회를 우승한 친구도 그렇고, 전년도 우승팀의 인터뷰에서도 들었듯이 AI 모델을 잘 바꾸는 것보다 휴리스틱한 rule-base를 얼마나 잘 만드냐가 결국 승패를 좌우하는 것으로 파악하였다. 따라서 우리가 할 수 있는 부분에서 최선을 다해보자는 생각으로 rule-base를 잘 만드는 쪽으로 전략을 세웠다. 이를 위해서는 게임을 먼저 이해하는 것이 중요했으므로, 일주일가량 해당 게임만 플레이하며 시간을 보냈다.

게임 파악을 마친 이후에는 기본적인 환경 세팅을 진행하였다. GPU가 나와 팀원 모두 없는 관계로 Google Colab 환경을 사용하기로 하였고, 백그라운드 실행이 필요할 듯하여 Colab Pro+를 구독하였다. Colab 기반 환경 세팅이 설명이 없었기 때문에 이 과정에서 2 ~ 3일은 소모한 듯 하다. 환경이 어찌저찌 세팅된 이후에는 NC에서 제공받은 예제 코드를 실행시켜 보았다. 근데 문제는 모델의 입력이 서로 안 맞는다는 것이었다. 모델은 길이 26짜리 벡터를 받지만, environment는 어째서인지 27짜리 벡터를 주는 것이었다. 코드를 살짝 고치니 잘 실행이 되었고, 코드에 오류가 있었던 것으로 잠정 결론을 내린 뒤 프로젝트를 진행하였다. (사실 이 부분은 마지막에 큰 반전을 맞이한다.)

1월

환경 세팅을 마친 상태에서 최종 점검 미팅을 진행하였고, 이 미팅에서 최종 방향성을 전달받았다. 기존에는 NetHack Challenge로 평가를 할 예정이었으나, 너무 문제의 난이도가 높은 관계로 NetHack Score를 기준으로 평가를 할 계획이며 action space를 사용자가 직접 자유롭게 수정할 수 있다는 안내를 받았다. 해당 공지를 들은 이후에 소감은 오히려 지난 기간 동안 별다른 작업을 하지 않은 것이 나쁘지 않은 선택이었다는 생각이었다. 최종 평가 방식이 결정되었으니, 이에 맞춰 모델을 수정하자고 생각하였고 주최 측에서 제공한 Example 10을 기반으로 최종 제출본을 만드는 것으로 방향을 잡았다.

주최 측에서는 action space 확장이 되는 코드를 추후에 제공해 주겠다고 했지만, 이를 기다리기엔 시간이 부족할 듯해서 직접 NLE 코드를 뜯어서 수정을 진행하였고, 확장된 action space에서의 모델 학습을 시킬 수 있었다. 또한 이 과정에서 reward function 부분 또한 수정하는 방법도 찾아낼 수 있었다. 다만 이 과정에서도 많은 삽질이 존재하였는데, 기반이 된 Example 10의 동작 방식을 잘못 파악하여 agent가 음식을 먹는 것 또한 neural net에 기반하여 작동한다고 생각한 것이었다. 잘못된 이해로 약 일주일간 자원 낭비를 좀 하였고, 이 기간 동안 모델의 성능이 260점 내외로 변화가 없는 것을 보고 쉽지 않은 과제라는 생각을 하였다.

코드 파악을 제대로 한 이후에는 어디를 rule-base로 가져가는지 알 수 있었고, 문제가 되는 부분을 해결할 수 있었다. 이 부분을 해결하니 점수가 400점대로 올라갔고, 모델을 학습시키면서 플레이 영상을 다시 보고 버그를 수정하는 식으로 꾸준히 개선 작업을 진행하였다. 그 결과 700점대까지 점수를 올릴 수 있었다. 이후에는 추가로 필요한 action들을 찾아 rule-base에 추가하였고, neural net의 output을 수정하는 식의 작업을 조금 거쳐 평균 900점대의 성능까지 높였다. 이맘때쯤 대회 측에서 평가용 코드를 제공해 주었고, 매일 매일 다른 팀들의 제출본과 비교하여 성능을 공개해 주었다.

2월 초 (마무리)

첫 평가를 받은 결과 여러 이유로 코드가 제대로 실행되지 않아 0점대 점수가 나왔다. 이는 action space 확장 방식과 관련된 부분의 문제였고, 주최 측과 2~3일간 의견을 주고받으며 올바르게 수정할 수 있었다. 올바르게 실행된 결과는 1등이었고, 다만 이상한 점은 로컬에서 실행시킨 결과물보다 점수가 200 ~ 300점가량 낮게 나왔다는 것이었다. 또한 프로그램의 실행시간도 굉장히 길게 나오는 문제가 있었다. 아마 action에 random성이 존재하기 때문에 그럴 것이라 잠정 결론 내고 지속해서 마이너한 fine-tuning을 진행하였다. 중간중간 다른 팀이 우리 팀을 역전하는 경우도 존재하였지만, 전반적으로는 1등을 꾸준히 가져가고 있었고 이 상태를 유지하면서 끝까지 달리면 우승도 가능하겠다는 생각이 들었다.

평가가 막바지에 다다랐을 무렵 많은 팀이 우리 팀의 점수에 육박하는 점수대를 보였고, 여전히 우리 팀은 로컬 실행보다 200점가량 낮은 점수로 평가가 되고 있었다. 이에 위기를 느꼈고 뭔가 평가 환경과 로컬 환경의 차이가 존재한다는 생각을 하였다. 원인은 예상한 대로 NLE 버전의 문제였다. 예제가 작성될 당시에는 0.8.1 버전이었지만, 우리가 환경을 세팅한 12월경에 0.9.0으로 버전이 올라간 것이었다. 그 과정에서 처음 말한 벡터의 길이가 1이 커졌고, 따라서 모델이 돌아가지 않았던 것이다. 지금까지 학습을 0.9.0을 기준으로 진행한 만큼, 지금까지의 모든 중간 평가 결과가 알고 보니 random agent + 휴리스틱의 결과물이었던 것이었지만 점수가 800점대 정도로 나쁘지 않았으므로 눈치를 채지 못하였다. 당시에 마감이 하루 앞으로 다가왔으므로, 평가 환경을 우리만 다르게 하는 것도 형평성에 어긋나므로 최대한 현재의 모델을 살려내는 방법을 찾아내야만 했다. 모델의 성능 자체가 우승권에 가까웠기 때문에 이를 살려내기만 하면 승부를 볼 수 있다고 생각하였고, 입력층을 약간 수정해 주는 방식을 적용하여 NLE 호환성 문제를 해결하여 최종 제출을 무사히 마무리 지었다.

최종 결과

최종 평가는 총 300개의 에피소드에 대한 평균 점수로 진행되었고, 100개의 에피소드로 진행되는 중간 평가가 24시간 정도가 걸린 것으로 생각할 때 3일 정도를 기다려야 했다. 의도하지 않았지만, 우리 팀은 전력을 숨긴 꼴이 되었고, 다른 팀도 의도적으로 전력을 숨겼을 가능성도 있었기 때문에 최종 등수가 어떻게 될지 궁금한 상태로 결과를 기다리고 있었다. 그렇게 최종 결과가 중간 평가와 마찬가지로 Github에 공지되었고, 결과는 평균 1100점, 에러율 0%로 1등을 차지하였다. 평균, 중앙값, 에러율 모든 면에서 다른 팀보다 좋은 결과를 냈기 때문에 2달간의 노력이 헛되지 않았다는 사실에 안도의 한숨을 쉴 수 있었다. 처음에는 가볍게 참가에 의의를 두는 방향으로 시작했지만 최종적으로 우승이라는 결과와 상금 700만원 그리고 하계 인턴십 기회까지 좋은 혜택을 받을 수 있게 되었다.

사실 PS 이외에 눈에 띌만한 실적을 거둔 것은 이번이 처음이다. 지난해 ICPC 수상 이후 새로운 강화 학습이란 분야에서도 작은 규모의 대회였지만 좋은 결과를 얻게 되어 상당히 유의미한 경험이라 생각한다. 무엇보다 기존에 늘 해오던 것에서 벗어나 새로운 분야에 도전해 본 경험이 설령 본 대회를 우승하지 못하였더라도 귀중한 경험으로 남았을 것 같다. 시상식을 통해 들었을 때는 내년에는 진행 방식과 참가 대상에 변동이 생길 것이라 들었는데, 만약 우리 동아리에서 여전히 참여가 가능하다면 모두에게 한 번쯤 참여해 보는 것을 추천해 주고 싶다.