※ 본 글은 한경훈 교수님의 머신러닝 강의를 정리, 보충한 글입니다. ※
(5) [딥러닝I] 5강. 신경망 구현 - YouTube
신경망 구현
MNIST 신경망을 우리가 만든 3층 퍼셉트론의 구조로 구현해보자.
📣 MNIST 신경망의 작동 원리
입력층에서 28*28(784) 차원의 벡터를 입력받아
affine 과 sigmoid 연산을 거치고 최종적으로 softmax 를 이용해 확률벡터를 출력해야 한다.
확률벡터에 argmax함수를 적용하면 확률벡터 중 값이 가장 큰 인덱스를 얻을 수 있는데,
확률벡터의 인덱스는 0-9 이고 확률벡터의 의미는 '데이터가 해당 정수일 확률'을 의미하므로
argmax에서 얻은 인덱스 값이 곧 모델이 예측한 정수이다.
마지막으로 예측한 정수와 테스트 데이터의 값을 비교하면 모델이 제대로 돌아가고 있는지를 확인할 수 있다.
📣 복습
affine : 가중치(w)*입력(x) + 편향(b)
sigmoid : 1/(1+exp(-x))
softmax : 벡터를 확률벡터로 변환. 0과 1사이 값으로 변환하므로 정규화(normalize)한다고도 한다.
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False) # flatten = true 로 행렬을 벡터로 변환
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']
# Affine
a1 = np.dot(x, W1) + b1
# Sigmoid
z1 = sigmoid(a1)
# Affine
a2 = np.dot(z1, W2) + b2
# Sigmoid
z2 = sigmoid(a2)
# Affine
a3 = np.dot(z2, W3) + b3
# Softmax - 0-9까지 10개의 결과 중 가장 확률이 높은걸 가려내야 하므로, 확률벡터를 만드는 softmax 사용.
y = softmax(a3)
return y
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p= np.argmax(y) # 값이 가장 큰 즉, 확률이 가장 높은 원소의 인덱스를 얻는다.
if p == t[i]:
accuracy_cnt += 1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
네트워크 모양
가중치, 편향의 모양을 확인하기 위해 shape 함수를 사용한다.
network = init_network()
keys = ['W1', 'W2', 'W3', 'b1', 'b2', 'b3']
for key in keys:
print(key, 'shape : ', network[key].shape)
#---- 출력 -----#
# W1 shape : (784, 50) # 784개의 입력마다 각각의 50개의 가중치가 있음.
# W2 shape : (50, 100)
# W3 shape : (100, 10)
# b1 shape : (50,)
# b2 shape : (100,)
# b3 shape : (10,)
# 총 parameter 개수 : 784×50 + 50 + 50×100 + 100 + 100×10 + 10
# = 45360
배치 처리
위의 계산은 이미지를 한장씩 입력받아 학습하는데, 이는 상당히 비효율적이다.
데이터를 하나씩 처리하게 되면 I/O를 통해 데이터가 처리되는데 이는 CPU와 GPU의 병렬처리보다 오래 걸리기 때문이다.
또한 수치 계산 라이브러리 대부분이 큰 배열을 효율적으로 처리할 수 있도록 최적화되어 있기 때문에
한번에 여러 데이터를 학습하는 것이 더 효율적이다.
하지만, 전체 데이터를 한번에 학습하면 학습하는데에 시간이 오래걸리고 학습을 1회만 할 수 있다는 단점을 가지고 있다.
위의 문제점을 해결할 수 있는 것이 바로 배치 처리이다.
배치 처리는 배치사이즈만큼 데이터를 그룹화하여 하나의 그룹(배치)씩 학습하게하는 방법을 말한다.
배치 처리를 적용한 데이터 예측
x, t = get_data()
network = init_network()
batch_size = 100 # 100개를 한번에 처리
accuracy_cnt = 0
for i in range(0, len(x), batch_size): # i가 0부터 x의 크기(테스트 이미지 만장)까지 100씩 건너뜀
x_batch = x[i:i+batch_size] # x[0] ~ x[99], x[100] ~ x[199], ...
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
# axis=1 이므로 행에 대해 argmax 적용.
# cf. argmax 전 모양 : (100, 10) / argmax 후 모양 : (100,)
# 데이터 하나에 대해 10차원 벡터를 argmax에서 스칼라로 바꾸므로 행렬이 벡터로 바뀐다.
accuracy_cnt += np.sum(p == t[i:i+batch_size])
print("Accuracy: " + str( accuracy_cnt / len(x))) # Accuracy: 0.9352
배치처리를 적용한 softmax
def softmax(x):
if x.ndim == 2: # x의 차원이 2이면, 배치로 들어왔음을 의미함 (100,10)
x = x.T # x를 transpose -> (10,100)
x = x - np.max(x, axis=0) # transpose 했으므로 열에 대해 max를 구해서 overflow 방지
y = np.exp(x) / np.sum(np.exp(x), axis=0) # softmax 적용
return y.T # y를 transepose -> (100,10)
x = x - np.max(x) # 배치로 들어오지 않았을 때는 일반 softmax 적용
return np.exp(x) / np.sum(np.exp(x))
'ML' 카테고리의 다른 글
[ML] 딥러닝 1 - 7강 엔트로피 (0) | 2021.07.29 |
---|---|
[ML] 딥러닝 1 - 6강 손실함수 (0) | 2021.07.23 |
[ML] 딥러닝 1 - 4강 MNIST (0) | 2021.07.17 |
[ML] 딥러닝 1 - 3강 인공신경망 (0) | 2021.07.14 |
[ML] 딥러닝 1 - 2강 활성화 함수 (1) | 2021.07.13 |