최종 출력층에는 어떤 문제냐에 따라서 사용하는 활성화 함수가 달라진다.
대부분 회귀에는 항등함수, 분류에는 소프트맥스를 사용한다.
Softmax(소프트 맥스) 함수 구현
식은 다음과 같다.
$$ y_{k}=\frac{exp(a_{k})}{\sum_{i=1}^{n}exp(a_{i})} $$
간단히 구현해보자
def softmax(x):
exp_x = np.exp(x)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
위처럼 잘 구현했지만 컴퓨팅 환경에선 오버플로 문제를 일으킬 수 있다는 점이다.
오버플로 문제를 해결하기 위해 함수를 개선해 보자
$$ y_{k}=\frac{exp(a_{k})}{\sum_{i=1}^{n}exp(a_{i})} =~\frac{C\exp(a_{k})}{C\sum_{i=1}^{n}\exp(a_{i})} $$
$$ =\,{\frac{\exp(a_{k}+l o g^{C})}{\sum_{i=1}^{n}\exp(a_{i}+l o g^{C})}} $$
$$ =\,{\frac{\exp(a_{k}+C^{\prime})}{\sum_{i=1}^{n}\exp(a_{i}+C^{\prime})}} $$
이런 식으로 치환하여 C'이라는 새로운 기호로 바꿔보았다.
위에서 말하는 핵심은 어떤 값을 더하거나 빼도 기존의 소프트 맥스 함수랑 차이가 없다는 것이다.
그래서 우리가 해결해야 하는 오버플로문제의 일반적인 방법은 최댓값을 빼주는 것이다.
def softmax(x):
c = np.max(x) # 최대값 뽑기
exp_x = np.exp(x - c) # 최대값 빼기
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
소프트 맥스의 특징
이 녀석은 재밌는 특징이 있다.
x = np.array([2.0, 1.3, 3.1])
y = softmax(x)
print(y)
np.sum(y)
softmax()의 출력의 총합은 1이라는 것이다.
이 특징은 매우 중요하다. 왜냐하면 이것 때문에 확률로 해석할 수 있기 때문이다.
학습과 추론
큰 문제는 아니고 학습에서는 소프트 맥스를 적용하지만 현업에 적용될 때는 지수 함수 계산에 사용되는 자원 낭비를 줄이기 위해서 출력층에 소프트 맥스함수는 생략하는 것이 일반적이다.