본문 바로가기
Data Science/문과생도 이해하는 딥러닝

문과생도 이해하는 딥러닝 (5) - 신경망 학습 실습

by 싸코 2017. 12. 26.


2017/09/27 - 문과생도 이해하는 딥러닝 (1) - 퍼셉트론 Perceptron

2017/10/18 - 문과생도 이해하는 딥러닝 (2) - 신경망 Neural Network

2017/10/25 - 문과생도 이해하는 딥러닝 (3) - 오차 역전파, 경사하강법

2017/12/24 - 문과생도 이해하는 딥러닝 (4) - 신경망구현, 활성화함수, 배치




신경망 알고리즘으로 모델을 만들고 학습하는 방법에 대해 간단하게 실습을 진행하였다. 그리고 학습할 때 필요한 필수 개념인 손실함수, 배치, 기울기, 학습률에 대해서 알아보았다. 수학적 개념만으로는 이해하기 어려운 부분들이 다소 있었으나 코드를 보면서 진행하니 확실히 각 개념과 역할에 대해서 이해하기 수월하였다.


 


신경망 학습 Learning 실습

문과생도 이해하는 딥러닝 (5)

인공신경망(Neural Network)도 다른 머신러닝 알고리즘의 모델들 같이 모델에 대한 학습이 필요하다. 지금까지 배운 것은 모델을 구축하기 위해 필요한 개념이나 기능 등에 대한 것이었다면 설계한 모델을 학습용 데이터를 가지고 어떻게 학습할 것인지 인공신경망 방식은 어떻게 학습하는 것인지 알아볼 것이다.

기본적으로 머신러닝 모델의 학습 방법은

  1. 데이터를 탐색한 후 전처리하고
  2. 데이터 변수 등을 분석하여 전체 훈련용, 테스트용 데이터 셋을 구성한 다음
  3. 해결하고자 하는 문제에 맞는 알고리즘을 선택하여 모델을 만든 후
  4. 훈련용 데이터 셋으로 모델을 학습시키고
  5. k-folds 교차검증 및 테스트용 데이터 셋 으로 모델 간 검증을 진행하고
  6. 최고의 성능을 보이는 모델을 최종 배치한다.

일반적으로 머신러닝 모델은 위와 같이 문제 해결을 위한 모델을 개발하며 딥러닝에서도 이와 크게 다르지 않다. 다만 차이점은 위에서 진행한 2번의 순서가 사라지는 특징이 있다. 다른 머신러닝은 데이터를 구성하기 위해서 변수를 선택하기도 하고 사람이 생각한 특징(features)에 따라 데이터에 대한 작업을 한 번 더 진행하지만, 신경망(딥러닝)은 데이터 그 자체에서 스스로 중요한 특징을 찾아간다는 end-to-end learning이 가능한 것이 큰 차이다. 규칙을 기계가 스스로 찾는다는 점에서 인공신경망이 더욱 재미있고 이전에 풀지 못한 문제를 풀 수 있을 것이라는 기대를 할 수 있게 되는 것이다.

딥러닝도 머신러닝과 비슷하게 학습과 검증을 해야 하기 때문에 이 기법(technique)에 대해서 좀 더 다루면 좋겠지만 다른 포스팅 시리즈에서 이 부분에 대해 더 다루는 것으로 하고 이번 포스팅 시리즈에서는 핵심개념 위주로 정리하는 식으로 다룰 것이다.

1. 손실 함수 Loss Function

딥러닝을 공부하다보면 손실 함수라는 말이 엄청 자주 나온다. 처음 모델링을 하기 위해 딥러닝을 접했을 때 이 용어가 이해를 많이 방해했었다.

손실함수는 신경망을 학습할 때 학습 상태에 대해 측정하는 하나의 지표로 사용한다. 신경망의 가중치 매개변수들이 스스로 특징을 찾아 가기에 이 가중치 값의 최적이 될 수 있도록 해야 하며 잘 찾아가고 있는지 볼 때 손실 함수를 보는 것이다.


1) 평균제곱오차 Mean Squared Error

평균제곱오차는 손실 함수로 가장 많이 쓰이며 통계를 공부한 사람이라면 자주 듣는 용어 중 하나일 것이다. 간단하게 설명하면 예측하는 값이랑 실제 값의 차이(error)를 제곱하여 평균을 낸 것이 평균제곱오차이다. 

예측 값과 실제 값의 차이가 클수록 평균제곱오차의 값도 커진다는 것은 이 값이 작을 수록 예측력이 좋다고 할 수 있다.


평균제곱오차 Mean Squared Error

def mean_squared_error(y, t):
    return 0.5*np.sum((y-t)**2)
#정답은 2
t = [0,0,1,0,0,0,0,0,0,0]

y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
print(mean_squared_error(np.array(y1), np.array(t)))

y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(mean_squared_error(np.array(y2), np.array(t)))
0.0975
0.5975


2) 교차 엔트로피 오차 Cross Entropy Error

교차엔트로피는 로그의 밑이 e인 자연로그를 예측값에 씌워서 실제 값과 곱한 후 전체 값을 합한 후 음수로 변환한다. 실제 값이 원핫인코딩(one-hot encoding; 더미변수처럼 1~9까지 범주로 했을 때 정답이 2일 경우 2에는 '1'을 나머지 범주에는 '0'으로) 방식 일경우에는 2를 제외한 나머지는 무조건 0이 나오므로 실제값일 때의 예측값에 대한 자연로그를 계산하는 식이 된다. 실제 값이 2인데 0.6으로 예측했다면 교차 엔트로피 오차는 -log(1*0.6) = -log0.6 이 된다. = 0.51

교차 엔트로피는 출력이 1일 때 0이 되며 x가 커질수록 0에 가까워지고 x가 작아질수록(0에 가까워질수록) 값이 작아진다(음의방향).


교차 엔트로피 오차 Cross Entropy Error

def cross_entropy_error(y,t):
    delta = 1e-7
    return -np.sum(t * np.log(y+delta))

y + delta인 이유는 만약 y가 0일 때는 infinite 값을 반환하므로 계산이 안되기 때문에 아주 작은 임의의 값을 입력하여 값이 -inf가 되는 것을 막는다


t = [0,0,1,0,0,0,0,0,0,0]

y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
print(cross_entropy_error(np.array(y1), np.array(t)))

y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(cross_entropy_error(np.array(y2), np.array(t)))
0.510825457099
2.30258409299

평균제곱오차에서 계산한 것과 동일하게 처음의 예측이 더 잘맞았음을 교차엔트로피 오차로 확인할 수 있다.




2. 미니배치 학습 Mini-Batch

기계학습은 앞에서 말한 것처럼 가장 예측을 잘하는 모델을 찾는 것이라고도 할 수 있다. 딥러닝에서는 가중치 매개변수에 대한 손실함수 값이 가장 작은 것은 찾아야 하므로 훈련용 데이터 셋을 대상으로 손실 함수 값을 구한다. 그리고 구한 값이 하나의 지표로 모델의 성능을 판단할 때 활용한다.

앞의 교차 엔트로피 오차에서 구한 것은 하나의 케이스(instance)에 대한 손실함수를 구한 것으로 만약 mnist 데이터와 같이 약 6만개 정도의 케이스에 대해서 학습을 할 때는 교차 엔트로피 오차를 6만번 계산해야되게 된다. 만약 실제 빅데이터 환경에 간다면 6만이 아니라 6백만, 6천만, 6억개의 데이터가 될 수도 있으며 일일이 계산한다면 굉장히 오랜 시간이 걸리게 될 것이다. 따라서 한번에 하나만 계산하는게 아니라 일부를 조금씩 가져와서 전체의 '근사치'로 이용하여 일분만 계속 사용하여 학습을 수행하는 방법을 이용한다. 그 일부를 미니배치 mini-batch 라고 한다. 훈련 데이터에서 일부를 무작위로 뽑아 학습하는 것은 미니배치 학습이다.

미니배치는 무작위로 추출하는 것으로 표본을 무작위로 샘플링하는 것과 개념적으로 유사하다.

 

미니배치 학습 Mini-Batch Learning

from mnist import load_mnist

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

print(x_train.shape)
print(t_train.shape)
(60000, 784)
(60000, 10)
train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)

x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
np.random.choice(train_size, batch_size)
array([24632, 13808, 21266, 43860, 34652, 15548, 58670, 47186, 30791, 22296])

10개에 대한 인덱스가 무작위로 추출된 모습이다



미니배치를 위한 교차 엔트로피 오차 구현

# 타겟이 one-hot encoding 방식일 경우
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    
    batch_size = y.shape[0]
    return -np.sum(t*np.log(y))/batch_size
# 타겟이 단순 레이블 형태일 경우
def cross_entropy_error(y,t):
    if y.ndim == 1:
        t = t.reshpae(1, t.size)
        y = y.reshape(1, y.size)
    
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size),t]))/batch_size


손실함수를 사용하는 이유는 궁극적으로 높은 정확도를 가진 가중치 매개변수를 구하기 위함이다. 최적의 가중치와 편향을 구할 때 손실함수의 값을 가능한 한 작게 하는 값을 찾으며 이때 미분(기울)을 계산하고 그 미분 값을 통해서 가중치와 편향에 대한 매개변수의 값을 서서히 갱신하는 과정을 반복한다.

손실함수의 미분은 가중치 매개변수의 값을 변화시켰을 때의 손실함수의 변화를 의미한다. 손실함수의 값이 음수이면 양의방향으로 값을 줄이도록 이동하고, 양수이면 음의방향으로 값을 줄이도록 이동하며 미분 값이 0이 되어 변화가 없을 때 가중치 매개변수의 갱신을 멈춘다.

매개변수의 작은 변화에 반응하여 손실함수의 값도 함께 변화해야하므로 정확도로 보는 것은 적합하지 않다. 계단함수가 0의 값을 많이 가져 이를 시그모이드 함수 같은 활성화함수로 매끄럽게 변화시키는 것과 같은 이치이다.




3. 미분

경사법에서는 기울기 값을 기준으로 방향을 정한다. 

미분은 한 순간의 변화량을 계산한 것이다. 미분에 대한 것은 따로 수학에 대해서 다루고 있는 다른 포스팅 시리즈를 참고하는 것이 좋다.



1) 수치미분


h는 시간을 뜻하고 이를 한 없이 0에 가깝게 한다는 의미로 lim를 주었다. 분자는 a에 대한 변화량을 나타낸다.

이와 같은 방식으로 미분을 구하는 것은 수치 미분이라고 한다. 차분(; 임의의 두 점에서 함수 값들의 차이)으로 미분을 구하기 때문이다. 수치 미분은 오차가 포함될 수 밖에 없다. 오차를 줄이기 위해서는 x를 중심으로 h 만큼의 함수 f의 차분을 계산하여 구하기도 하며 이를 중심 차분 또는 중앙 차분이라고 한다. 위의 식은 전방 차분을 의미한다.

해석학적으로 미분을 구하는 것은 보통 그 테크닉을 알고 있는 방법으로 수식을 이용해서 구하는 것이다.


미분 계산 예시 (수치미분)

# 중심차분, 중앙차분
def numercial_diff(f, x):
    h = 1e-4
    return (f(x+h)-f(x-h))/2*h
def function_1(x):
    return 0.01*x**2 + 0.1*x

x = np.arange(0.0, 20.0, 0.1)
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x,y)
plt.show()
# x = 5 일 때, 함수의 미분 계산
print(numercial_diff(function_1, 5))

# x = 10 일 때, 함수의 미분 계산
print(numercial_diff(function_1, 10))
1.9999999999908982e-09
2.999999999986347e-09

이렇게 계산한 미분 값이 x에 대한 f(x)의 변화량이다. 함수의 기울기를 의미한다. 해석학적으로 이를 풀이해도 0.2와 0.3으로 오차가 매우 작음을 알 수 있다. 거의 같은 값이다.



2) 편미분

변수가 여러 개인 함수에 대한 미분을 편미분이라고 한다. 

편미분 역시 변수가 하나인 미분과 동일하게 특정 장소에 대한 기울기를 구한다. 목표 변수 하나에 초점을 맞추고 다른 변수는 값을 고정한다.


미분계산 편미분 예시

def function_2(x):
    return x[0]**2 + x[1]**2
# x0 = 3, x1 = 4 일 때, x0에 대한 편미분

def function_tmp1(x0):
    return x0*x0 + 4.0**2.0

print(numercial_diff(function_tmp1, 3.0))

# x0 = 3, x1 = 4 일 때, x1에 대한 편미분
def function_tmp2(x1):
    return 3.0**2.0 + x1*x1

print(numercial_diff(function_tmp2, 4.0))
6.000000000003781e-08
7.999999999999119e-08



4. 기울기 Gradient

모든 변수의 편미분을 벡터로 정리한 것을 기울기 gradient라고 한다. 다른 포스팅에서 경사하강법에 대해 설명하면서 기울기에 대해 다루기도 했었다. 

기울기는 가장 낮은 장소를 가리키지만 각 지점에서 낮아지는 방향을 의미한다. 기울기가 가리키는 쪽은 각 장소에서 함수의 출력 값을 가장 줄이는 방향이라고 할 수 있다.


1) 경사하강법

최적의 가중치와 편향을 찾기위해서 학습을 진행하며 손실함수가 최솟값을 갖도록 하는 것이다. 가중치의 차원이 커질수록 이 손실함수의 최솟값을 갖는 지점을 찾는 것은 어려워진다. 기울기를 이용해서 함수의 최솟값이 어디에 있는지 찾는 것이며 이를 경사하강법이라고 한다.

기울기를 통해서 손실함수의 최솟값이 그쪽에 있는지 보는 것이며 최소한의 방향을 나타낸다. 최솟값이 되는 지점에서는 기울기가 0이 된다. 주의할 것은 기울기가 0이라고 반드시 그 지점이 최솟값이라고 할 수 없다. 경사하강법에서 발생할 수 있는 문제이기도 하다.

Related image

위의 그림을 보면 plateau라는 지점에서 기울기가 0이 되어 최솟값이 아님에도 최솟값으로 인식하고 학습이 중지된 상태다.

기울기 구하기

def numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)
    
    for idx in range(x.size):
        tmp_val = x[idx]
        
        #f(x+h) 계산
        x[idx] = tmp_val + h
        fxh1 = f(x)
        
        #f(x-h) 계산
        x[idx] = tmp_val - h
        fxh2 = f(x)
        
        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val
        
    return grad
# 임의의 세 점에서의 기울기 계산 (수치미분)
print(numerical_gradient(function_2, np.array([3.0, 4.0])))
print(numerical_gradient(function_2, np.array([0.0, 2.0])))
print(numerical_gradient(function_2, np.array([3.0, 0.0])))
[ 6.  8.]
[ 0.  4.]
[ 6.  0.]

Learning Rate

아래는 학습률 Learning Rate라고 하며 한 번 학습할 때 얼마만큼 학습해야 하는지 학습 양을 의미하며 한 번의 학습량으로 학습한 이후에 가중치 매개변수가 갱신된다.

displaymath1999

학습률 값은 미리 0.01, 0.001과 같이 특정 값을 정해두어야 하며 일반적으로 이 값이 너무 크거나 작으면 적합한 지점으로 찾아가기가 어렵다. 신경망 학습에서는 보통 이 학습률 값을 변경하면서 올바르게 학습하고 있는지를 확인한다.

학습률이 너무 크면 큰 값을 반환하고, 너무 작으면 거의 갱신되지 않고 학습이 끝나버린다.

학습률은 하이퍼파라미터 hyperparameter라고 부르며 가중치와 편향 같은 신경망의 매개변수와는 다르다. 가중치 등은 훈련용 데이터 셋과 학습 알고리즘에 따라 자동적으로 생성되는 것임에 비해서 학습률 같은 하이퍼파라미터는 사람이 수동적으로 설정해야 하기 때문에 시험을 통해서 가장 적절한 값을 찾아가야 한다.

기울기를 계산한 후에 기울기 값을 기존 가중치(기울기)에 더하거나 빼서 가중치를 업데이트하는데 이때 계산된 기울기에 미리 설정해둔 학습률을 곱해서 나온 값으로 가중치를 업데이트하도록 한다. 예를들어 내가 계산한 기울기 값이 +6이어서 기존의 가중치 값이 5이면 가중치의 업데이트 이후에는 -1이 된다. 하지만 학습률을 0.1로 설정하게 되면 +6 * 0.1로 0.6이 되고 이 때의 업데이트 결과는 5 - 0.6으로 4.4가 된다.

학습률이 너무 작으면 (0.00001), 5 - 0.00006 = 4.99994 가 되므로 가중치의 변화가 거의 없어 학습으로 가중치가 제대로 갱신도 되지 않고 끝나버리게 된다. 따라서 학습률을 어떻게 잡는지는 중요한 이슈이다.

학습률 Learning Rate

def gradient_descent(f, init_x, lr= 0.01, step_num=100):
    '''
    f는 최적화려는 함수
    init_x는 초깃값
    lr은 학습률
    step_num은 경사법에 따른 반복 횟수
    함수의 기울기는 앞서 정의한 numerical_gradient로 구하고
    그 기울기에 학습률을 곱한 값으로 갱신하는 처리를 setp_num번 반복
    '''
    x = init_x
    
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

학습률이 너무 크거나 작으면 좋은 결과를 얻기가 힘들다

# 학습률이 너무 큰 경우 lr = 10.0
init_x = np.array([-3.0, 4.0])
gradient_descent(function_2, init_x=init_x, lr=10.0, step_num=100)
array([ -2.58983747e+13,  -1.29524862e+12])
# 학습률이 너무 작은 경우 lr = 1e-10
init_x = np.array([-3.0, 4.0])
gradient_descent(function_2, init_x=init_x, lr=1e-10, step_num=100)
array([-2.99999994,  3.99999992])


2) 신경망에서의 기울기

신경망 학습도 기울기를 구해야 하며 여기서의 기울기는 가중치 매개변수에 대한 손실 함수의 기울기이다. 


신경망에서의 기울기

from scratch.common.functions import softmax, cross_entropy_error
from scratch.common.gradient import numerical_gradient

class simpleNet:
    def __init__(self):
        self.W = np.random.randn(2,3)
    
    def predict(self, x):
        return np.dot(x, self.W)
    
    def loss(self,x, t):
        z = self.predict(x)
        y = softmax(z)
        loss = cross_entropy_error(y, t)
        
        return loss
net = simpleNet()
print(net.W)
[[-0.98857721 -1.19498403  1.7798275 ]
 [ 1.92945432  2.08198445  0.48024869]]
x = np.array([0.6, 0.9])
p = net.predict(x)
print(p)
np.argmax(p)
[ 1.14336256  1.15679559  1.50012032]
2
t = np.array([0,0,1])
net.loss(x, t)
0.87935693550588223
def f(W):
    return net.loss(x, t)

dW = numerical_gradient(f, net.W)
print(dW)

[[ 0.17430645  0.17666371 -0.35097016]
 [ 0.26145968  0.26499557 -0.52645524]]






5. 학습 알고리즘 구현

1) 전제

신경망에는 적응 가능한 가중치와 편향... 가중치와 편향을 훈련 데이터에 적응하도록 조정하는 것이 '학습'.

2) 1단계: 미니배치

훈련 데이터 중 일부 무작위 추출. 미니배치의 손실 함수를 줄이는 것을 목표

3) 2단계: 기울기 산출

미니배치 손실 함수 값을 줄이기 위해 가중치 매개변수의 기울기 구함. 기울기는 손실 함수의 값을 최소화하는 방향을 가리킴

4) 3단계: 매개변수 갱신

가중치 매개변수 기울기 방향으로 조금 갱신

5) 1~3 단계 반복


이러한 학습 방법을 stochastic gradient descent(확률적 경사 하강법)이라고 하며 많이들 들어봤을 것이다.


학습 횟수가 늘어날수록 손실 함수의 값이 떨어진다면 이는 신경망의 가중치들이 학습 데이터에 잘 맞아들고 있음을 의미하며 이를 학습이 잘되고 있다고 볼 수 있다.



신경망 모델 클래스 생성


2층 신경망 클래스 구현

from scratch.common.functions import *
from scratch.common.gradient import numerical_gradient

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)
    
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        return y
    
    def loss(self, x, t):
        y = self.predict(x)
        
        return cross_entropy_error(y, t)
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis = 1)
        t = np.argmax(t, axis = 1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
    
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads
net = TwoLayerNet(input_size=784, hidden_size=100, output_size=10)
net.params['W1'].shape  # (784, 100)
net.params['b1'].shape  # (100,)
net.params['W2'].shape  # (100, 10)
net.params['b2'].shape  # (10,)
(10,)


예제로 2층 신경망 학습시켜보기

nuemrical_gradient는 수치미분으로 기울기를 계산하기 때문에 계산이 오래 걸린다. 신경망이 그렇게 복잡하지 않음에도 상당한 시간이 소요됐다.


x = np.random.rand(100, 784)
t = np.random.rand(100, 10)

%time grads = net.numerical_gradient(x, t)

print(grads['W1'].shape)
print(grads['b1'].shape)
print(grads['W2'].shape)
print(grads['b2'].shape)
CPU times: user 3min 49s, sys: 564 ms, total: 3min 50s
Wall time: 57.7 s
(784, 100)
(100,)
(100, 10)
(10,)



검증 testing

하지만 오버피팅의 문제가 있을 수 있으므로 이를 확인하기 위해서 테스트 데이터를 통해서 일반적으로 잘 들어맞는지 확인할 필요가 있다. 오버피팅overfitting은 학습한 모델이 학습 데이터에만 잘들어 맞고 다른 실제 상황에서 잘 맞지 않음을 말한다.


이를 위해서 하나의 epoch 단위 별로 훈련 데이터와 테스트 데이터에 대한 모델의 정확도를 확인할 필요가 있다.



Epoch 에포

에포는 하나의 학습 단위인데 1 에포는 학습에서 훈련 데이터를 가지고 훈련을 모두 완료했을 때를 말하며, 즉 학습 횟수를 의미한다. 예를 들어 1000개에 대한 훈련 데이터를 10개의 미니배치로 학습한다면 확률적 경사하강법을 100회 반복해서 가중치를 계산하고 나서 100*10=1000으로 학습이 완료되고 이 때의 100회가 1 에포가 되며 학습이 한 번 됐다고 하는 것이다.


미니배치를 위한 학습을 구현했을 때 변수에 대해서 설명하자면

  • iter_num : 가중치 갱신을 몇 번 하는지
  • train_size : train 데이터의 총 개수
  • batch_size : 한 번에 학습을 다하기 어려우니 나누어서 갱신을 하는데 이때 미니배치를 사용하며 배치 사이즈는 몇 개씩 뽑아서 쓸 것인지... 한 번의 기울기 갱신에 몇 개의 train 데이터를 사용할 것인지 그 개수를 의미
  • epoch : 하나의 단위로 train_size/batch_size로 구하며 하나의 미니배치에 대해서 갱신을 몇 번 해야 전체 train 데이터에 대해서 한 번의 학습이 가능한지를 나타낸다. 100개의 train_size에 batch_size가 10이면 10번의 iter로 한 번의 학습이 가능하므로 epoch는 10이 된다. 10번 미니배치를 추출해서 기울기 계산과 가중치를 업데이트하면 한 번 전체 train 데이터에 대해서 학습했다고 볼 수 있다.
  • # of epochs : 총 iter(기울기 계산, 가중치 업데이트) 횟수를 epoch의 단위로 나누면 전체 train 데이터에 대해서 몇 번 학습했는지 알 수 있다. 예를 들어 10,000개의 데이터에 대해서 가중지 업데이트를 1,000번 한다고 했을 때, 배치 사이즈를 1,000이라고 한다면 epoch 단위는 10이 된다. 따라서 # of epochs는 100번(= 1,000/10)이 된다. 학습은 총 10번 하게 되는 것이다.



예제로 미니배치와 에포를 이용해서 학습을 한 결과는 학습이 끝나고 업로드하겠다.

생각보다 계산량이 많아서 기울기 계산과 가중치 업데이트에 시간이 오래걸린다.









기본적인 신경망이 학습이 정말 오래 걸린다는 것을 깨달았다. 이러한 문제를 해결하기 위해서 오차역전파 방법이 빠르게 기울기를 계산할 수 있도록 한다고 하니 다음 포스팅에서 이를 다루도록 하겠다.



댓글