퍼셉트론을 쌓음으로써 복잡한 함수(선형적 + 비선형적)를 표현할 수 있다는 것을 확인했다. 하지만 우리가 직접 W,b(가중치)를 정해줘야 한다는 점이 큰 단점으로 작용한다. 이를 해결하기 위해 등장한 신경망은 데이터로부터 가중치의 매개변수 값을 자동적으로 학습한다. 이번 장은 신경망의 학습 방법에 대해 알기 전에 신경망의 개요와 입력 데이터를 식별하고 처리하는 과정에 대해 기초부터 개괄적으로 알려주고 있다.
1. 퍼셉트론과 비슷한 딥러닝 신경망
이전 장에서 배웠던 퍼셉트론은 신경망과 공통점이 많다. 하지만 차이점도 명확한데 이를 중점으로 보여준다..!
공통점은 노드가 서로 연결되어 임계값을 정해줄 활성화 함수를 사용하여 그 출력값을 다음 노드로 전달한다는 점이다.
반면 차이점은 퍼셉트론은 이를 위해 사람이 직접 가중치 값을 알맞게 조정해야 했으나 신경망은 가중치 매개변수가 데이터로부터 학습한다는 점이다.
이를 살펴보기 전에 우선은 신경망이 어떻게 생겼고, 활성화 함수가 어떤 것인지 알아보자.
신경망은 다음과 같이 도식화 할 수 있다.
노드와 노드가 서로 연결되어 있는 구조이다.
퍼셉트론과 크게 다를게 없다!
그럼 다음 노드로 신호를 전달할 때는 어떨까?
퍼셉트론은 신호를 전달할 때 가중치(w)와 편향(b)를 통해 신호의 영향력을 제어했다.
신경망도 활성화 함수라는 입력신호를 출력신호로 변환하는 함수를 사용하여 신호에 변환을 일으킨다.
활성화 함수를 쓰는 이유는 앞선 챕터에서 본 것 처럼 비선형적 표현을 하기 위함이다.
각 활성화 함수를 구현한 코드를 확인해보자.
# 다양한 활성화 함수 구현하기
#계단함수
def stepf(x):
if x > 0:
return 1
else:
return 0
#시그모이드 함수
import numpy as np
def sigmoidf(x):
return 1 / (1+np.exp(-x))
#relu 함수
def reluf(x):
return np.maximum(0,x)
#softmax함수
def softmaxf(x):
exp_x = np.exp(x)
sum_exp = np.sum(exp_x)
y = exp_x / sum_exp
return y
2. 퍼셉트론과 다른 딥러닝 신경망
이번에는 다른 점에 대해 좀더 면밀히 살펴보고 mnist dataset으로 딥러닝 추론을 구현해보자.
이를 이해하기 위해서는 다차원 배열의 계산 방식에 대해 알아야한다.
2-1 다차원 배열의 계산
다차원 배열이란 숫자가 n차원 배열로 있는 것을 의미한다.
가령, 스칼라 벡터값은 1차원 배열을 가지고 2차원 배열은 행렬이 된다.
이 중 가장 딥러닝에서 기본이되는 계산은 행렬의 내적(곱)이 된다.
행렬의 내적에서 체크해야 하는 가장 기본적인 것은 1. 조건을 만족하는가와 2.결과값은 어떤 shape를 가지고 있는가이다.
우선 1에 대해서는 왼쪽 행렬의 행(가로)의 크기와 오른쪽 행렬의 열(세로)의 크기를 맞춰줘야 한다는 것이다.
예를들어 (2,3) * (3,7)는 행과 열의 크기가이 3으로 같기 때문에 행렬의 곱을 할 수 있다.
반면 그 반대면 못할 것이다.((3,7) * (2,3) -> 7은 2와 다르다!)
2에 대해서는 조건으로 본 행, 열을 제외하고 붙여주면 결과값의 shape가 된다는 것을 알면 된다.
위의 예시 (2,3) * (3,7)의 결과 행렬의 크기는 (2,7)이 될 것 이다.
파이썬에서는 numpy의 dot()모듈로 구현해놨다.
2-2 3층 신경망 구현하기
다차원 배열의 계산 방식에 대해 알았으면 실제로 간단한 신경망을 구현할 수 있다!
3층 신경망을 구현해봤다.
입력층 - 은닉층1 - 은닉층2 - 출력층으로 구성된 3층 신경망이다.
def init_network():
network = {}
network['W1'] = np.array([[1,3,5],[2,4,6]])
network['b1'] = np.array([1,2,3])
network['W2'] = np.array([[2,3,5],[6,3,6]])
network['b2'] = np.array([1,2,4])
network['W3'] = np.array([[6,8,2],[2,7,6]])
network['b3'] = np.array([1,2,6])
return network
def forward(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W2']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
#forward(행렬곱 + activation)
a1 = np.dot(x,W1) + b1
z1 = sigmoidf(a1)
a2 = np.dot(z1,W2) + b2
z2 = sigmoidf(a2)
a3 = np.dot(z2,W3) + b3
y = a3
return y
network = init_network()
x = np.array([13,5])
y = forward(network, x)
print(y.shape)
입력값과 넣어준 가중치는 임의로 썼기 때문에 의미가 없다.
2-3 mnist 추론 처리
mnist dataset은 0~9까지의 손글씨 데이터 셋이다.
keras에서 제공하여 직접 임포트 할 수 있으며, cv에 입문할 때 가장 처음 보는 유명한 데이터 셋이다!
(28,28,1)의 크기를 가지고 있다.(픽셀 가로, 세로, 채널(흑백색))
keras에서 mnist dataset을 임포트하여 아까 3층 신경망처럼 구현해보자.
이 때는 학습이 아니기 때문에 가중치 매개변수가 알아서 변하지 않는다.
다만 학습이 완료된 (가중치 매개변수가 다 변하고 고정된) 가중치 파일을 가져와 추론한다.
코드는 다음과 같다.
# mnist dataset으로 신경망 추론처리
# 28 * 28크기의 입력크기 / 10개의 예측값
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록
import numpy as np
import pickle
from keras.datasets import mnist
def get_data():
(x_train, t_train), (x_test, t_test) = mnist.load_data()
return x_test, t_test
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
def predict(network, x):
w1, w2, w3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
a1 = np.dot(x, w1) + b1
z1 = sigmoidf(a1)
a2 = np.dot(z1, w2) + b2
z2 = sigmoidf(a2)
a3 = np.dot(z2, w3) + b3
y = softmaxf(a3)
return y
#배치처리 + test data로 추론하기
#가중치가 저장되어 있는 파일이 있어야 함. (init_network())
x, t = get_data()
network = init_network()
batch_size = 100 # 배치 크기
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
x_batch = x[i:i+batch_size]
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i+batch_size])
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
한 줄 정리: 신경망을 통해 가중치 매개변수를 학습시켜 적절한 값으로 바꿀 수 있다!
'Book Review > [밑바닥부터 시작하는 딥러닝 1] 리뷰' 카테고리의 다른 글
5장. 오차역전파법 (0) | 2023.11.09 |
---|---|
4장. 신경망 학습 (0) | 2023.10.04 |
2장. 퍼셉트론 (1) | 2023.09.17 |