[밑바닥부터 시작하는 딥러닝] 3. 신경망 part2 - 출력층 설계, MNIST 데이터 인식, 배치

Yejin Kim·2022년 3월 4일
0
post-thumbnail

🌿 출력층 설계

어떤 문제를 푸느냐에 따라 출력층에서의 활성화 함수가 달라짐

기계학습 문제는 분류(classification)회귀(regression) 로 나뉨
분류 : 데이터가 어느 클래스(class)에 속하느냐는 문제 (ex. 사진 속 인물의 성별 분류)
회귀 : 입력 데이터에서 연속적인 수치를 예측하는 문제 (ex. 사진 속 인물의 몸무게 예측)

📍 항등 함수

identity function
항등 함수는 입력을 그대로 출력
그래서 출력층에 항등 함수를 사용하면 입력 신호가 그대로 출력 신호가 됨

📍 소프트맥스 함수

softmax function

exp(x)는 e^{x}를 뜻하는 지수 함수

n : 출력층의 뉴런 수
yk : 그 중 k번째 출력

분자는 입력 신호의 지수 함수, 분모는 모든 입력 신호의 지수 함수의 합!


분모에서 알 수 있듯이 출력층의 각 뉴런이 모든 입력 신호에서부터 영향을 받는다.

소프트맥스 함수의 구현은 다음과 같다.

def softmax(a):
	exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y

🚨 소프트맥스 함수 구현 시 주의점

softmax 함수는 컴퓨터로 계산 시 오버플로 문제가 발생할 수 있다.
따라서 다음과 같이 개선하는 것이 좋다.

여기서 입력 신호 중 최댓값을 빼주는 방식으로 계산이 진행될 수 있도록 C의 값을 선택하면 올바른 계산이 이루어질 수 있다.

소프트맥스 함수의 특징

  • 출력은 0에서 1.0 사이의 실수
  • 소프트맥스 함수 출력의 총합이 1

출력의 총합이 1이라는 성질 덕분에 소프트 맥스 함수의 출력을 '확률'로 해석할 수 있다.

신경망을 이용한 분류에서는 일반적으로 가장 큰 출력을 내는 뉴런에 해당하는 클래스로 인식
소프트맥스 함수를 적용해도 출력이 가장 큰 뉴런의 위치는 달라지지 않으므로
신경망으로 분류할 때에는 소프트함수 맥스를 생략해도 됨

기계학습의 문제 풀이는 학습추론의 두 단계를 거쳐 이뤄짐
학습 → 모델을 학습
추론 → 학습한 모델로 미지의 데이터에 대해 추론(분류) 수행


🌿 손글씨 숫자 인식

MNIST 데이터셋이라는 손글씨 숫자 이미지 집합을 이용한다.

🔢 MNIST 데이터셋

MNIST 데이터셋은 0부터 9까지의 숫자 이미지로 구성됨

MNIST 이미지 데이터는 28x28 크기의 회색조 이미지이며,
각 픽셀은 0에서 255까지의 값을 취한다.

다음의 코드를 통해 MNIST 데이터를 쉽게 가져올 수 있다.

import sys 
import os
sys.path.append(os.pardir) # 부모 디렉토리의 파일을 가져올 수 있도록 설정
from dataset.mnist import load_mnist # dataset 폴더의 mnist파일에서 load_mnist 함수 import

(x_train, t_train), (x_test, t_test) = \
    load_mnist(flatten=True, normalize=False)

# 각 데이터의 형상 출력
print(x_train.shape)
print(t_train.shape)
print(x_test.shape)
print(t_test.shape)

load_mnist 함수는 MNIST 데이터를
"(훈련 이미지, 훈련 레이블), (시험이미지, 시험 레이블)"의 형식으로 반환한다.

인수
normalize : 입력 이미지의 픽셀 값을 0.0~1.0 사이의 값으로 정규화 할지 정함
flatten : 입력 이미지를 1차원 배열로 만들지 정함 (False → 1x28x28(3차원), True →784(1차원))
one_hot_label : 원-핫 인코딩 형태로 저장할 지 정함

** 원-핫 인코딩은 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]처럼 정답을 뜻하는 원소만 1이고 나머지는 0인 배열

아래의 코드로 MNIST 이미지를 화면으로 부를 수 있다.

import sys 
import os
import numpy as np
sys.path.append(os.pardir)
from dataset.mnist import load_mnist
from PIL import Image

def img_show(img):
    pil_img = Image.fromarray(np.uint8(img)) # 넘파이로 저장된 이미지 데이터를 PIL용 데이터 객체로 변환
    pil_img.show()
    
(x_train, t_train), (x_test, t_test) = \
    load_mnist(flatten=True, normalize=False)
    
img = x_train[0]
label = t_train[0]
print(label)

print(img.shape)
img = img.reshape(28,28) # 원래 이미지 모양으로 복구
print(img.shape)

img_show(img)

신경망의 추론 처리

MNIST 데이터셋은 이미지 크기가 28x28=784이고, 0부터 9까지의 숫자를 구분해야 하므로
입력층 뉴런을 784, 출력층 뉴런을 10개로 구성

순서대로 작업을 처리해줄 세 함수는 다음과 같다.

def get_data():    
    (x_train, t_train), (x_test, t_test) = \
        load_mnist(flatten=True, normalize=False, one_hot_label=False) # 1차원 넘파이 배열로 저장
    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 = sigmoid(a1)
    a2 = np.dot(z1,W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2,W3) + b3
    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)
    
    # 정답을 맞춘 case를 count
    if p == t[i]:
        accuracy_cnt += 1

print('Accuracy:' + str(float(accuracy_cnt)/len(x)))

배치 처리

하나로 묶은 입력 데이터를 배치(batch)라고 한다.

배치 처리는 컴퓨터로 계산 시 이미지 1장당 처리 시간을 대폭 줄여주는 이점이 있다.

  • 수치 계산 라이브러리 대부분이 큰 배열을 효율적으로 처리할 수 있도록 고도로 최적화되어 있기 때문
  • 큰 신경망에서는 데이터 전송이 병목으로 작용하는 경우가 자주 있는데, 배치 처리를 통해 버스에 주는 부하를 줄일 수 있음

앞에서 진행한 MNIST 데이터셋에 배치 처리를 적용하면 다음과 같이 처리가 가능하다.

x, t = get_data()
network = init_network()

batch_size = 100 # 배치 크기
accuracy_cnt = 0

for i in range(0,len(x), batch_size): # 0부터 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)))
profile
The World Is My Oyster 🌏

0개의 댓글