본문 바로가기

Data Science/Machine Learning 구현

[ML] Tensorflow로 Pretrained Model Fine Tuning 하기

반응형

🔊 해당 포스팅은 권철민님의 CNN Fundamental 완벽 가이드 강의를 듣고 난 후 배운 내용을 정리하고자 하는 목적 하에 작성되는 포스팅입니다. 하단의 포스팅에서 사용되는 실습 코드 및 자료는 필자가 직접 재구성한 자료이며 권철민님의 자료를 그대로 인용하지 않았음을 필히 알려드립니다. 

 

이번 포스팅에서는 Tensorflow를 활용해 Pretrained Model을 로드하고 우리가 갖고 있는 데이터로 Pretrained Model을 추가로 학습시키는 Fine Tuning하는 방법에 대해 알아보자.

 

모델을 튜닝하는 방법에 대해 알아보자


1. Fine Tuning 이란?

먼저 Fine Tuning에 대해 간단히 알아보자. Fine Tuning은 미리 수많은 데이터로 학습된 전이 학습 모델을 가져와서 우리 데이터를 추가로 학습시켜서 전이 학습 모델을 더욱 우리 스타일(?)에 맞게 파라미터를 조정해주는 것을 의미한다.

 

예를 들어서 ImageNet 데이터로 학습된 전이 모델을 가져와서 우리가 해결하려는 개/고양이 이진 분류 문제를 해결하려고 한다. 이 때, ImageNet 데이터로 학습된 전이 모델이기 때문에 개/고양이 이진 분류를 잘 못할 수도 있겠다는 걱정이 살짝 들어서 내가 직접 수집한 개/고양이 이미지 데이터를 추가적으로 학습시키려고 한다. 이 때, 우리는 Fine Tuning을 통해서 이미 ImageNet 데이터에 최적화된 전이학습 모델의 파라미터를 개/고양이 이미지 데이터를 추가적으로 학습시켜서 파라미터를 더욱 더 세밀하게 미세 조정하게 된다.

 

보통은 Fine Tuning을 진행하기 위해서 2차례의 학습을 수행하게 된다. 처음에는 전이학습 모델의 파라미터들은 고정시킨(Freeze) 채 우리가 새롭게 정의한 즉, 우리의 목적에 맞게 새롭게 설계한 Classifier Layer들의 파라미터만 학습시킨다. 다시 예시로 들면, 우리가 추가로 학습시킬 개/고양이 데이터를 학습시킬 때는 전이 학습 모델의 파라미터들은 고정시킨다는 것이다. 그리고 이후에 2번째 학습시킬 때는 모든 파라미터를 학습 가능한 상태로 만들고 학습시킨다.

2. Tensorflow 로 Fine Tuning 하기

우선, Tesnorflow에서 제공하는 전이 학습 모델 중 MobileNet v2를 사용할 것이다. 그리고 추가적으로 학습할 데이터는 개와 고양이 데이터로 데이터의 출처는 여기를 참고하자. 참고로 추가로 학습시킬 개, 고양이 이미지 데이터를 소스로부터 가져오고 전처리하는 파이프라인 과정은 생략하겠다. 개, 고양이 데이터는 이진 분류 문제이므로 전이학습 모델을 로드하고 우리가 해결하려는 문제(이진 분류)에 맞게 Classifier Layer를 다음과 같이 새롭게 정의하자.

 

from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.layers import Input, GlobalAveragePooling2D, Dense
from tensorflow.keras.models import Model

def create_model(verbose=False):
    
    input_tensor = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3))
    base_model = MobileNetV2(input_tensor=input_tensor, include_top=False, weights='imagenet')
    
    bm_output = base_model.output

    x = GlobalAveragePooling2D()(bm_output)
    x = Dense(50, activation='relu', name='fc1')(x)
    # 최종 output 출력을 softmax에서 sigmoid로 변환. 
    output = Dense(1, activation='sigmoid', name='output')(x)

    model = Model(inputs=input_tensor, outputs=output)
    
    if verbose:
        model.summary()
        
    return model

 

이제 모델을 정의했으니 Fine Tuning 하는 방법에 대해 알아보자. 모델을 정의하게 되면 모델의 속성에 layers라는 속성이 존재한다. layers 속성을 반환하게 되면 리스트 형태로 모델을 구성하는 모든 레이어들이 출력되는데, 이 각 레이어에는 trainable 이라는 속성이 또 존재한다. 따라서 각 레이어의 trainable 속성을 True 에서 False로 바꾸게 되면 파라미터를 고정(Freeze)시키게 된다. 모델을 구성하고 있는 레이어들의 속성을 살펴보는 예시 코드는 다음과 같다.

 

# Fine Tuning 하기 위해서 Pretrained Model 레이어 구조 보기
model = create_model(verbose=False)

# 레이어 이름과 각 레이어의 Trainable 상태 볼 수 있음
for layer in model.layers[0:10]:
    print('Name:', layer.name, 'Trainable:', layer.trainable)

 

따라서 위와 같은 방법을 이용해서 처음 학습시킬 때는 우리가 만든 Classifier Layer들을 제외한 나머지 레이어들의 trainable 속성을 False로 만들고 학습시킨 후 두번째 학습시킬 때는 모든 레이어들의 trainable 속성을 True로 만들고 학습시킨다.(참고로 두번째 학습시킬 때에도 BatchNormalization 레이어들은 웬만하면 파라미터를 고정시키는 것을 권고한다고 한다)

 

from tensorflow.keras import layers

FIRST_EPOCHS = 10
SECOND_EPOCHS = 10

# Pretrained Model 로드
model = create_model(model_name='mobilenet', verbose=False)
model.compile(Adam(lr=0.0001), loss='binary_crossentropy', metrics=['accuracy'])

#============================================================================
# 1.Freeze 시킨 상태에서 10번 학습(즉, Custom으로 만든 Classifier Layer들만 파라미터 학습)
#============================================================================
# Feature Extractor Layer들은 파라미터 Freeze 시키기
for layer in model.layers[:-4]:
    layer.trainable = False

first_hist = model.fit(tr_ds, epochs=FIRST_EPOCHS, validation_data=val_ds)

#=====================================
# 2. 다시 학습시키기 위해 모델 재 컴파일 후 학습
#=====================================
for layer in model.layers:
    # layer객체가 tf.keras.layers.BatchNormalization 클래스인지 확인
    if not isinstance(layer, layers.BatchNormalization):
        layer.trainable = True
        
model.compile(Adam(lr=0.00001), loss='binary_crossentropy', metrics=['accuracy'])
second_hist = model.fit(tr_ds, epochs=SECOND_EPOCHS, validation_data=val_ds)

 

반응형