본문 바로가기

Deep Learning

신경망-1 (Neural Network)

퍼셉트론은 AND, OR 게이트의 진리표를 보면서 우리 인간이 적절한 가중치 값을 수동으로 결정했다.

신경망은 가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하여 이 문제를 해결해 준다.

1. 퍼셉트론에서 신경망으로

1-1. 신경망의 예

아래 그림에서 가장 왼쪽줄을 입력층, 맨 오른쪽 줄을 출력층, 중간 줄을 은닉층이라고 한다.

은닉층의 뉴런은 (입력층이나 출력층과는 달리) 사람들의 눈에는 보이지 않는다.

아래의 신경망은 모두 3층으로 구성되지만, 가중치를 갖는 층은 2개 뿐이기 때문에. 2층 신경망 이라고 한다.

 

 

1-3. 활성화 함수의 등장

입력신호의 총합을 출력 신호로 변환하는 함수를 활성화 함수(activation function) 이라고 한다. "활성화" 라는 이름이 말해주듯이 활성화 함수는 입력 신호의 총합이 활성화를 일으키는지를 정하는 역할을 한다.

 

 

 

위의 그림은 다음과 같은 두개의 식으로 표현할 수 있다.

$a = b + w_1x_1 + w_2x_2$

$y = h(a)$

2. 활성화 함수

$$h(x)=\left\{ \begin{array}{rcr}0&(x <= 0)\\ 1&(x > 0) \\ \end{array} \right.$$

위의 활성화 함수는 편향을 더한 출력의 결과 $a$ 가 0 이냐 1이냐에 따라 뉴런의 출력 여부를 결정한다. 이와 같이 임계값을 경계려 출력이 바뀌는 함수를 계단 함수(step function) 이라고 한다.

이 활성화 함수를 계단 함수에서 다른 함수로 변경하는 것이 신경망의 세계로 나아가는 열쇠이다!

2-1. 시그모이드 함수

다음은 신경망에서 자주 이용하는 활성화 함수인 시그모이드 함수(sigmoid function) 이다.

$$h(x)=\cfrac{1}{1+exp(-x)}$$

신경망에서는 활성화 함수로 시그모이드 함수를 이용하여 신호를 변환하고, 그 변환된 신호를 다음 뉴런에 전달한다.

 

앞에서 본 퍼셉트론과 앞으로 신경망의 주된 차이는 이 활성화 함수의 차이이다

 

 

2-2. 계단 함수 구현하기

import numpy as np
import matplotlib.pylab as plt


# 가장 단순한 계단함수
def step_function(x):
    if x > 0:
        return 1
    else:
        return 0


print(step_function(3.0))


# 넘파이 배열도 지원하는 계단함수
def step_function(x):
    y = x > 0  # 넘파이의 부등호 연산을 수행
    return y.astype(np.int)  # Bool 배열을 int 형으로 변환


print(step_function(np.array([1.0, 2.0])))

2-3. 계단 함수의 그래프

import numpy as np
import matplotlib.pylab as plt

# 계단 함수의 그래프
def step_function(x):
    return np.array(x > 0, dtype=np.int)


x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()

 

2-4. 시그모이드 함수 구현하기

 

import numpy as np


# np.exp(-x) 가 넘파이 배열을 반환하기 때문에 1 / (1 + np.exp(-x)) 도 넘파이 배열의 각 원소에 연산을 수행한 결과를 내어준다.
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


# 넘파이 배열도 처리 가능
print(sigmoid(np.array([-1.0, 1.0, 2.0])))

 

  • 시그모이드 함수 그리기
import numpy as np
import matplotlib.pylab as plt

# 시그모이드 함수 그래프 그리기
x = np.arange(-5.0, 5.0, 1.0)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)  # y 축 범위 지정
plt.show()

 

 

2-5. 시그모이드 함수와 계단 함수 비교

  • 공통점
  1. 큰 관점에서 같은 모양을 하고 있다. (둘 다 입력이 작을때의 출력은 0 에 가깝거나 0 이고, 입력이 클때의 출력은 1에 가깝거나 1이 된다.)
  2. 입력이 아무리 작거나 커도 출력은 0에서 1 사이이다.
  3. 두 함수 모두 비선형 함수 이다. ( 선형 함수를 이용하면 신경망의 층을 깊게 하는 의미가 없어지기 때문에 신경망에서는 활성화 함수로 비선형 함수를 사용해야 한다. )

 

 

 

  • 차이점
  1. 계단 함수는 0을 경계로 출력이 갑자기 바뀌어 버리지만, 시그모이드 함수는 부드러운 곡선이며 입력에 따라 출력이 연속적으로 변화한다.
  2. 계단 함수는 0과 1중 하나의 값만 돌려주는 반면 시그모이드 함수는 실수(0.731 ... 0.123...) 를 돌려준다. 다시 말해 퍼셉트론에서는 뉴런 사이에 0 혹은 1이 흘렀다면, 신경망에서는 연속적인 실수가 흐른다.

2-6. ReLU 함수

시그모이드 함수는 신경망 분야에서 오래전부터 이용해왔으나, 최근에는 ReLU(Rectified Lineaar Unit) 함수를 주로 이용한다.

ReLU 는 입력이 0 을 넘으면 입력을 그대로 출력하고, 0 이하이면 0 을 출력하는 함수이다.

수식으로는 다음과 같이 표현할 수 있다.

 

$$h(x)=\left\{ \begin{array}{rcr}x&(x > 0)\\ 0&(x <= 0) \\ \end{array} \right.$$

 

import numpy as np


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


print(relu(0.3))  # 0.3
print(relu(-0.1))  # 0.0

 

* ReLU 함수의 그래프

 

3. 다차원 배열의 계산

3-1. 차원의 수 & Shape 출력하기

import numpy as np

# 다차원 배열
B = np.array([[1, 2], [3, 4], [5, 6]])

"""
[[1 2]
 [3 4]
 [5 6]]
"""
print(B)

# 차원의 수 출력
print(np.ndim(B))  # 2
# 3행 2열을 의미
print(B.shape)  # (3, 2)

 

3-2. 행렬 곱 (내적) 구하기

import numpy as np

# (2,3)
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A.shape)

# (3,2)
B = np.array([[1, 2], [3, 4], [5, 6]])
print(B.shape)

# 행렬 곱 (내적)
print(np.dot(A, B))

""" 행렬 곱을 할 수 없는 경우 """
C = np.array([[1, 2], [3, 4]])

# print(np.dot(A, C))  # Error! shapes (2,3) and (2,2) not aligned: 3 (dim 1) != 2 (dim 0)

 

3-3. 차원이 다른 배열의 경우

""" 차원이 다른 배열의 경우 """
A = np.array(([1, 2], [3, 4], [5, 6]))
print(A.shape)  # (3, 2)

B = np.array([7, 8])
print(B.shape)  # (2,)

print(np.dot(A, B))  # [23 53 83]

 

 

3-4. 차원의 곱으로 신경망 구하기

 

import numpy as np

""" 행렬의 곱으로 신경망 구하기 """
X = np.array([1, 2])
W = np.array([[1, 3, 5], [2, 4, 6]])
Y = np.dot(X, W)

print(Y)  # [ 5 11 17]

 

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

신경망 학습 - 1  (0) 2021.02.11
신경망-2 (Neural Network)  (0) 2021.01.31
Perceptron (퍼셉트론)  (0) 2021.01.17