파이톨치

[밑바닥부터 시작하는 딥러닝] 신경망 본문

AI&ML/밑바닥부터 시작하는 딥러닝

[밑바닥부터 시작하는 딥러닝] 신경망

파이톨치 2022. 12. 26. 15:12
728x90

여기부터는 천천히

기억을 더듬어서 작년에 처음 기계학습에 대해 배울 때 여기부터 어려웠던 것 같습니다. 내용이 어려운 것도 있지만 여기부터 알아야 할 내용이 많아져서 그런 것이라고 생각합니다. 때문에 여기부터는 이것을 읽는 사람이 최대한 이해할 수 있도록 노력해야겠습니다.

 

우선은 간단한 복습을 해야 이 이후의 내용들을 이해하는데 무리가 없을 것 같습니다. 

 

 

그림1. 신경망의 구조

신경망은 다음과 같이 입력층, 은닉층, 출력층이 있습니다. 입력층은 지금 단계에서는 크게 신경쓰지 않아도 되지만 은닉층과 출력층은 어떻게 설계하는지에 따라서 완전히 다른 결과가 나오기도 합니다. (물론 입력도 어떻게 넣느냐에 따라 하나의 논문이 나오기도 한 것 같습니다.)

 

신경망은 다수의 노드들의 층을 어려개 만들어 놓은 것입니다만, 한가지 퍼셉트론과 다른 점은 활성 함수의 존재입니다. 사실 이전에도 우리는 알게 모르게 활성함수를 써왔습니다.

 

그림2. 퍼셉트론의 활성함수

언제 우리가 저 활성함수를 썼을까요? 바로 theta의 존재입니다. 우리는 가중치를 통해서 0보다 큰지 작은지 체크를 하고 그에 따른 반환 값을 주었습니다. 이것이 하나의 활성 함수입니다. 신경망에서는 이 활성함수의 개념이 메인이라고 생각됩니다. 

 

우리가 은닉층과 출력층을 나누었던 것도 활성 함수가 다른 이유도 있을 것입니다. 먼저 은닉층의 구조와 어떤 활성 함수를 쓰는지 살펴보고 출력층은 어떻게 설계하는지 살펴봅시다. 

우선은 은닉층

은닉층은 만들어 놓고 자세하게는 보지 않는 층입니다. 데이터가 많아지면서 우리는 모든 가중치를 설정하기 힘들어집니다. 때문에 학습을 통해 자동으로 가중치를 설정하게 만드는데 그것을 은닉층에서 담당합니다. 설계된 절차에 따라 움직이기 때문에 안에서 일어나는 연산들은 사실상 우리가 알 바는 아닙니다.

 

앞에서도 말했다듯이 우리는 은닉층에서 활성 함수를 사용합니다. 퍼셉트론의 연산 기억을 살려보면 우리는 행렬끼리의 연산을 진행한 후에 theta를 통해 값을 정해주었습니다. 즉, 행렬의 연산 후에 활성함수가 동작하는 것이고 이를 그림으로 보면 다음과 같습니다. 

 

 

그림3. 활성함수 퍼셉트론

여기서 b는 theta와 같은 역할을 하고 편향이라 부릅니다. 수식을 명확히 보면 다음과 같습니다.

 

식1. a에 대한 식

우리가 이제 봐야할 것은 활성 함수의 종류에는 무엇이 있고 어떻게 만드는지 입니다. 

우선, 우리가 계속해서 사용해왔던 것은 계단함수입니다. 0부근에서 값이 계단처럼 바뀌기 때문에 이러한 이름이 붙었을 것이라 생각합니다.

 

다음은 시그모이드 함수라고 부르는 함수입니다. 자주 사용하는 것 같긴 한데, 이 함수에는 사실 치명적인 단점이 있습니다. 수학에 자신이 있는 분들은 미분을 해보시면, 1보다 작은 값이 나오는 것을 알 수 있습니다. 그렇게 되면 학습을 할 때, 기울기 소실이라는 문제가 생기는데 이는 학습에 대해 다룰 때 좀 더 자세하게 이야기할 것 입니다. 시그모이드 함수의 수식은 다음과 같습니다. 

 

 

식2. 시그모이드 활성 함수

이 두 식의 그래프를 한 번 봅시다.

 

그림 4. 계단 함수와 시그모이드 함수

곡선의 형태를 띄고 있는 것이 시그모이드 함수입니다. 우선 보이는 공통점은 0과 1 사이에서 움직인다는 것입니다. 둘의 차이점은 역시 시그모이드 함수의 경우 0 근처에서 부드럽게 움직이는 것을 알 수 있습니다. 또한 사실 둘 다 비선형의 함수입니다. 1개의 직선으로 그릴 수 없으니까요. 

 

그리고 이것은 앞에서 말했던 기울기 소실의 문제를 없앤 활성함수입니다. 바로, ReLU 함수입니다.

 

그림5. ReLU 함수

보기에는 굉장히 간단하지만 꽤나 많이 사용하는 함수입니다. 0보다 클 때는 y=x 로 움직입니다.

 

이런 식으로 단순히 행렬의 곱을 활성함수를 지나면 됩니다. 이런 층을 여러개 쌓으면 그것이 은닉층이 됩니다. 연산 과정을 보면 꽤나 복잡해 보이지만 사실 그 안에서 일어나는 일들은 알 바가 아니기 때문에 굳이 복잡하게 보지는 않겠습니다. 우리가 할 것은 연산을 하는 것보다 어떻게 설계할지입니다.

다음은 출력층

출력층은 어떻게 설계하는냐에 따라서 푸는 문제가 달라집니다. 예를 들어서 소프트맥스 함수를 쓰면 분류 문제를 풀고 항등 함수는 회귀 문제를 풉니다. 하지만 항등 함수의 경우 하는 역할이 딱히 없기 때문에 문제를 푼다고 말하기 애매 할 수도 있습니다.

 

항등함수는 입력이 그대로 출력으로 나오는 함수입니다. 그니까 a를 넣으면 a가 나온다는 말입니다. 

 

소프트 맥스의 경우하는 역할이 큽니다. 우선 수식을 보면 다음과 같습니다. 

 

수식 3. 소프트맥스 함수

하지만 이것을 그대로 쓴다면, 오버플로우라는 문제가 생깁니다. 이 문제는 컴퓨터가 표현할 수 있는 범위를 빠져가서 표현하는 문제입니다. 컴퓨터는 제한된 크기의 숫자만 다루기에 문제가 생기는 것 입니다. 때문에 실제로 사용하기 위해서는 저 식을 변형을 해주어야 합니다. 이것이 가능한 이유는 위의 것이 지수형태로 되어 있기 때문입니다. 

 

수식 4. 소프트맥스 변형 과정

이렇게 변형하면 C'을 통해서 크기는 줄이지만 같은 결과를 뽑아냅니다. 또한 소프트맥스의 결과의 합은 항상 1이라는 점도 기억해주세요. 코드로 보면 다음과 같습니다.

def softmax(a):
  c = np.max(a)
  exp_a = np.exp(a - c)
  sum_exp_a = np.sum(exp_a)
  y = exp_a / sum_exp_a
  return y

a = np.array([0.3, 2.9, 4.0])
y = softmax(a)

이것이 왜 분류를 푸는데 사용되냐면 소프트맥스의 결과는 확률을 의미하기 때문입니다. 위의 결과는 [0.018 0.245 0.736] 이 나오는데 여기서 0.736이 가장 높은 확률을 가지기에 분류를 한다면 3번째 것으로 분류를 할 것 입니다. (참고로 소수점을 버려서 1.0 이 안나오는 것이지 정확하게 계산을 돌리면 합은 항상 1.0 입니다.)

 

하지만 주의해서 봐야할 것은 결국 원소들 사이의 순위는 변하지 않았습니다. 지수함수가 단조 증가 함수이기 때문에 원소들 사이의 대소 관계는 변하지 않은 것입니다. 때문에 확률로 변환해주는 것은 신경망 학습을 쓰일 때 사용하는 것이지 실제로 분류를 할 때는 크게 도움이 되지 않을 것 입니다. 

 

이는 뒤의 글에서 더 자세하게 다룰 것 입니다.

 

 

 

 

 

 

728x90