다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 지난해 9월 '블소 토너먼트 월드 챔피언십'에선 AI에 프로게이머들이 고전을 하는 장면이 펼쳐졌다 (사진: 게임메카 촬영)

작년 9월, '블레이드앤소울(이하 블소)' 글로벌 e스포츠 대회인 '블소 토너먼트 월드 챔피언십' 결선에선 꽤나 충격적인 일이 벌어졌다. 내로라하는 프로게이머들이 의문의 유저에게 참패를 당한 사건이다. 특히 한국선수와의 경기에선 전에 보지 못한 빠른 공격을 바탕으로 적을 압도하는 모습을 보여줬다. 경기가 끝나고 나서야 밝혀진 이 고수의 정체는 엔씨소프트가 개발한 비무 전용 AI였다.

'블소' PvP 콘텐츠에 적용될 이 인공지능은 딥러닝을 적용한 심층강화학습 기술로 스스로 다양한 전투법을 몸에 익힌 똑똑한 친구다. 알파고나 알파스타같은 지능 위주 게임이 아닌 수십 분의 일 초 단위 판단이 필요한 MMORPG PvP 모드에서 딥러닝 AI가 적용된 사례는 굉장히 드물다. 이 AI는 어떤 방식으로 학습했길래 프로게이머와 겨룰 수준의 실력을 갖게 됐을까? 이번 GDC 현장에서 엔씨소프트 강화학습 팀 정지년 팀장과 노승은 연구원이 발표한 <강화학습을 이용한 프로게이머 수준의 '블소' 비무 AI 개발> 강의에서 그 방법을 구체적으로 들을 수 있었다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ '강화학습을 이용한 블소 AI 만들기'라는 주제의 강연이 GDC 2019에서 열렸다 (사진: 게임메카 촬영)

인공지능이 게임 시스템을 이해하는 것부터 차근차근

AI에게 프로게이머 수준의 경기력을 지니게 하기 위해선 일단 스킬 시스템을 이해시키는 것이 제일 중요했다. 군중 제어기와 대미지 딜링용 스킬을 연계해서 쓸 수 있게 하고 회피와 반격을 위해 적절한 타이밍과 거리를 재도록 해야 했다. 더불어 각 스킬이 가진 상성을 이해시키고 어떤 움직임이 제일 효율적인지를 체크할 수 있도록 만들 일련의 과정이 필요했다.

이를 위해선 몇 가지 과제를 수행해야만 했다. 첫 번째는 복잡성을 줄이는 과정이다. '블소'에서 한 번 전투가 벌어질 때 발생하는 경우의 수는 바둑의 몇백 배는 될 정도로 복잡하다. 덕분에 딥러닝을 통해서 AI가 배워야 할 것도 기하 급수적으로 늘어난다. 이를 줄이기 위해 정지년 팀장은 활동 공간을 눈에 띄게 줄이는 방향으로 갔다. AI로 하여금 불펼요한 움직임은 처음부터 하지 않도록 가르친 것이다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 엔씨소프트 강화학습팀 정지년 팀장이 각종 기술을 설명하고 있다 (사진: 게임메카 촬영)

두 번째는 실시간 반응이었다. 행동 하나하나에서 뻗어나올 경우의 수를 모두 계산한다면 유저의 공격에 실시간으로 반응하는 것이 불가능 할 것이다. 이를 위해 제작지는 인공신경망 네트워크를 사용했다. 비슷한 상황을 계속해서 제공함으로써 먼 미래의 결과 예측보다는 그때 그때의 효율적인 움직임을 추구할 수 있도록 구성했다.

이 실시간 반응과 함께 고려되어야 하는 것이 바로 추상화 작업이었다. 사람마다 다른 패턴을 스스로 분석하고 일반화 시켜 상황에 따른 답안을 내놓을 수 있도록 추가적인 훈련이 필요했다. 이를 위해서 다양한 프로 선수들의 경기를 반복적으로 학습하게 만들었다. 수없이 많은 움직임 중에서도 가장 모범적인 움직임들을 보고 일반화 과정을 이해하는데 성공했다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 이번 연구의 목표는 프로게이머 레벨의 AI를 제작하는 것이다 (사진제공: 엔씨소프트)

보상을 이용해 본격적인 싸움 법을 알려주기

마지막으로 AI가 보다 기민하면서도 다채로운 움직임을 보여주기 위해선 다양한 방식의 전투법을 익혀야 했다. 각각 공격적인 형태와 방어적인 싸움법, 공수를 골고루 사용하는 스타일을 자유자재로 구사하는 것이 필요했다. 연구팀은 이를 위해서 '보상을 통한 강화학습'을 선택했다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 노승은 연구원이 강화학습에 대해서 구체적으로 설명하고 있다 (사진: 게임메카 촬영)

보상을 통한 강화학습은 행동하는 법을 직접적으로 알려주는 것이 아니라, 맞는 행동을 했을 때는 일정한 보상을 주고 맞지 않은 행동을 했을 때는 불이익을 줘 스스로 계속 보상을 따라서 맞는 행동을 찾아가게 만드는 시스템이다. 아이가 걸음마를 익히는 과정을 연상하면 쉽다. 아이가 한발짝씩 제대로 걸을 때는 제대로 걷는다는 보상이 있지만 넘어지면 그 보상이 다 날아가게 된다. 결국 아이는 더 많은 보상을 위해 스스로 걷는 방법을 터득해나간다.

연구팀이 AI에게 설정한 기본적인 보상은 승리와 더 많은 HP였다. 쉽게 말해 더 큰 HP 차이를 유지한 채 이기면 더 큰 보상을 얻고 반대의 경우는 보상을 얻지 못하는 것이다. 더불어 스타일에 따라 거리 패널티, 공격 연계의 딜레이, 자신과 적 사이의 HP 비율 등으로 시작 조건을 다르게 구성해 상황에 맞는 전술을 구사하도록 학습 과정을 설정했다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 아이가 걸음마를 익히는 과정이 보상을 통한 자기 학습의 원류라고 볼 수 있다 (사진제공: 엔씨소프트)

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ AI에게 제공되는 기본적인 보상은 '승리'와 HP 차이다 (사진제공 : 엔씨소프트)

이후에는 자기자신을 상대로 반복적인 대련을 하며 최상의 보상을 찾아 스스로 연구하는 기회를 지속적으로 제공했다. 163시간을 훈련한 AI가 3시간, 142시간, 87시간 훈련한 AI와 지속적으로 대련하며 학습을 거쳤다. 딥러닝이 적용되지 않은 AI를 상대로 5시간 만에 승률 100%를 달성할 정도로 학습 속도는 빠른 편이었다. 이후에는 사람과 직접 맞붙으며 다른 방식을 학습했다. 특히, 사람과의 대련이 지속될 수록 AI 맹점이 하나 둘 드러났기 때문에 이를 보완하기 위해 다양한 선수들과 대련을 펼쳤다. 

결과적으로 프로게이머와의 공식적인 전적에서 공격적 스타일의 경우 92% 승률, 밸런스 타입은 42%, 방어형 AI는 50% 승률이라는 준수한 성적을 보였다. 보상을 통한 강화학습이 효과적으로 작용함을 입증한 것이다.

▲ 지난 9월에 있었던 블라인드 매치 전경기 (영상출처: OGN 유튜브)

유저들에게 그 자체로 새로운 콘텐츠가 될 수 있는 연구

AI가 실제 사람처럼 움직이면서도 프로게이머 못지 않은 실력을 지니고 있다면 이는 그 자체로 훌륭한 콘텐츠가 될 수 있다. 더불어 그동안 나왔던 연습용 더미보다 훨씬 좋은 연습상대가 되어줄 것이다.

물론, 앞에서 이야기했듯이 보상을 이용한 강화학습도 완벽한 것은 아니다. 인간과 오랜시간 대련하다 보면 약점이 드러난다는 점에서 알 수 있다. 다만, 그 과정을 스스로 깨우치는 AI가 제대로 개발된다면, 머지 않아 진짜 프로게이머 수준의 AI가 유저의 연습상대가 되어줄지도 모를 일이다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
▲ 한 청자가 연구진에게 기술에 대해 상세히 질문하고 있다 (사진: 게임메카 촬영)

Copyright ⓒ 게임메카. 무단전재 및 재배포 금지

안녕하세요, 프로메디우스 인턴사원 간정현입니다. 이번 포스팅에서는 YOLO와 다크넷 프레임워크를 간단히 소개하고, 다크넷 사용 후기를 공유하려고 합니다. 부족한 글이지만 재밌게 봐주시면 감사하겠습니다!

You Only Look Once 😎

Overview

YOLO(You Only Look Once)는 빠른 추론 속도와 상당한 정확도를 자랑하는 오브젝트 디텍션 모델입니다. 오브젝트 디텍션은 객체의 위치와 크기를 예측하는 문제와 해당 객체의 클래스를 분류하는 문제로 세분화할 수 있습니다. 모델에 따라서 이 두 가지 문제를 한번에 처리하기도 하고, 두 단계로 나누어 처리하기도 합니다. YOLO는 이름에서 알 수 있듯이 하나의 네트워크에서 객체의 위치와 크기, 클래스를 동시에 예측하는 방식을 채택합니다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
Source: YOLOv4: Optimal Speed and Accuracy of Object Detectionv

YOLO의 아이덴티티는 실시간 수준의 빠른 예측 속도를 유지하면서도 꽤 정확한 예측을 내놓는다는 점에 있습니다. 일반적으로 위치 예측과 클래스 분류를 한꺼번에 수행하는 간결한 파이프라인을 채택할 경우 예측 속도 면에서는 유리하지만 정확도 면에서는 불리합니다. YOLO 역시 정확도만 놓고 보면 가장 뛰어난 모델이라고는 할 수 없습니다. 하지만 추론 속도를 함께 고려하면 상황이 달라집니다. 위 그림처럼 실시간 수준의 추론 속도를 가진 모델들 중 YOLOv4는 압도적인 성능을 보입니다.

YOLOv1: outputs

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
YOLO CVPR 2016 slides

YOLOv1을 통해서 모델의 학습 과정을 조금 살펴봅시다. 위 그림은 네트워크의 아웃풋을 나타낸 것입니다. 아웃풋이 만들어지는 과정을 보다 구체적으로 살펴보면 아래와 같습니다.

  • 이미지를 S x S의 그리드로 나눕니다.
  • 각 그리드 셀은 B 개의 바운딩 박스를 예측합니다.
  • 각 그리드 셀은 바운딩 박스와 무관하게 C 개의 클래스 확률을 예측합니다.
  • 각 바운딩 박스는 클래스와 무관하게 객체의 존재 여부(confidence), 위치(x,y), 크기(w,h)를 예측합니다
  • 따라서 모델의 아웃풋은 (S, S, B x 5 + C)의 텐서가 됩니다(바운딩 박스의 갯수만을 따지면 S x S x B 가 됩니다).
  • 논문에서는 S=7, B=2를 사용하였습니다. 즉 클래스가 20개인 데이터셋에 대해서 위 그림처럼 (7, 7, 30) 크기의 텐서를 출력합니다.
  • 훈련 이후 실제 예측시에는 non-maximal surpression 을 적용합니다.

confidence 의 정답은 실제 바운딩 박스와 예측된 바운딩 박스의 IOU 값으로 정해집니다. 특이하게도 정답을 결정하는데 예측치가 관여하는 것입니다! 디텍션 분야를 처음 접한 입장에서는 정답을 결정하는데 예측치가 관여할 수 있다는 컨셉이 굉장히 당황스러웠고 헷갈렸습니다. 여기서는 당황하지 말고 천천히 살펴봅시다!

논문에서는 모델이 내놓는 confidence 점수를 Pr(Object) x IOU로 정의합니다. 예측된 박스 안에 객체가 존재하지 않는다면, 이상적인 모델에서는 Pr(Object)가 0이 되어  confidence 역시 0이 되어야 합니다. 반대로 예측된 박스 안에 객체가 존재한다면, 이상적인 모델에서는 Pr(Object)가 1이 되어  confidence 는 IOU와 같아져야 합니다. 이러한 성질로 인해서 연구자들은 confidence 점수와 IOU를 예측치-정답의 쌍처럼 사용할 수 있다고 판단한 것 같네요!

YOLOv1: loss

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
You Only Look Once: Unified, Real-Time Object Detection

위 수식은 YOLOv1의 로스 함수입니다. 😈 무시무시하게 생겼지만 사실 자세히 뜯어보면 그렇게까지 험악한 친구는 아닙니다 😇 기본적으로 좌표, 크기, 컨피던스, 클래스 확률의 평균제곱오차를 계산한 후 모두 더하는 구조로 되어있습니다. 여기에서 로스의 모든 디테일을 리뷰할 수는 없으니 "responsible" 의 개념에 대해서만 짚고 넘어가려 합니다.

(p.2) If the center of an object falls into a grid cell, that grid cell is responsible for detecting that object.

(p.3) At training time we only want one bounding box predictor to be responsible for each object. We assign one predictor to be “responsible” for predicting an object based on which prediction has the highest current IOU with the ground truth.

위 인용을 보면 "responsible" 이라는 개념은 그리드 셀에 대해서도, 바운딩 박스에 대해서도 쓰입니다. 하지만 로스의 관점에서 "responsible" 은 결국 바운딩 박스에 대한 개념으로 생각하면 됩니다. 즉 하나의 물체에 대한 예측을 책임지는 유일한 바운딩 박스를 결정하는 문제입니다. 수식을 보면예측에 대해 "responsible" 하지 않은 박스의 좌표 크기 로스 텀은 0이 되는 것을 알 수 있습니다. 즉 책임이 없는 박스들에 대해서는 좌표와 크기의 로스를 면제해주자는 아이디어입니다. 천천히 따져봅시다!

먼저그리드 셀의 단위에서는 해당 셀이 어떤 물체의 중심을 포함하는 경우 그 물체의 탐지에 대해 "responsible"하다고 합니다.하지만 모델의 구조상 하나의 그리드 셀은 여러 개의 바운딩 박스를 예측하게 됩니다. 하나의 물체에 대해 정확히 하나의 바운딩 박스를 대응시키기 위해 바운딩 박스에 대해서도 "responsible" 의 조건을 정의해야 합니다. 바운딩 박스에 대해서는, 물체에 대해 가장 높은 IOU를 갖는 박스를 물체에 대해 "responsible" 하다고 정합니다. 정리하면, 어떤 물체의 중심을 포함하는 셀에서 예측된 바운딩 박스 중 실제 바운딩 박스와 가장 큰 IOU를 갖는 박스를 그 물체에 대해 "responsible" 하다고 말합니다.

Darknet

다크넷은 Joseph Redmon이 YOLO 학습을 위해 개발한 프레임워크입니다. 하지만 대부분의 사용자들은 YOLOv4의 저자인 Alexey Bochkovskiy의 버전을 사용하는 듯 하고, 업데이트도 포크 버전에서 더욱 활발하게 이루어지는 것 같습니다. 저 역시 포크 버전을 사용했는데, 개인적으로는 프레임워크 전반에 대한 문서와 설명이 오리지널 웹사이트보다 훨씬 상세하다고 느꼈습니다. 저뿐만 아니라 다른 분들도 다양한 이유로 오리지널 버전보다는 Alexey 버전을 선호하시는 것 같습니다!

데이터셋 제작

<object-class> <x> <y> <width> <height>
다크넷 라벨 데이터 형식

모델을 만들기 위해서는 우선 데이터가 있어야겠죠? 다크넷 학습을 위해서는 이미지와 라벨의 쌍으로 이루어진 데이터셋이 필요합니다. 저는 흉부 X-ray 사진에서 L 자 마커를 찾아내는 모델을 학습시키기 위해 사내 데이터 2,200장, 오픈 데이터 200장을 직접 레이블링했습니다. 레이블링 작업은 정말 힘들고 괴롭지만 마치고 나면 묘한 성취감이 느껴져요 😄

레이블링 작업에는  Yolo_label이라는 툴을 사용했습니다. 이 툴의 장점은 다크넷의 라벨 데이터 형식을 그대로 따르기 때문에 만들어진 데이터를 별도의 전처리 없이 즉시 다크넷에 주입할 수 있다는 것입니다. 또한 드래그 & 드롭 방식이 아닌 클릭 & 클릭 방식을 사용해서 손목의 부담도 확실히 덜합니다. 사실 예전에도 3개월 정도 자율주행을 위한 데이터를 레이블링해본 적이 있는데, 그 당시 사용한 툴과는 비교도 되지 않을만큼 편했습니다. 직접 다크넷에 들어갈 데이터를 제작해야하는 상황이 또다시 생기면 고민 없이 사용할 것 같네요!

학습 준비

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna

자신의 데이터셋으로 다크넷 모델을 훈련시키려면 다크넷 깃허브의 How to train (to detect your custom objects) 파트에 설명된대로 몇 가지 준비가 더 필요합니다.  개인적으로는 이 과정이 헷갈려서 제 방식대로 다시 정리를 해봤습니다. 편의를 위해 그림과 같이 meta, images 디렉토리를 생성하고, 제작한 데이터셋은 images 디렉토리에 넣어두었다고 가정하겠습니다.

meta 디렉토리 아래에는 훈련과 검증에 사용할 데이터의 목록을 작성합니다. 예를 들어 1번부터 80번 이미지를 학습용으로, 81번부터 100번 이미지를 검증용으로 사용한다면 아래와 같이 두 개의 txt 파일을 작성하면 됩니다.

images/img1.png
images/img2.png
...
images/img80.png
meta/train.txt
images/img81.png
images/img82.png
...
images/img100.png
meta/valid.txt

cfg 디렉토리에는 data, names, cfg 파일이 들어갑니다. data 파일에는 학습에 사용할 데이터와 백업 디렉토리를 정의하고, names 파일에는 데이터셋에 포함된 클래스들의 이름을 작성하면 됩니다. 예를 들어 클래스가 세 개인 데이터셋을 학습한다면 아래와 같이 작성합니다.

classes=3 # 클래스 갯수
names=cfg/cxr.names # 클래스 이름
train=meta/train.txt # 훈련용 이미지 파일 목록
valid=meta/valid.txt # 검증용 이미지 파일 목록
backup=backup # 훈련 중 가중치 백업 디렉토리
cfg/example.data
ClassName0
ClassName1
ClassName2
cfg/example.names

YOLO의 각 버전에는 대응하는 다크넷 cfg 파일이 존재합니다. cfg 파일은 네트워크 구조와 학습 하이퍼파라미터를 결정합니다. 원하는 버전의 설정파일을 선택한 후 사전 학습된 가중치를 다운받습니다. 물론 밑바닥부터 모델을 학습시키는 것이 불가능하지는 않지만, 이미 잘 만들어진 가중치를 굳이 활용하지 않을 이유는 없는 듯 합니다. cfg 파일과 가중치를 선택했다면 자신의 데이터에 맞게 cfg 파일을 수정합니다. 일반적으로 아래와 같은 파라미터를 조정합니다. 더욱 자세한 조정을 원하시면 깃허브 위키를 참고해주세요!

섹션파라미터설명
[convolution] filters 컨볼루션 필터 갯수 (5 + 클래스 수) * 3
[yolo] classes 클래스 수 클래스 수
[net] batch 배치 사이즈 -
[net] subdivisions 미니배치 갯수 -
[net] max_batches 최대 훈련 배치 갯수 클래스 갯수 * 2000
[net] steps 학습률 조정 시점 max_batches 값의 80%,90%

학습

이제 모델을 학습시킬 준비가 모두 끝났습니다 😆 번거로운 준비과정에 비해서 학습과 성능 평가, 예측은 train, map, test 등의 간단한 커맨드만으로 수행할 수 있습니다. 조금 번거로운 준비 과정을 거쳐야 하지만 절차만 잘 지킨다면 누구나 쉽게 사용할 수 있다는 점이 다크넷의 매력인 것 같습니다!

저는 사내 데이터 2,000장으로 YOLOv3의 학습과 검증을 진행한 후 사내 데이터 200장과 오픈 데이터 200장에 대해서 각각 mAP를 테스트해보았습니다. 테스트 결과 사내 데이터에 대한 성능은 0.9998로 꽤 높았지만 오픈 데이터에 대한 성능은 0.2020 정도로 매우 낮았습니다 😞 나름대로 이런저런 augmentation을 적용해서 성능을 끌어올린 결과인데, 생각보다 훈련 데이터에 오버피팅이 많이 되어있는 듯 합니다. 역시 시간이 허락하는 한 가장 좋은 방법은 더욱 다양한 데이터를 만드는 것인가봅니다. 아래 사진은 오픈 데이터에 대한 테스트 수행 결과입니다.

다크넷은 어떻게 만들어졌나 - dakeunes-eun eotteohge mandeul-eojyeossna
오픈 데이터셋에 대한 예측 결과

Wrap up

다크넷을 간단하게 사용해본 소감은 "귀찮지만 쉽다(혹은 쉽지만 귀찮다)" 입니다. 제 생각에 다크넷은 고난도의 태스크를 해결하기 위한 전문적 도구라기보다는 쉬운 난이도의 태스크를 해결하기 위한 범용적 도구인 것 같습니다 (YOLO의 가장 큰 장점으로 꼽히는 속도에 대해서는 사실 다른 모델을 사용해본 적이 없어서 뭐라고 말씀은 드리지 못하겠네요😅).

다크넷은 정말 쉽습니다. 다크넷의 학습 과정은 YOLO와 C에 대한 지식을 거의 요구하지 않습니다. 다크넷은 모델의 구조와 사전 훈련된 가중치를 모두 제공하기 때문에 사용자는 자신의 데이터를 준비한 후 훈련에 필요한 파일들을 만들고 수정하기만 하면 됩니다. 이 과정이 조금 번거롭기는 하지만, 가이드 문서에 설명이 상세하게 되어있기 때문에 인내심을 가지고 따라한다면 누구나 나쁘지 않은 성능을 가진 모델을 만들 수 있습니다.

하지만 이 준비 과정이 상당히 귀찮고, 반복적인 실험과 재현의 편의성 면에서 다른 프레임워크에 비해 뒤떨어집니다. 전처리 방식이나 학습 파라미터가 변경될때마다 이 준비과정을 계속 반복해야 한다고 생각하면 정말 끔찍합니다 😱 즉 가볍게 사용하기에는 좋지만, 반복적인 실험을 통한 성능 향상을 염두에 두고 있다면 조금 불편할 수 있는 프레임워크입니다. 머신러닝 모델의 성능 향상이 결국에는 수많은 실험에 기반하는 것이라면 다크넷의 단점은 꽤 치명적일수도 있지만, 1%의 성능 향상에 목숨을 걸어야 하는 상황이 아니라면 상당히 괜찮은 프레임워크이니 자신의 상황에 맞게 선택하면 될 것 같습니다!

참고

  • AlexeyAB/darknet
  • Darknet: Open Source Neural Networks in C
  • RSNA Pneumonia Detection Challenge
  • YOLOv4: Optimal Speed and Accuracy of Object Detection
  • You Only Look Once: Unified, Real-Time Object Detection