개발/기타

드디어 스와이프 벽돌깨기 AI를 만들어 보았다

Syphon 2023. 2. 2. 00:52

이전 글: 갑자기 스와이프 벽돌깨기 레플리카를 만들어 보았다

 

갑자기 스와이프 벽돌깨기 레플리카를 만들어 보았다

제목 그대로이다. 나도 왜 만들었는지는 잘 모르겠지만 아무튼 만들어버려서, 앞으로 이걸 플레이하는 AI를 강화학습 또는 유전 알고리즘으로 학습시켜볼까 한다. github.com/SyphonArch/brick_breaker GitH

syphon.tistory.com

Github Repository

 

GitHub - SyphonArch/brick_breaker: This project features a clone of a popular 'brick breaker' game variant, characterised by sho

This project features a clone of a popular 'brick breaker' game variant, characterised by shooting a volley of 'balls' at an angle of choice. Along with the game is an AI implementa...

github.com

음.. 일단 사진 첨부.

색상을 조금 튜닝했다.

개요

군 입대를 앞두고 있던 2021년 1월의 나는... 갑자기 스와이프 벽돌깨기를 Pygame으로 구현했었다.

 

게임을 완성한 이후, AI를 만들어보자! 라는 결심을 했지만, 그 누구도 시키지 않았고 이걸 해야 할 이유가 하나도 없었기에 나도 내가 이 프로젝트를 마무리하러 다시 올 줄은 몰랐다.

 

그냥 두기에 뭔가 찝찝해서 한달간 삽질해서 결과물을 내 보았다.

시도 1: 유전 알고리즘

게임 상태를 입력으로 넣으면, 최적의 발사각을 출력해주는 신경망을 얻고 싶었다.

 

그래서 무식하게 유전 알고리즘을 돌려보았다.

게임 스코어가 높은 신경망을 뽑아 돌연변이와 염색체 교차를 섞어 복제하는 방식이다.

 

안될 줄은 알았지만... 독일 여행을 가 있는 10일 내내 32코어 CPU로 열심히 돌렸기에 살짝 기대는 했었다.

스코어 70정도에서 왔다갔다하며 성능이 더 좋아지지를 않는다.

(이정도 스코어는 단순히 발사각을 최대한 낮게 함으로서 달성 가능하다.)

 

지도학습을 전혀 쓰지 않는 방식은.. 힘들 것 같다는 생각이 들었다.

시도 2: 시뮬레이션 + Evaluator/Explorer

유전 알고리즘 시도의 결과가 시원찮음을 보고 고민을 하던 중... 어느 날 이런 생각이 났다:

만약 게임 상태가 얼마나 좋거나 나쁜지 평가해줄 수 있는 evaluator 신경망이 있다고 가정하자. 여기에 무식하게 모든 각도를 시뮬레이션해보는 explorer 코드를 결합하면... 어떤 각도로 쏘았을 때, 결과물이 제일 좋은지 고를 수 있다. 즉 AI를 돌릴 수 있다. 어 그럼... 이렇게 AI를 돌린 게임 기록을 기반으로 evaluator를 다시 학습시킨다면..?!

 

무조건 될 것이라는 확신이 들었다. 이 과정을 반복할수록 evaluator 성능은 매우 빠르게 좋아질 것이라는 느낌이 들었다.

게임 기록에서, 각 게임 상태가 게임 오버 상태로부터 몇 수 전인지를 라벨로 삼아 다음 세대의 evaluator를 학습시키기로 했다.

최초의 0 세대 evaluator만 존재하면 되는데, 이는 그냥 랜덤하게 초기화한 신경망을 사용하기로 했다.

 

그리고 실제로 정말 잘 되었다.

1200판의 게임을 돌렸고, 1세대 evaluator 학습을 위해 1000판을 train data, 100판씩을 각각 test와 validation data로 두었다.

신경망 architecture는 그냥 fully connected relu에 hidden layer 2개를 두었다. Dropout을 사용했다.

학습 결과의 평가를 위한 metric을 따로 정의하기 어려워서(귀찮아서), 위와 같이 라벨링된 ground truth (i.e. $\log t$, t는 게임 오버까지 남은 수)에 대해 신경망의 prediction이 얼마나 선형적인지를 눈대중으로 보았다. 빨간 선($y=x$)과 일치하면 완벽한 신경망이다.

 

대~충 학습시켜서 대~충 적용시켰는데 게임을 너무 잘하더라.

거의 모든 차례에서, 남은 벽돌이 하나도 없게 완벽한 플레이를 해버린다.

 

1세대 evaluator를 돌려서 2세대를 만드는 작업을 할 수 없게 되었다.

게임이 끝나지를 않는다.

시도 2.5: 하드코딩

시뮬레이션을 돌려서 각 각도로 쏘는 결과를 계산하는 방식이 너무 사기인 것 같아서, 신경망 대신 그냥 내가 하드코딩한 가중치 행렬을 이용해 evaluator를 만들어보기로 했다. 두 결과를 비교해보기 위함이다.

 

벽돌이 아래에 있을수록 더 큰 가중치를 두었고, 초록색 점수를 먹어 공이 더 많아지는 경우에도 인센티브를 주었다.

 

... 이렇게 하드코딩한 AI가 앞에서 학습시킨 AI보다 더 잘한다.

먼저의 학습시킨 AI는 초록 점수를 먹어야 좋다는 것을 잘 학습하지 못해서 게임 초반에 살짝 불안정한 모습을 보인다.

(적은 개수의 공으로 계속 플레이를 함.)

내가 하드코딩한 친구는 그런 것 없다... ㅎ

결론

어이가 없다.

 

일단 잘 동작하는 AI를 만들긴 했다.

또, 이 AI를 게임 도중 활성화시켜 AI의 도움을 받을 수 있는 AI Assist 기능도 추가하였다.

 

그런데 결국 만들게 된 AI가, 각도를 n등분해 각 결과를 직접 계산해버리는 그 계산력 자체에 가장 크게 의존한다는 것이 판명이 났다. Evaluator 성능은 크게 중요하지 않고, 시뮬레이션을 쓰는 explorer 방식의 AI 자체가 성능이 압도적인 것이다. 내가 그냥 하드코딩하고 한번도 수정하지 않은 가중치 행렬로 evaluator를 돌려도, 학습된 evaluator보다 AI 성능이 좋다.

 

즉, 각도마다 공을 쏘아보고, 그 결과를 보고 벽돌이 몇개인지(가중치를 취해) 봐서, 각도를 고르는 단순한 방식으로 마무리가 되었다.

 

이 플젝에 왜이리 많은 시간을 썼을까.

 

진짜 결론:

1. 그냥 계산 가능한 문제에 이상한 AI 결합시키려 하지 말자

2. AI 할거면 아무데나 유전 알고리즘 결합해서 기적을 바라지 말고... 강화학습 공부부터 제대로 해보자