반응형

[그림.1] 신경망의 예

신경망을 그림으로 나타내면 위의 그림과 같고 입력층, 은닉층, 출력층으로 이루어진 것을 볼 수 있다.

 

[그림.2] 

x1과 x2 의 신호를 입력으로 받아 y를 출력하는 퍼셉트론은 위의 [그림.2] 와 같이 표현될 수 있고

이를 식으로 표현하면 아래와 같다.

 

[식.1]

여기서 b는 편향을 나타내는 매개변수로 뉴런이 얼마나 쉽게 활성화되느냐를 제어하게 되고

w1과 w2는 각 신호의 가중치를 나타내는 매개변수로 각 신호의 영향력을 제어하게 된다.

 

그리고 이 식을 변형시켜서 아래와 같이 표현할 수 있다.

 

[식.2]

 

[식.3]

 

즉 (b+w1x1+w2x2) 가 0보다 작거나 같으면 0, 0보다 크면 1 이므로

[식.1] 은 [식.2]와 [식.3] 으로 표현될 수 있다.

 

이 때, 함수 h(x)를 활성화함수 라 하고 입력신호의 총 합을 출력신호로 변환시키는 작업을 하게 되는 함수이다.

 

따라서 위 [식.2], [식.3] 은

[식.2] -> 가중치가 곱해진 입력신호의 총 합을 계산함

[식.3] -> 그 합을 활성화함수에 입력해 결과를 나타냄

위의 2가지 과정으로 진행이 되고 따라서 아래와 같이 표현이 가능하다.

 

[그림.3]
[식.4]
[식.5]

 

즉 a는 입력신호와 가중치를 합한 값

h(a) 는 a의 값에따라 결과적으로 1인지 0인지를 판별하는 과정을 진행하는 함수

로 정리할 수 있다.

 

 

위의 [식.2], [식.3] 을 확인하여보면 x값에 따른 결과(h(x))가 0 아니면 1을 갖게 되고 이를 그래프로 표시하면

계단함수형태를 나타내게 된다.

 

 

[그림.4]

 

여기까지의 내용은 퍼셉트론에서 다룬 내용과 비슷하다.

 

퍼셉트론과 신경망의 가장 큰 차이는 활성화 함수 h(x)이고 h(x)의 형태가 퍼셉트론의 경우 위와같은 계단함수 형태,

신경망의 경우 부드러운 곡선형의 시그모이드 함수의 형태를 갖게 된다.

 

시그모이드 함수란

[식.6]

활성화 함수 h(x)의 값이 다음과 같이 표시되고 그래프로 나타내게 되면

[그림.5]

위의 [그림.5]와 같이 부드러운 곡선 형태로 그려지게 된다.

 

한가지 짚고 넘어갈 것은 계단함수와 시그모이드 함수 모두 비선형 함수라는 것이다.

선형함수는 층을 아무리 깊게해도 은닉층이 없는 네트워크로 표현되기 때문에 비선형함수이어야 한다.

 

 

* 참고 *

시그모이드 함수는 신경망 분야에서 오래전부터 사용되었으나 최근에는 ReLU함수를 주로 사용하고 있다.

[식.7] ReLU함수
[그림.6] ReLU함수

 

 

 

그럼 이제 신경망을 구현하여 보자.

[그림.7] 입력층에서 1층으로 신호 전달

위의 그림을 보면 편향과 입력값(x1, x2)을 이용하여 1층의 a1 값을 구하게 된다.

이와같은 방식으로 1층의 a2, a3를 구할 수 있을 것이고 여기서 구한 a값을 이용하여

그 다음 2층의 a1, a2값을 구할 수 있게 된다.

 

즉 위와 같이 a1이 표현될 수 있고 이 과정을 계속 진행하여 1층의 a원소들은 행렬 A로 아래와 같이 표현된다.

 

 

 

2층, 3층의 계산 과정은 아래의 그림을 참고하도록 하자.

[그림.8](좌) 1층에서 2층으로의 과정                                               [그림.9](우) 2층에서 출력층으로의 과정

### 입력층에서 1층으로까지의 과정
X = np.array([1.0, 0.5])
S1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])

print(W1.shape)
print(X.shape)
print(B1.shape)

A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)

print(A1)
print(Z1)



### 1층에서 2층으로까지의 과정
W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])

print(Z1.shape)
print(W2.shape)
print(B2.shape)

A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)



### 2층에서 출력층으로까지의 과정
def identity_function(x):   ## 여기서 identity 함수는 입력값을 그대로 출력하게 되는 함수
    return x

W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])

A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)

 

 

 

 

 

 

 

 

 

 

그 다음 등장하는 개념은 분류에서 사용되는 소프트맥스 함수(Softmax function) 이다.

 

[식.8] 소프트맥스 함수

위의 식에서 n은 출력층의 뉴런 수, y_k 는 그 중 k번째 출력임을 뜻하고 있다.

이를 그림으로 나타내면 아래와 같다.

[그림.10] 소프트맥스

이를 보면 소프트맥스 함수의 출력은 모든 입력 신호로부터 화살표를 받게 된다.

즉 출력층의 각 뉴런이 모든 입력신호에서 영향을 받는다는 것을 확인할 수 있다.

 

하지만 위의 소프트맥스 함수[식.8]은 지수함수로 이루어져 k의 값이 굉장히 커지게 되면 오버플로우가 발생하게 된다.

(컴퓨터는 수를 4바이트나 8바이트와 같이 크기가 유한한 데이터로 다루기에 표현할 수 있는 수의 범위가 한정적이다)

 

이를 확인하기 위해 프롬프트창에서 다음과 같이 실행시켜보자.

 

>>> a = np.array([1010, 1000, 990])
np.exp(a) / np.sum(np.exp(a))

 

이를 실행시키면

array([ nan, nan, nan])

과 같이 출력될 것이다.

 

그럼

위의 내용에 이어서

>>> c=np.max(a)

>>> a-c

를 입력하면

 

array([0, -10, -20])

이 출력되는 것을 확인할 수 있고 계속 이어서

 

>>> np.exp(a-c) / np.sum(np.exp(a-c))

를 입력하여 확인하여보면

array([ 9.99954600e-01,   4.53978686e-05,   2.06106005e-09  ])

의 값이 출력되는 것을 확인할 수 있다.

 

즉 간단하게 표현하여

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

 

위와 같이 구현할 수 있다.

 

소프트맥스 함수의 큰 특징은 이를 이용하여 소프트맥스 함수의 결과값을 확률로 해석할 수 있다는 것이다.

소프트맥스 함수의 결과값은 0에서 1.0 사이의 실수이다.

또한 출력의 총합이 1이 되고 출력값이 모든 입력값의 영향을 받기때문에 확률로 해석이 가능하다.

 

또한 소프트맥스 함수를 적용해도  y=exp(x)의 함수는 단조증가함수이기에

각 원소의 대소관계는 변하지 않는다.

 

 

반응형

'Deep Learning' 카테고리의 다른 글

선형회귀  (0) 2021.01.11
퍼셉트론(Perceptron)  (0) 2020.02.04

+ Recent posts