본문 바로가기

ML

[ML] 딥러닝 1 - 5강 신경망 구현

※ 본 글은 한경훈 교수님의 머신러닝 강의를 정리, 보충한 글입니다. ※

(5) [딥러닝I] 5강. 신경망 구현 - YouTube

 


신경망 구현

MNIST 신경망을 우리가 만든 3층 퍼셉트론의 구조로 구현해보자.

 

📣 MNIST 신경망의 작동 원리

입력층에서 28*28(784) 차원의 벡터를 입력받아

affinesigmoid 연산을 거치고 최종적으로 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