728x90
반응형

 이전 포스트까지 모델 컴파일에 대해 알아보았다. 이번 포스트에서는 모델을 학습에 대해 자세히 알아보도록 하자.

 

 

모델 학습과 학습 과정 확인

0. 이전 코드 정리

# Import module
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import (Dense, BatchNormalization, Dropout, Flatten)
from tensorflow.keras.datasets.mnist import load_data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Dataset 준비
(train_images, train_labels), (test_images, test_labels)= load_data()

# 무작위로 샘플 추출
np.random.seed(1234)
index_list = np.arange(0, len(train_labels))
valid_index = np.random.choice(index_list, size = 5000, replace = False)

# 검증셋 추출
valid_images = train_images[valid_index]
valid_labels = train_labels[valid_index]

# 학습셋에서 검증셋 제외
train_index = set(index_list) - set(valid_index)
train_images = train_images[list(train_index)]
train_labels = train_labels[list(train_index)]

# min-max scaling
min_key = np.min(train_images)
max_key = np.max(train_images)

train_images = (train_images - min_key)/(max_key - min_key)
valid_images = (valid_images - min_key)/(max_key - min_key)
test_images = (test_images - min_key)/(max_key - min_key)
# 모델 생성
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28], name="Flatten"))
model.add(Dense(300, activation="relu", name="Hidden1"))
model.add(Dense(200, activation="relu", name="Hidden2"))
model.add(Dense(100, activation="relu", name="Hidden3"))
model.add(Dense(10, activation="softmax", name="Output"))
# 모델 컴파일
opt = keras.optimizers.Adam(learning_rate=0.005)
model.compile(optimizer = opt,
              loss = "sparse_categorical_crossentropy",
              metrics = ["accuracy"])

 

 

 

 

1. 모델 학습

# 모델 학습하기
history = model.fit(train_images, train_labels,
                    epochs=100,
                    batch_size = 5000,
                    validation_data=(valid_images, valid_labels))
Epoch 1/100
11/11 [==============================] - 2s 185ms/step - loss: 1.5537 - accuracy: 0.4795 - val_loss: 0.4806 - val_accuracy: 0.8638
Epoch 2/100
11/11 [==============================] - 1s 52ms/step - loss: 0.3852 - accuracy: 0.8864 - val_loss: 0.2727 - val_accuracy: 0.9204
Epoch 3/100
11/11 [==============================] - 1s 53ms/step - loss: 0.2276 - accuracy: 0.9327 - val_loss: 0.1879 - val_accuracy: 0.9406
Epoch 4/100
11/11 [==============================] - 1s 53ms/step - loss: 0.1617 - accuracy: 0.9522 - val_loss: 0.1460 - val_accuracy: 0.9558
Epoch 5/100
11/11 [==============================] - 1s 52ms/step - loss: 0.1213 - accuracy: 0.9650 - val_loss: 0.1222 - val_accuracy: 0.9618

...

Epoch 96/100
11/11 [==============================] - 1s 54ms/step - loss: 2.8528e-05 - accuracy: 1.0000 - val_loss: 0.1078 - val_accuracy: 0.9804
Epoch 97/100
11/11 [==============================] - 1s 59ms/step - loss: 2.9069e-05 - accuracy: 1.0000 - val_loss: 0.1080 - val_accuracy: 0.9806
Epoch 98/100
11/11 [==============================] - 1s 56ms/step - loss: 2.7108e-05 - accuracy: 1.0000 - val_loss: 0.1082 - val_accuracy: 0.9806
Epoch 99/100
11/11 [==============================] - 1s 51ms/step - loss: 2.8243e-05 - accuracy: 1.0000 - val_loss: 0.1086 - val_accuracy: 0.9806
Epoch 100/100
11/11 [==============================] - 1s 50ms/step - loss: 2.6565e-05 - accuracy: 1.0000 - val_loss: 0.1086 - val_accuracy: 0.9804
  • 이전 포스팅까지는 model.fit(train_set, train_label, epochs)만 설정하였었으나, 이번 포스팅에서는 model.fit(train_set, train_label, epochs, batch_size, validation_data)로 처음 보는 인자들이 여럿 등장한 것을 볼 수 있다.
  • train_set, train_label, epochs는 여러 번 본 인자이므로 넘어가고, batch_size와 validation_data를 위주로 설명해보겠다.
  • 아직 epochs에 대한 개념이 헷갈린다면 다음 포스팅을 참고하기 바란다.
    참고: "머신러닝-6.2. 최적화(3)-학습단위(Epoch, Batch size, Iteration)

 

 

 

 

2. Batch size

  • model.fit() 함수 안에 batch_size라는 인자가 추가된 것을 볼 수 있다.
  • batch_size는 전체 데이터셋을 한 번에 학습시키자니, 데이터가 너무 크기 때문에 메모리 과부하와 속도 저하 문제가 발생하므로, 데이터를 Batch size만큼 쪼개서 학습을 시키는 것을 의미한다.
  • 학습 단위에 대한 보다 자세한 설명은 다음 포스팅을 참고하기 바란다.
  • Batch size는 전체 데이터셋을 Batch size로 나눴을 때, 나머지가 생기지 않은 크기로 만드는 것이 좋다.
  • Batch size를 너무 크게 하면, 메모리 과부하가 발생하기 쉬우나, 더 많은 데이터를 보고 파라미터를 결정하므로 학습이 안정적으로 진행된다.
  • Batch size를 너무 작게 하면, 자주 파라미터 갱신이 발생하므로 학습이 불안정해진다.
  • Batch size를 얼마나 잡느냐에 대해선 정답이 없다고 할 수 있는데, 어떤 사람들은 자신의 머신이 가진 메모리를 넘지 않는 선에서 Batch size를 최대로 잡는 것이 좋다고 하고, 또 다른 사람은 32보다 큰 미니배치를 사용해선 절대 안된다고도 했다.
  • 양쪽 다 주장이 꽤 탄탄하므로, 미니 배치를 크게도 해보고 작게도 해보며, 결과를 비교해보도록 하자.

 

2.1. Batch size의 효과

  • Batch size는 학습에 걸리는 시간과 학습에 소모되는 메모리에 큰 영향을 미친다.
  • 얼마나 차이가 나는지 확인하기 위해 Batch size를 설정하지 않은 학습과 설정하지 않은 학습을 비교해보도록 하자.

 A. Batch size를 지정하지 않는 경우

from time import time
start = time()

history = model.fit(train_images, train_labels,
                    epochs=100,
                    validation_data=(valid_images, valid_labels))
...
>>> print("코드 동작 시간: {} minutes".format(round((time() - start)/60, 2)))
코드 동작 시간: 6.39 minutes
  • time 모듈의 time() 함수는 1970년 1월 1일 0시 0분 0초 이후 경과한 시간을 초 단위로 반환하는 함수로, time함수의 차를 이용해서, 특정 구간에서 소모된 시간을 알 수 있다.
  • Batch size를 사용하지 않고, 모든 데이터를 한 번에 학습시키는 경우, 6.39분이 소모된 것을 볼 수 있다.

B. Batch size를 지정한 경우

start = time()

history = model.fit(train_images, train_labels,
                    epochs=100,
                    batch_size=5000,
                    validation_data=(valid_images, valid_labels))
...
>>> print("코드 동작 시간: {} minutes".format(round((time.time() - start)/60, 2)))
코드 동작 시간: 1.0 minutes
  • Batch size를 사용하자, 학습에 소모된 시간이 1.0분으로 6배 이상 감소한 것을 볼 수 있다.
  • 이번에 학습에 사용한 MNIST는 그다지 큰 데이터도 아님에도 소모 시간 차이가 이렇게 크게 발생한 것을 볼 때, 이보다 더 큰 데이터를 다루게 되는 실제 상황에서 Batch size 지정은 필수임을 알 수 있다.

 

 

 

 

3. validation data

  • 이전 학습에서 validation_data를 지정하지 않았듯, 검증 셋을 지정하지 않아도 학습을 하는 데는 문제가 없지만, 검증 셋이 존재한다면, 매 학습 때마다 모델을 평가하여, 최적의 모델을 만들어내는데 큰 도움이 된다.
  • 검증 셋에 대해 헷갈리는 분을 위해 이전 포스트 링크를 걸어놓도록 하겠다.
    (참고: "Tensorflow-3.2. 이미지 분류 모델(2)-검증 셋(Validation set)")
  • validation data는 위 방법처럼 검증 셋을 미리 뽑고, 학습을 진행하는 방법도 있지만 자동으로 검증 셋을 뽑아놓는 방법도 존재한다.
  • model.fit() 함수의 파라미터에 validation_split이라는 인자가 존재하는데, 이는 float으로 지정할 수 있으며, 데이터를 섞기(Shuffle) 전에 지정한 비율만큼의 데이터를 검증 셋으로 사용한다.
  • 그러나, 참고 포스팅에서 보듯 검증 셋을 대표성 있게 추출하는 것은 매우 중요하므로, 사전에 검증 셋을 미리 추출하는 것을 추천한다.
  • 이밖에도 validation_steps, validation_batch_size, validation_freq와 같은 검증 셋 관련 파라미터들이 더 존재하지만, 이들에 대해서는 추후 다루도록 하겠다.

 

 

 

 

 지금까지 모델의 학습(Fit)에 대해 알아보았다. 이전에 fit()에 사용했던 파라미터들은 학습을 위해 필요한 최소한의 파라미터들이었다면, 이번에 사용한 파라미터들은 가장 일반적으로 사용되는 파라미터들이다. 

 fit() 함수는 이밖에도 샘플별 가중치 조정(sample_weight)이나, 특정 클래스에 대한 가중치 조정(class_weight)과 같은 다양한 기능들을 더 가지고 있다. 그러나, 이들까지 모두 다루기는 쉽지 않고, 이번에 다룬 내용만 알더라도 Tensorflow를 적당히 다루는데 지장이 없으므로, 여기까지 학습을 하고, 나중에 필요하다면 더 자세히 다뤄보도록 하겠다.

 다음 포스트에선 학습 과정에서 나온 Log들을 분석하는 History 객체의 사용법에 대해 학습해보도록 하겠다.

728x90
반응형
728x90
반응형

 이전 포스트에서는 경사 하강법의 한계점에 대해 학습해보았다. 이번 포스트에서는 경사 하강법의 실행 과정을 살펴보고, 기본 사용 방법인 배치 경사 하강법(Batch Gradient Descent)이 어떤 단점을 가지고 있기에 최적화 기법의 기반이 되는 경사 하강법인 확률적 경사 하강법(Stochastic Gradient Descent, SGD)이 나오게 되었는지를 알아보고자 하였으나, 이 과정을 쉽게 이해하려면 먼저 학습이 일어나는 구조와 학습 단위에 대한 개념을 알아야 한다.

 

 

1. 학습의 구조

  • 학습은 기본적으로 다음과 같은 구조로 움직인다.
  1. 임의의 매개변수(가중치)를 정한다.
  2. 선택된 매개변수로 손실 값을 구하고, 손실 함수의 기울기(Gradient)를 계산한다.
  3. 계산된 기울기와 학습률(Learning Rate)을 이용해 다음 가중치의 위치로 이동하여, 파라미터를 업데이트한다.
    이때, 이동 거리는 경사 하강법 공식을 통해 구해진다.
    $$ \theta_{n+1} = \theta_n - \eta \bigtriangledown f(\theta_n) $$
  4. 이동된 지점에서 손실 함수의 기울기(Gradient)를 계산하고, 3.과정을 다시 실시한다.
  5. 손실함수의 기울기가 최솟값에 도달하면, 파라미터 업데이트를 멈춘다.

 

 

 

 

2. 학습 단위

  • 그런데, 위 과정을 보다 보면 한 가지 의문이 든다.
  • 바로, 기울기 계산이 엄청 많이 일어난다는 것인데, 우리가 기계를 학습시킬 때 사용하는 빅 데이터는 일반적으로 최소 1,000만 건 이상을 가리키며, 1억, 10억 건 이상 데이터도 심심치 않게 등장한다는 것이다.
  • 이렇게 많은 데이터를 한 번에 모델에 태우게 된다면, 아무리 좋은 컴퓨터라도 버티지 못할 것이다.
  • 한 번의 학습에 모든 학습 데이터셋을 사용한다면, 여러 문제를 일으킨다.
  1. 데이터의 크기가 너무 큰 경우, 메모리가 너무 많이 필요해진다.
  2. 학습 한 번에 계산돼야 할 파라미터(가중치) 수가 지나치게 많아지므로 계산 시간이 너무 오래 걸린다.
  • 여기서 Epoch, Batch size, iteration라는 개념이 등장하게 된다.

 

 

 

 

3. Epoch(에포크)

  • Epoch의 네이버 영어 사전 뜻은, "(중요한 사건·변화들이 일어난) 시대"라는 뜻이다.
  • 훈련 데이터셋에 포함된 모든 데이터들이 한 번씩 모델을 통과한 횟수로, 모든 학습 데이터셋을 학습하는 횟수를 의미한다.
  • 1 epoch는 전체 학습 데이터셋이 한 신경망에 적용되어 순전파와 역전파를 통해 신경망을 한 번 통과했다는 의미가 된다.
  • 즉 epoch가 10회라면, 학습 데이터 셋 A를 10회 모델에 학습시켰다는 것이다.
  • epoch를 높일수록, 다양한 무작위 가중치로 학습을 해보므로, 적합한 파라미터를 찾을 확률이 올라간다.
    (즉, 손실 값이 내려가게 된다.)
  • 그러나, 지나치게 epoch를 높이게 되면, 그 학습 데이터셋에 과적합(Overfitting)되어 다른 데이터에 대해선 제대로 된 예측을 하지 못할 수 있다.

 

 

 

 

4. Batch size(배치 사이즈)

  • Batch의 네이버 영어 사전 뜻은 "(일괄적으로 처리되는) 집단", "한 회분(한 번에 만들어 내는 음식 기계 등의 양)", "(일괄 처리를 위해) 함께 묶다"라는 의미가 있다.
  • 즉, 연산 한 번에 들어가는 데이터의 크기를 가리킨다.
  • 1 Batch size에 해당하는 데이터 셋을 mini Batch라고 한다.
  • 1회 epoch 안에 m 개($m \geq 1$)의 mini Batch가 들어가게 되며, 만약, m = 1인 경우, 배치 학습법이라고 한다.
  • 배치 사이즈가 너무 큰 경우 한 번에 처리해야 할 데이터의 양이 많아지므로, 학습 속도가 느려지고, 메모리 부족 문제가 발생할 위험이 있다.
  • 반대로, 배치 사이즈가 너무 작은 경우 적은 데이터를 대상으로 가중치를 업데이트하고, 이 업데이트가 자주 발생하므로, 훈련이 불안정해진다.

 

 

 

 

5. Iteration(이터레이션)

  • Iteration은 네이버 영어사전에서 "(계산·컴퓨터 처리 절차의) 반복"이라는 뜻이다.
  • 전체 데이터를 모델에 한번 학습시키는데 필요한 배치의 수를 말한다.
  • 즉, 1 epoch를 마치는데 필요한 파라미터 업데이트 횟수라 할 수 있다.
  • 각 배치마다 파라미터 업데이트가 한 번씩 이루어지므로, Iteration은 "파라미터 업데이트 횟수 = 배치의 수"가 된다.

 

 

 

 

※ 참고

 만약, 데이터셋이 너무 거대해서 전체를 메모리에 올리는 것만으로도 부하가 걸릴 정도라면, 배치 학습 방법을 하되, 한 번에 학습할 학습 데이터 셋의 크기를 줄이고, for문으로 실제 batch를 만들고, pickle로 파일로 만들어 놓은 데이터 셋을 일부씩 불러와 batch에 학습시키고, 모든 데이터 셋을 불러와 한번 학습하는 것을 epoch로 잡는 방식도 있다.

 위 글만으로는 이해가 가지 않을 수 있으므로, 나중에 기회가 된다면 이를 자세히 다뤄보도록 하겠다.

 

 

 

 

 이번 포스트에서는 학습 단위로 사용되는 단어인 Epoch, Batch size, mini batch, Iteration에 대해 알아보았다. 다음 포스트에서는 배치 경사 하강법(BGD)과 확률적 경사 하강법(SGD)에 대해 학습해보도록 하겠다.

 
728x90
반응형

+ Recent posts