게임 디자인 레벨업 #5 엑셀로 쉽게 이해하는 딥러닝 – Single Neuron의 학습

보다 새롭고 창의적인 게임 디자인을 발굴하기 위해, 최신 게임 트렌드와 사례 연구에 힘쓰고 있는 엔씨소프트의 개발전략실!

개발전략실에서 직접 조사하고 연구한 내용을 담은 ‘게임 디자인 레벨업’에서는 앞으로 3회에 걸쳐 딥러닝의 핵심인 신경망의 기초에 대해 소개할 예정입니다.

신경망을 복잡하고 어렵다고 생각할 수 있지만 각 구성 요소를 살펴 보면 단순한 사칙연산으로 이루어져 있습니다. 이 주제를 처음 접하는 분들의 부담감을 줄이기 위해 많은 분들에게 익숙한 프로그램인 엑셀을 통해서 접근해보도록 하겠습니다.


신경망은 다양한 인공지능(Artificial Intelligence) 기법들 중 하나입니다.

인간의 신경세포를 흉내낸 뉴런(Neuron)을 각 층(Layer)에 배치하고, 그들 간에 정보를 교환해서 다양한 문제를 풀어냅니다. 신경망을 사용한 딥러닝은 바둑, 이미지 인식 문제, 자동 번역 등 전통적인 문제해결법으로 풀 수 없던 문제를 풀어내고 있어서 현재 세계적으로 가장 주목받는 기법입니다.

[그림 1] 1,000개 카테고리의 이미지를 정확히 분류하는 문제인
ImageNet에서 딥러닝 방식은 2015년부터 인간의 수준을 넘어섰습니다.

신경망은 얕은(Shallow) 신경망과 깊은(Deep) 신경망으로 분류할 수 있으며, 이 중 가운데에 있는 은닉층(Hidden Layer)의 개수가 2개 이상이면 보통 깊은 신경망으로 간주합니다. 이 깊은 신경망으로 학습을 시키는 것을 딥러닝이라고 합니다.

[그림 2] 신경망은 입력층(Input), 은닉층(Hidden), 출력층(Output)으로 구성됩니다.

[그림 2]에서 확인할 수 있듯이 신경망은 여러 개의 층으로 구성됩니다. 각 층은 입력을 받아서 다음 층에 출력하고, 출력층(Output Layer)의 출력이 신경망의 최종 출력이 됩니다.

각 층은 1개 이상의 뉴런으로 구성됩니다. 각 층을 구성하는 뉴런의 개수는 필요에 따라 얼마든지 달라질 수 있습니다. 층이 많아질수록, 층을 구성하는 뉴런이 많아질수록 계산량이 늘어나기 때문에 원활한 딥러닝을 위해 좋은 시스템(주로 GPU)이 필요하게 됩니다.

[그림 3] 하나의 층은 여러 개의 뉴런으로 구성됩니다.

이번 글에서는 하나의 뉴런에만 집중해서, 뉴런의 계산이 어떻게 수행되는지에 대해서 구체적으로 알아보고 엑셀 예제로 동작을 확인해보겠습니다.

하나의 뉴런은 입력, 가중치, 활성화함수, 출력으로 구성됩니다.

[그림 4] 입력, 가중치, 출력은 보통 정수나 실수(float)이며,
활성화함수는 sigmoid, ReLU, identity, step 등이 주로 쓰입니다.

입력에 가중치를 곱하고 활성화함수를 취하면 뉴런의 출력이 됩니다.

[그림 5] ‘활성화함수(입력 * 가중치) = 출력’입니다.

가중치는 학습 과정에서 서서히 변하는 값입니다. 학습이 잘된다는 것은 좋은 가중치를 얻어서 원하는 출력에 점점 가까워지는 것이라고 정의할 수 있겠습니다.

[그림 6] 딥러닝 학습을 이용한 가상 인물의 Portrait 생성 사례입니다.
학습이 진행됨에 따라 더 좋은 결과를 얻습니다. (관련 링크)

그럼 이제 실제 예제로 들어가보도록 하겠습니다.

만약 뉴런에 입력=1을 넣었을 때 출력=0을 얻고 싶다면 어떻게 해야 할까요?

[그림 7] 입력이 1일 때 출력이 0이 되는 것은 논리회로 NOT 과 비슷합니다.
True값을 받으면 False값을 출력하는 식입니다.

입력에 가중치를 곱해서 활성화함수에 넣는다는 식을 기억하실 겁니다. 뉴런에서 자주 쓰이는 활성화함수는 Sigmoid, ReLU 등이 있습니다. 활성화함수에 대해서는 이 글을 참고하시면 좋을 것 같습니다. 여기서는 Sigmoid 함수를 사용해 봅니다.

[그림 8] 딥러닝을 공부하다 보면 활성화함수로 Sigmoid와 ReLU를 자주 볼 수 있습니다.
신경망 초창기에는 sigmoid가 많이 쓰였지만,
은닉층을 많이 쓰는 딥러닝 시대가 되면서 ReLU 가 더 많이 쓰이고 있습니다.

Sigmoid 함수 형태는 밸런스 경험이 있는 기획자 분들에게 익숙할 것입니다. 방어수치 등의 입력값이 증가할 때 실제 방어도 출력값은 입력값보다는 적게 증가하며 상한치에 한없이 가까워지는 분수함수와 비슷한 형태이기 때문입니다.

[그림 9] <월드 오브 워크래프트>의 방어도 공식입니다.
<리그 오브 레전드>, <디아블로 3> 등 다른 게임들도 비슷한 방어도 공식을 사용하고 있습니다.

Sigmoid에서는 이 상한치가 1입니다. 그리고 하한치는 0입니다. 즉 어떤 값을 넣어도 0 ~ 1 사이의 값을 출력하기 때문에, 출력값을 확률 등으로 사용할 때 편리합니다. 가령 어떤 이미지가 고양이 사진일 확률 = 0.62 = 62% 등으로 출력값을 나타낼 수 있습니다.

[그림 10] 특정 이미지가 고양이 사진일 확률을 출력하는 과정.
(출처: Machine Learning 101, Edwin Efraín Jiménez Lepe, 관련 링크)

[그림 11] 활성화함수는 Sigmoid로 정했습니다.
복잡해보이는 식이지만 일단은 항상 0 ~ 1 사이의 값을 출력한다는 정도만 알고 계시면 됩니다.

Sigmoid 함수를 활성화함수로 선택하니 이제 가중치를 정해야 합니다.

가중치는 변하는 값이지만 초기값 세팅이 필요합니다. 여러 가지 방법이 있지만 랜덤한 값(-1 ~ 1 사이의 실수값)을 넣어주는 것도 괜찮습니다. 엑셀에서는 셀의 수식에 =RAND()*2-1을 입력하면 됩니다. RAND()는 0 ~ 1 사이의 실수값을 출력하기 때문에, 여기에 2를 곱하면 0 ~ 2, 다시 1을 빼면 -1 ~ 1 사이의 값을 얻게 됩니다.

[그림 12] 초기 가중치는 랜덤한 값입니다.

이제 계산을 해봅니다. 입력과 가중치를 곱해서 활성화함수에 넣어주면,

[그림 13] 엑셀로 직접 계산해보세요. =1/(1+EXP(-1*1*-0.12568))을 입력하면 됩니다.

출력은 0.46862가 나옵니다.

[그림 14] 보통 처음 계산되는 실제출력값은 기대출력과 다릅니다.

그런데 기대출력은 0이었습니다. 실제출력과 기대출력 사이에는 -0.46862만큼의 Error가 있습니다.

뉴런에서 학습이라는 것은 이 Error를 줄여서 실제출력을 기대출력과 거의 같아지도록 하는 것입니다. Error를 줄인다는 것은, 0에 가까워지도록 한다는 것입니다.

[그림 15] 기대출력과 실제출력의 차이인 Error를 0에 가까워지도록 줄이는 것이 학습의 목적입니다.

그럼 어떻게 Error를 줄일 수 있을까요? 여러 가지 방법이 있지만 여기서는 간단하게 Batch Learning이라는 방법을 사용해보도록 하겠습니다.

가중치에 학습계수(α), 입력값, Error를 곱한 값을 더해주는 것입니다. 그리고 새로운 가중치로 다시 출력값을 계산하고, 거기서 나온 Error로 다시 가중치를 계산하고, 이 과정을 반복해줍니다. 학습계수는 보통 1보다 작은 값으로 설정하는데, 여기서는 0.25를 사용하겠습니다.

[그림 16] 가중치에 Error값이 반영됩니다.
Error가 클수록 가중치는 많이 변하고, 반대의 경우는 적게 변할 것이라고 예측할 수 있습니다.

계산 결과 가중치는 -0.12568에서 -0.24284로 변합니다.

[그림 17] 가중치가 변했습니다. 다음 번 실제출력은 어떻게 될까요?

새로운 가중치로 다시 계산을 해보면, 실제출력값은 0.43959가 됩니다.

Error 값이 줄어들었습니다. 0에 가까워진 것입니다.

[그림 18] 엑셀로 계산해보세요. =1/(1+EXP(-1*1*-0.24284))을 입력하면 됩니다.

몇 번 더 계산을 해보면 Error가 꾸준히 줄어드는 것을 확인할 수 있습니다.

[그림 19] 기대출력과 실제출력의 오차는 0에 가까워집니다.

그럼 이제까지 살펴본 내용을 엑셀에서 확인해보도록 하겠습니다. 첨부된 엑셀 파일에는 방금 살펴본 계산을 200번 반복한 시뮬레이션이 있습니다.

[그림 20] 하늘색으로 표시된 숫자를 바꾸면 시뮬레이션 결과도 같이 바뀝니다.

가중치 W의 초기값(D3 셀)은 =RAND()*2-1로 설정되어 있습니다. 시뮬레이션을 돌릴 때마다 -1 ~ 1 사이의 랜덤한 값이 지정됩니다. 그리고 그 여파로 다른 값들도 변하게 됩니다.

[그림 21] D3 아래의 셀들은 D3의 값에 영향을 받아서 자동으로 계산됩니다.

입력, 기대출력, 초기 학습 계수를 바꾸면 새로운 시뮬레이션이 실행됩니다. 최소 허용 에러는 Error 셀의 절대값이 해당 값보다 작을 때 Error 셀을 연두색으로 표시해줍니다. 설정값들을 그대로 유지한 채 새로운 시뮬레이션을 보고 싶을 때는 빈 셀에 Delete 키를 눌러주면 됩니다.

마지막으로 그래프에서 Error 는 학습이 진행될수록 0에 가까워지는 것을 확인할 수 있습니다.

[그림 22] X축은 계산회차, Y축은 Error입니다.

그런데 입력과 기대출력 값을 바꾸다 보면 학습이 전혀 되지 않는 경우가 발생합니다. 바로 입력을 0으로 설정할 때입니다. 입력 * 가중치 = 0 * 가중치 = 0이기 때문에 항상 같은 값을 활성화함수에 전달하게 됩니다. 또 가중치에 더하는 값에도 입력값이 있는데 여기에도 0이 있기 때문에 가중치도 항상 같은 값을 유지하게 됩니다.

그리고 입력에 0을 설정하지 않아도 기대출력을 2로 설정하면 Error가 1 부근에서 더 줄어들지 않는 것을 확인할 수 있습니다. 이것은 Sigmoid 함수가 0 ~ 1 사이의 값만 출력하기 때문에 발생하는 문제입니다.

위의 두 가지 문제를 해결하기 위해서 뉴런에는 결과값에 편향치(Bias)라는 것을 더해줍니다. 이 편향치에 대해서는 다음 글에서 자세히 다루도록 하겠습니다.

아래 첨부 파일로 엑셀 시뮬레이션 시트가 제공됩니다. 파란색 값을 바꿔 보시고 변화하는 그래프의 모습을 직접 확인해보세요.

▶ 엑셀 파일 다운 받기  ◀


엑셀로 쉽게 이해하는 딥러닝 시리즈

# 1   Single Neuron의 학습

# 2   Bias의 학습

# 3   AND, OR 논리회로 학습