처음부터 하는 딥러닝

[딥러닝 기초] 활성화 함수 (Activation function)

빈이름 2023. 5. 17. 22:00

활성화 함수의 필요성

딥러닝 모델의 성능을 높이는 방법 중 하나는 레이어의 깊이를 늘리는 것입니다.

위 그림의 모델 수식은 아래와 같이 쓸 수 있습니다.

$$ y=w_3(w_2(w_1x+b_1)+b_2)+b_3=w_3w_2w_1x+w_3w_2b_1+w_3b_2+b_3 $$

그러나 이 모델을 자세히 본다면, 사실상 weight가 $w_3w_2w_1$이고 bias가 $w_3w_2b_1+w_3b_2+b_3$인 하나의 뉴런으로 이루어진 모델과 같다는 걸 알 수 있습니다.

즉, 뉴런을 아무리 깊이 쌓아봤자 사실상 뉴런 하나짜리 모델과 크게 다르지 않게 되는 것입니다.

 

이를 해결하기 위해 사용하는 것이 '활성화 함수(activation function)'입니다.

앞서 봤듯이, 선형 함수(wx+b와 같이 그래프 형태가 직선 형태인 함수)를 아무리 모델을 깊게 설계해봤자 크게 의미가 없게 됩니다. 활성화 함수는 이 선형 함수를 비선형 함수 형태로 바꿔주는 역할을 합니다.

 

활성화 함수의 종류에 대해 알아보고 실제로 성능을 실험해보는 식으로 진행해 보겠습니다.

Sigmoid

Sigmoid 함수는 다음과 같습니다.

$$ \sigma(z)={1\over 1+e^{-z}} $$

Sigmoid를 사용하면 모든 값의 범위가 0에서 1사이의 범위로 제한됩니다.

Sigmoid 함수 그래프

Tanh

Tanh(Hyperbolic Tangent) 함수는 다음과 같습니다.

$$ tanh(z)={e^z-e^{-z}\over e^z+e^{-z}} $$

Tanh를 사용하면 모든 값의 범위가 1에서 -1 사이의 값으로 변환됩니다.

Tanh 함수 그래프

ReLU

Sigmoid와 Tanh도 아주 훌륭하지만, 두 활성화 함수 모두 뉴런의 출력값 z가 너무 크거나 작아질 경우에 도함수가 0에 가까워져 학습이 더뎌지게 되는 문제가 발생할 수 있습니다.

 

$$ ReLU(z)=max(0,z) $$

ReLU는 음수값들을 모두 0으로 바꾸는 역할을 합니다. 이를 이용하면 양수에서의 도함수가 0이 될 걱정은 없게 됩니다.

ReLU는 현재 가장 많이 사용되는 활성화 함수입니다.

ReLU 함수 그래프

그런데 ReLU는 굳이 보자면 선형 함수에 가깝지 않나요? 활성화함수로써의 역할을 제대로 수행할 수 있을까요?

관련된 좋은 글이 있어서 소개 드립니다.

https://towardsdatascience.com/if-rectified-linear-units-are-linear-how-do-they-add-nonlinearity-40247d3e4792

간단히 요약하자면, ReLU 자체는 선형 함수에 가깝지만, 그 수가 많이 쌓였을 땐 다른 활성화 함수와 마찬가지로 비선형 그래프 형태를 만들 수 있다는 것입니다. 그리고 음수값들을 0으로 바꿔주는 것이 모델의 추론에 필요 없는 정보들을 필터링해주는 역할도 해줄 수 있습니다.

Softmax

분류에 사용되는 Softmax도 활성화 함수입니다.

$$p_i={e^{z_i}\over\Sigma^k_{j=1}e^{z_j}},(i=1,2,...,k)$$

Softmax는 모델이 출력한 확률 분포의 값들을 0과 1사이 범위로 제한하여 총합이 1이 되도록 하는 역할을 합니다.

여기에 자연 상수 $e$를 사용하는 이유는 다음과 같습니다.

 

  1. $e^x$ 꼴은 Probability 값을 항상 양수로 만들어줍니다.
  2. $e^x$는 x의 값이 커질수록 그 값이 더 커집니다. 따라서 높은 확률값을 더 강조하는 효과를 얻을 수 있습니다.
  3. $e^x$의 미분은 $e^x$로 미분이 굉장히 쉽습니다.

실험

MNIST 학습 모델에서 활성화 함수의 효과를 직접 실험해 보겠습니다.

https://drive.google.com/file/d/1P_qk34g-VJqklPZkniipa0LRrXDaVlci/view?usp=sharing 

 

서로 다른 활성화 함수를 사용하는 4개의 모델을 실험할 것입니다.

import torch.nn as nn

model1 = nn.Sequential(
    nn.Linear(28*28, 256),
    nn.Linear(256, 128),
    nn.Linear(128, 10)
)

model2 = nn.Sequential(
    nn.Linear(28*28, 256),
    nn.Sigmoid(),
    nn.Linear(256, 128),
    nn.Sigmoid(),
    nn.Linear(128, 10)
)

model3 = nn.Sequential(
    nn.Linear(28*28, 256),
    nn.Tanh(),
    nn.Linear(256, 128),
    nn.Tanh(),
    nn.Linear(128, 10)
)

model4 = nn.Sequential(
    nn.Linear(28*28, 256),
    nn.ReLU(),
    nn.Linear(256, 128),
    nn.ReLU(),
    nn.Linear(128, 10)
)

그 외의 조건은 다음과 같이 모두 통일했습니다.

  • optimizer : Adam
  • learning rate : 1e-3
  • batch size : 16
  • epoch : 3
  • random seed : 16

실험 결과 테스트셋에 대한 정확도는 다음과 같이 나타났습니다.

모델1 (no activation) 90.94%
모델2 (sigmoid) 97.14%
모델3 (Tanh) 97.35%
모델4 (ReLU) 97.39%

활성화 함수를 추가하는 것만으로도 활성화 함수를 사용하지 않은 모델과 7%가량의 성능 차이가 발생했습니다.

또, 활성화 함수 중에서도 sigmoid < tanh < ReLU 순으로 성능이 더 좋았습니다.

(당연히 이런 결과가 다른 데이터, 모델에서도 절대적인 것은 아닙니다. 다만 대체로 ReLU가 가장 좋기는 합니다.)