[TFLite] 4(3). 전이 학습

2 minute read

전이 학습


모델 선택


전이 학습은 직접 모델을 개발하는 방법과 사전 학습 모델을 이용하는 방법의 장점을 결합한 방법입니다. 학습이 완료된 모델을 다른 문제에 다시 학습시키는 방식으로 모델을 개발합니다.

전이 학습은 학습에 소요되는 시간을 줄일 수 있고, 훈련 데이터가 부족한 상황에서도 비교적 정확도가 높은 모델을 얻을 수 있습니다.


모델 개발


여기서는 기반 모델로 ImageNet 데이터를 학습한 MobileNet V2 를 사용하겠습니다. 이 모델을 개와 고양이 이미지로 학습시켜 개와 고양이 이미지를 구분하는 모델을 얻을 것입니다.

코드를 작성하기에 앞서 개와 고양이 이미지를 받기 위해 텐서플로의 데이터셋 프로젝트인 TFDS 라이브러리를 설치해야 합니다.

pip install tensorflow-datasets


이제 개와 고양이 이미지 데이터를 다운로드하여 불러옵니다.

import tensorflow_datasets as tfds
tfds.disable_progress_bar() # 다운로드 로그 출력 비활성화

raw_train, raw_test = tfds.load(
    'cats_vs_dogs',                         # 데이터명
    split=['train[:80%]', 'train[:20%]'],   # 데이터 분리
    as_supervised=True)                    # 데이터의 형태 
Downloading and preparing dataset Unknown size (download: Unknown size, generated: Unknown size, total: Unknown size) to C:\Users\wjsdu\tensorflow_datasets\cats_vs_dogs\4.0.0...
WARNING:absl:1738 images were corrupted and were skipped
Dataset cats_vs_dogs downloaded and prepared to C:\Users\wjsdu\tensorflow_datasets\cats_vs_dogs\4.0.0. Subsequent calls will reuse this data.

✋ as_supervised를 True로 설정하면 (input, label) 형태의 튜플 자료형을 반환하고, False로 설정하면 데이터별 고유한 dictionary 형태로 반환합니다.


이제 이미지 전처리를 수행합니다.

import numpy as np
import tensorflow as tf
from tensorflow.image import ResizeMethod

def preprocess(image, label):
    out_image = tf.image.resize(image, [96,96], method=ResizeMethod.BICUBIC)
    out_image = tf.keras.applications.mobilenet_v2.preprocess_input(out_image)
    return out_image, label

batch_size = 32
train_batch = raw_train.map(preprocess).batch(batch_size)
test_batch = raw_test.map(preprocess).batch(batch_size)

실질적인 전처리가 이루어지는 preprocess() 함수를 작성하고, raw_train과 raw_test 데이터에 각각 preprocess() 함수를 적용하여 결과 값으로 배치를 만들었습니다.

케라스 애플리케이션은 크기가 96, 128, 160, 192, 224 인 MobileNet 모델만 지원하기 때문에 preprocess() 함수 안에서 바이큐빅 보간법을 이용하여 입력 이미지의 크기를 (224,224)로 변환했습니다.

또한 mobilenet_v2 모듈에서 제공하는 preprocess_input() 함수를 이용하여 크기가 변환된 이미지 데이터를 한 번 더 전처리합니다.


이제 모델을 로드합니다.

mobilenet_base = tf.keras.applications.MobileNetV2(
    input_shape = (96,96,3), 
    weights = "imagenet", 
    include_top = False)
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_96_no_top.h5
9412608/9406464 [==============================] - 0s 0us/step

include_top 을 False로 설정하면 모델의 마지막 풀링 레이어와 Dense 레이어를 제외한 모델을 얻을 수 있습니다.

마지막 레이어를 제외하는 이유는 모델의 출력 결과가 문제에 의존적이기 때문입니다.

마지막 Dense 레이어는 결과로 1000개의 클래스로 분류합니다. 하지만 여기서는 이 모델을 개와 고양이로 분류하는 이진 분류에 사용할 것이기 때문에 마지막 레이어가 필요하지 않습니다.

따라서 마지막 Dense 레이어를 제거하고, 여기에 이진 분류에 맞는 출력을 내도록 풀링 레이어와 Dense 레이어를 추가하여 모델을 생성합니다.


아래 코드는 사전 학습된 MobileNet 모델을 훈련하고 평가하는 코드입니다.

mobilenet_base.trainable = False

mobilenet_model = tf.keras.Sequential([mobilenet_base, 
                                       tf.keras.layers.GlobalAveragePooling2D(),
                                       tf.keras.layers.Dense(1)])

mobilenet_model.compile(optimizer='adam', 
                        loss='binary_crossentropy', # 이진 분류
                        metrics=['accuracy'])

mobilenet_model.fit(train_batch, epochs=5)
mobilenet_model.evaluate(test_batch, verbose=2)
Epoch 1/5
582/582 [==============================] - 13s 16ms/step - loss: 0.9717 - accuracy: 0.9068
Epoch 2/5
582/582 [==============================] - 9s 16ms/step - loss: 0.7312 - accuracy: 0.9371
Epoch 3/5
582/582 [==============================] - 9s 16ms/step - loss: 0.6049 - accuracy: 0.9477
Epoch 4/5
582/582 [==============================] - 9s 16ms/step - loss: 0.5757 - accuracy: 0.9522
Epoch 5/5
582/582 [==============================] - 9s 16ms/step - loss: 0.5504 - accuracy: 0.9546
146/146 - 3s - loss: 0.5183 - accuracy: 0.9579
[0.5183104276657104, 0.9578675627708435]


이미 학습이 완료된 mobilenet_base의 가중치가 더 이상 학습되지 않도록 막기 위해 mobilenet_base.trainable = False로 설정합니다. 일반적으로 전이 학습은 이미 학습된 가중치가 더 이상 학습되지 않도록 동결시키고 훈련을 진행합니다. 나중에 성능 향상을 위해 모델을 다시 학습 가능하도록 되돌리고 학습률을 낮추어 전체를 다시 한 번 학습하며 미세 튜닝을 할 수 있습니다.

Categories:

Updated:

Leave a comment