3장
3.1 신경망
3.2 활성화 함수
3.3 다차원 배열의 계산
3.4 3층 신경망 구현
3.5 출력층 설계하기
3.6 배치 처리
3.1 신경망
신경망이란?
- 퍼셉트론을 여러층 쌓아 만든 하나의 거대 비선형 분류기
동작(0을 넘으면 1을 출력하고, 그렇지 않으면 0을 출력)을 하나의 함수로 나타낸다.
이 함수를 h(x)라 하면 다음과 같은 수식으로 표현할 수 있다.
h(x) = 입력신호의 총합
y = h(x)를 통해 변환된 값 (출력값)
3.2 활성화 함수
- 인공 신경망에서 h(x)와 같이 입력 신호의 총합을 출력값으로 변환하는 함수.
- 은닉층과 출력층에서 사용된다.
- 활성화 함수는 인공 신경망의 비선형성을 제공하고, 신경망의 복잡한 패턴을 학습할 수 있도록 한다.
- 만약 활성화 함수를 사용하지 않는다면, 인공 신경망은 선형 함수로만 표현될 수 있어 매우 제한적인 문제만 해결할 수 있다.
라고 하면, 활성화 함수는 a를 입력 받아 y를 출력하는 함수가 된다.
3.2.1 계단함수 (step)
음수이면 무조건 0을, 0초과이면 1을 출력해 주는 함수
현재는 많이 사용되지 않으며 데이터 손실이 발생할 가능성이 높고 불연속 함수이기에 미분이 불가능하다.
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) #-5부터 5까지 0.1 간격으로
y= step_function(x) #x를 입력으로
plt.plot(x,y)
plt.ylim(-0.1, 1.1) #y축 범위지정
plt.show()
3.2.2 시그모이드 함수 (Sigmoid)
입력값을 0과 1 사이의 값으로 변환하는 함수
0과 1로 출력되는 것이 아닌 0과 1사이의 실수로 구성되어있기 때문에, 정교한 수 전달 가능
입력값이 무한대로 커지거나 작아질 때 출력값이 0 또는 1에 수렴하는 함수
import numpy as np
import matplotlib.pylab as plt
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.ylim(-0.1, 1.1)
plt.show()
3.2.3 ReLU 함수
입력값이 0 이상일 경우 입력값을 그대로 출력하고, 0 이하일 경우에는 0을 출력.
0과 1사이가 아니기에 0 이하의 정보는 모두 무시한다.
import numpy as np
import matplotlib.pylab as plt
def relu(x):
return np.maximum(0,x)
x= np.arange(-6.0 , 6.0 , 0.1)
y= relu(x)
plt.plot(x,y)
plt.ylim(-1.0, 6.0)
plt.show()
- 활성화 함수를 쓰는 이유
Sigmoid 또는 ReLU와 같은 비선형 함수를 써서 데이터를 입력에 대해 출력이 연속인 결과를 얻기 위해
Step함수는 입력에 대해 출력이 0또는 1밖에 나오지 않음.
그에 반해 Sigmoid는 입력에 대해 0~1사이 연속적인 실수를 반환.
ReLU는 입력이 0보다 크기만 하면 입력값 그대로를 출력함. 그로 인해 층이 깊어져도 각 층의 입력 데이터로는 연속적인 값이 입력됨.
즉 데이터가 비선형이 되면 층이 깊어질 수 있고 원하는 값만 뽑아낼 수 있다.
- 활성화 함수로 선형함수 쓰지 않는 이유
은닉층이 없는 네트워크로 표현이 됨. 신경망의 층을 깊게하는 의미가 없음.
3.3 다차원 배열의 계산
3.3.1 다차원 배열
import numpy as np
b = np.array([[1,2], [3,4], [5,6]])
print(b)
print(np.ndim(b)) #2 : 배열의 차원 수
print(b.shape) #(3,2) : 배열의 형상 -> 3행 2열
3.3.2 행렬의 곱 (np.dot)
import numpy as np
b = np.array([[1,2], [3,4], [5,6]])
a = np.array([[1,2,3], [3,4,5]])
print(np.dot(a,b))
''' [[22 28]
[40 52]] '''
3.3.3 신경망에서의 행렬 곱
3.4 3층 신경망 구현
2층의 첫번째 뉴런 식을 수식으로
3.4.1 각 층의 신호 전달 구현하기
은닉층에서의 가중치 합을 a로 표기하고
활성화 함수 h()로 변환된 신호를 z로 표기한다.
import numpy as np
# 3층 신경망 구현하기
# 입력(2개) ->1층(3개)->2층(2개)->출력층(2개)
# A1 = X*W1+B1
# A1 = XW1 + B1
# = [x1 x2][w11 w21 w31] + [b1 b2 b3] = [x1w11 + x2w21 + b1, x1w12 + x2w22 + b2, x1w13 + x2w23 + b3]
# X = [x1,x2]
# B = [b1,b2,b3]
# W = [w11 w21 w31]
# [w12 w22 w32]
# 1층 3개짜리 구현하기
X = np.array([1.0, 0.5])
W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
B1 = np.array([0.1,0.2,0.3])
A1 = np.dot(X,W1)+B1
def sigmoid(x):
return 1/(1+np.exp(-x))
Z1 = sigmoid(A1)
print(Z1)
# [0.57444252 0.66818777 0.75026011]
# 2층 2개짜리 구현하기
W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
print("Z2")
print(Z2)
# Z2
# [0.62624937 0.7710107 ]
W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])
def identity_func(x):
return x
A3 = np.dot(Z2, W3) + B3
print("A3")
print(A3)
# A3
# [0.31682708 0.69627909]
Y = identity_func(A3)
print("Y")
print(Y)
# Y
# [0.31682708 0.69627909]
활성화 함수만 지금까지의 은닉층과 다르다.
그래서 이전 활성화 함수 h()와 다르게 σ()로 표시되어있다.
이 문제에서는 항등함수인 identity_function()을 정의하고, 이를 출력층 활성화 함수로 이용한다.
3.5 출력층 설계하기
3.5.1 항등 함수와 소프트맥스 함수 구현하기
출력층의 활성화 함수로는 항등 함수와 Softmax 함수
출력층에 항등 함수를 쓴다면 회귀를 할 수 있고, Softmax 함수를 쓴다면 분류를 할 수 있다.
(분류 : 데이터가 어느 클래스에 속하는지 / 회귀 : 입력 데이터에서 연속적인 수치를 예측하는 문제)
- 소프트맥스 함수
소프트맥스 함수는 입력받은 값을 출력으로 0과 1 사이의 값으로 정규화하며, 출력값의 총합은 항상 1이 되도록 만들어주는 함수. 따라서 출력값을 확률로 해석할 수 있다.
예를 들어, 어떤 이미지가 고양이, 강아지, 토끼 중 어떤 것인지 판별하는 문제가 있다면, 마지막 출력층의 각 뉴런은 해당 동물의 종류에 해당. 이때 소프트맥스 함수를 사용하여 출력값을 확률값으로 변환할 수 있다.
소프트맥스 함수 구현
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a/sum_exp_a
return y
aa = np.array([0.3, 2.9, 4.0])
yy = softmax(aa)
print(yy)
# [0.01821127 0.24519181 0.73659691]
print(np.sum(yy))
# 1.0
소프트맥스 함수 구현 시 주의점
소프트맥스 함수의 가장 큰 결함은 오버플로우 문제.
지수 함수는 아주 큰 값을 내뱉기 때문에 이런 큰 값끼리 나눗을 하면 결과 수치가 불안정해진다.
# 오버플로우를 막기위해 개선된 방법
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
입력값 a중 최대값인 c를 구한다.
입력값 a에서 최대값c를 뺀 값을 지수함수 e^x에 대입하여 지수함수 값을 계산.
그 후, 모든 지수함수 값을 더한 값을 분모로 사용해 소프트맥스 함수의 분자값을 구한다.
마지막으로 분자를 분모로 나누어 확률값 y계산, 이 확률값 중 가장 높은 값을 가지는 클래스가 소프트맥스 함수의 출력값.
3.6 배치 처리
배치란?
- 입력데이터를 하나로 묶는 것
컴퓨터는 작은 배열을 여러 번 계산하는 것 보다 큰 배열을 한 번 계산하는 것이 빠르기 때문에 배치 처리를 함으로써 한번에 업데이트.
대부분의 딥러닝 프레임워크에서 배치 처리를 지원하며, 일반적으로는 미니배치(mini-batch)라는 작은 단위로 데이터를 묶어서 처리