본문 바로가기
AI - Deep Learning

활성화 함수: 정의와 종류, 비선형 함수를 사용해야 하는 이유

by 모두의 케빈 2022. 11. 1.

안녕하세요. 모두의 케빈입니다.

오늘은 딥 러닝에서 사용되는 활성화 함수의 개념과 왜 비선형 활성화 함수를 사용해야 하는지, 그리고 대표적인 비선형 활성화 함수들에 대해 알아보도록 하겠습니다. 

 

■ 활성화 함수란

 

활성화 함수는 인공 신경망에서 입력값을 변환하는 함수입니다. 대표적으로는 Sigmoid, ReLu 등이 있습니다. 인공 신경망은 인간 두뇌 활동을 모방하기 위해 뉴런의 구조를 참고했습니다. 뉴런은 일정 세기 이상의 자극일 경우에만 신호를 전달하는 계단 함수(Step) 방식을 사용합니다. 따라서 최초의 인공 신경망이라고 평가받는 퍼셉트론은 계단 함수를 사용했습니다.

하지만 이러한 방식으로는 인공 신경망의 학습이 제대로 이루어지기 어려웠습니다. 인간은 오랜 시간 동안 하나의 분야를 탐구하고 학습하지만 계단 함수는 이러한 인간 학습의 연속성을 표현할 수 없었습니다. 그래서 인공 신경망은 뉴런과는 다른 길을 가기로 합니다. 바로, 값을 전달할 때 연속성을 부여할 수 있는 함수를 사용하고자 한 것입니다. 연속 함수를 사용함으로써 학습의 과정이 연속적이고 점진적이게 되었고, 이는 인간이 생애 주기에 걸쳐 연속적으로 학습하는 과정을 모방하는데 큰 도움이 됩니다.

그래서 값을 받고 다른 Layer로 값을 전달할 때 연속성이 있는 비선형 함수를 활용하게 됩니다. 비선형 함수를 사용하는 이유는 크게 두 가지입니다. 첫 번째는 신경망의 표현성을 높이기 위해서입니다. 현실 세계의 대부분 문제는 비선형 문제입니다. 따라서 비선형 활성 함수를 사용하면 모델이 문제를 더 효과적으로 풀 수 있게 됩니다. 또한, 다양한 비선형 활성 함수를 조합하여 사용함으로써 그 효과는 배가 됩니다.

두 번째는 선형 함수 자체가 심층 신경망에 큰 도움이 되지 않기 때문입니다. 이는 활성 함수로 선형 함수를 사용하게 되면, 여러 Layer를 통과하는 결과 값을 단 하나의 Layer로 표현할 수 있게 되면서 신경망을 깊게 쌓는 의미가 희석되기 때문입니다. 

수식적으로 살펴보겠습니다. y = WX라는 선형 함수가 있다고 가정해보겠습니다. 입력값이 3개의 Layer를 통과한다고 했을 때, y = f(f(f(x)))이고 W(W(WX))여서 결과 값은 (W^3)*X가 됩니다. W의 세제곱은 결국 상수이므로 세제곱 형태를 갖는 하나의 활성 함수로도 충분히 표현이 가능합니다. 즉, Hidden Layer가 3개인 신경망과 1개인 신경망의 차이가 거의 없어지게 되는 것입니다.

모델 입장에서 봤을 때, 이는 모델의 표현성과 성능을 현격히 저하시키고 망을 깊게 쌓는 의미를 퇴색시킵니다. 물론, 선형 함수를 깊게 쌓아도 가중치가 늘어나서 아이에 의미가 없지는 않지만 효율성이 너무 떨어집니다. 그래서 인공 신경망은 거의 대부분 비선형 활성 함수를 사용합니다.

■ 비선형 활성 함수의 종류

 

이제 인공 신경망에서 활용되는 비선형 활성 함수에는 어떤 것들이 있는지 살펴보겠습니다.

 

시그 모이드(Sigmoid) 함수

시그 모이드 함수는 로짓의 역변환이며, 로지스틱 회귀 분석의 로지스틱 함수와 유사한 개념입니다. 이에 대한 개념은 앞선 글에서 자세히 설명드려서 이 글에서는 생략하겠습니다. (딥 러닝을 위한 회귀 분석의 이해: Logit, Sigmoid, Softmax)

시그 모이드 함수는 무한대의 실수 값을 0과 1 사이의 확률 값으로 변환하는 역할을 합니다. 아래는 파이썬(Python)으로 구현한 시그 모이드의 코드입니다. 2차 AI 혹한기가 오기 전까지 가장 보편적으로 활용되었던 함수이며, 입력 값의 절대 값이 커질수록 기울기가 0으로 수렴하는 단점이 있습니다.

def sigmoid(x):
    return 1/(1+np.exp(-x))

x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)

plt.plot(x,y)
plt.plot([0,0],[1.0,0.0], ':')
plt.title("Activation Function: Sigmoid")
plt.show()

 

 

 

 

 

 

 

하이퍼볼릭 탄젠트 함수(Hyperbolic Tangent Function)

쌍곡선 함수라고 하기도 합니다. 시그 모이드(Sigmoid) 함수 대비 기울기가 작아지지 않는 구간이 넓어서 양수와 음수 모두에서 학습 효율성이 뛰어납니다. 따라서 심층 신경망에 시그 모이드 함수의 역할이 필요하다면 대안으로써 활용되는 함수이기도 합니다. 다만, 여전히 기울기가 0으로 수렴하는 구간이 존재하여 기울기 소실 문제에 대해서 아주 자유롭지는 않습니다.

x = np.arange(-5.0, 5.0, 0.1)
y = np.tanh(x)

plt.plot(x,y)
plt.plot([0,0],[1.0,-1.0], ':')
plt.title("Activation Function: Tahn")
plt.show()

 

 

 

 

 

 

ReLu 함수

현대 딥러닝 분야에서 가장 기초가 되는 ReLu 함수입니다. 입력값이 음수이면 0을 출력하고 양수 값이면 그대로 흘려보내는 비교적 간단한 함수입니다. Sigmoid 함수의 기울기 소실 문제를 해결해준 함수입니다. 연산이 간편하고 Layer를 깊게 쌓을 수 있다는 장점이 있습니다. 단순한 함수임에도 성능이 잘 나오는 이유에 대해 해석이 분분하지만, 대체적으로 앙상블(ensamble) 효과로 해석합니다. 참고로 ReLu 함수는 입력값이 너무 커지게 되면 모델이 입력 값에 편향이 될 수 있으므로 max값을 6 이하로 제한하는 방식으로 사용하기도 합니다.

(Tip) ReLu 함수는 선형 함수가 아닌, 비선형 함수입니다. 수학적으로 선형의 정의는 ①가산성: T(x+y) = T(x) + T(y)②동차성: T(cx) = cT(x)를 만족하는 선형 변환 또는 일차 변환의 함수여야 합니다. 하지만 ReLu는 가산성이 성립하지 않습니다. x = -1, y = 2라고 가정한다면 T(-1+2) = T(1) = 1이지만, T(-1) = 0이고 T(2) = 2이므로 T(-1+2)와 T(-1) + T(2)는 같지 않고 따라서 ReLu는 비선형 함수입니다.

def ReLu(x):
    return np.maximum(0,x)

x = np.arange(-5.0, 5.0, 0.1)
y = ReLu(x)

plt.plot(x,y)
plt.plot([0,0],[5.0,0.0], ':')
plt.title("Activation Function: ReLu")
plt.show()

 

 

 

 

 

 

 

Leaky ReLu 함수

ReLu 함수의 단점을 보완하기 위해 나온 함수입니다. ReLu는 음수 값이 들어오면 0을 반환하기 때문에 음수 값에서는 학습이 진행되기 어렵습니다. Layer 간 전달되는 값이 0이기 때문인데요. 이러한 문제를 죽어가는 ReLu(Dying ReLu) 또는 죽은 뉴런(Dead Nueron)이라고 합니다.

이를 해결하기 위해, 음수 값에서는 입력 데이터에 아주 작은 값을 곱(일반적으로 1 이하의 아주 작은 값)하여 반환하는 Leaky ReLu가 등장하게 됩니다. ReLu의 특징을 거의 이어받았다는 특징이 있습니다.

def LeakyReLu(x):
    return np.maximum(0.1*x, x)

x = np.arange(-5.0, 5.0, 0.1)
y = LeakyReLu(x)

plt.plot(x,y)
plt.plot([0,0],[5.0,-1.0], ':')
plt.title("Activation Function: Leaky_ReLu")
plt.show()

 

 

 

 

 

 

 

ELU(Exponential Linear Unit) 

ELU(Exponential Linear Unit)은 ReLu의 장점을 포함하면서 단점을 최소화할 수 있도록 고안된 함수입니다. 2015년이라는 비교적 이른 시간에 발표되었고 ReLu를 보다 부드럽게 만든 형태가 특징입니다. 음수 값이 들어오면 지수 함수를 사용하여 부드럽게 꺾어주기 때문에 노이즈에 덜 민감한 효과가 있습니다. 다만, ReLu나 Leaky_ReLu 대비 연산량이 복잡하다는 단점이 있습니다.

a = 1

def ELU(x):
    return (x>0)*x + (x<=0)*(a*(np.exp(x)-1))

x = np.arange(-5.0, 5.0, 0.1)
y = ELU(x)

plt.plot(x,y)
plt.plot([0,0],[5.0,-1.0], ':')
plt.title("Activation Function: ELU")
plt.show()

 

 

 

 

 

 

 

 

 

 

댓글