본문 바로가기
Study/AI

[AI] 전이학습(Transfer Learning)에 대하여

by ngool 2025. 3. 5.

데이터가 부족하지만 보다 높은 성능을 얻고 싶을 때 흔히 사용하는 방법이 있습니다.

바로 전이학습(transfer learning)인데요, 이는 기존에 학습된 모델의 지식을 새로운 문제에 적용하는 기법입니다.

 

이번 포스팅에서는 매우매우 powerful한 방법인 전이학습에 대해 예제와 함께 알아보도록 하겠습니다.


전이학습(Transfer Learning)이란?

전이학습이란, 일반적으로 대량의 데이터를 사용하여 미리 학습된 모델을 가져와, 특정 목적에 맞게 일부만 수정하여 재학습하는 방식을 말합니다.

https://kr.mathworks.com/discovery/transfer-learning.html

 

이미 똑똑한 녀석을 가져와 우리가 원하는 방식으로 조금만 더 학습시키는 느낌이기 때문에, 엄청난 효율을 볼 수 있는 것이죠!


전이학습의 장점

적은 데이터로도 높은 성능: 대량의 데이터가 없는 경우에도 강력한 모델을 구축할 수 있습니다.

학습 시간 단축: 처음부터 모델을 학습하는 것보다 훨씬 빠르게 훈련이 가능합니다.

연산 비용 절감: 대규모 연산이 필요한 모델을 다시 훈련할 필요 없이 일부만 업데이트하면 됩니다.

일반화 성능 향상: 기존 모델이 학습한 일반적인 특징을 재사용하므로 과적합을 줄일 수 있습니다.


전이학습 실습

제가 연구하고 있는 의료 영상 분야는 사람의 데이터를 사용하기 때문에, 당연하게도 많은 데이터를 구하기 어렵습니다.

그래서 더더욱 전이학습이 빛을 발할 수 있는 분야이기도 합니다.

 

이번 포스팅에서는 다량의 이미지 넷 데이터를 학습한 VGG-16 모델을 이어 받아 소량의 알츠하이머 뇌사진 데이터를 가지고 알츠하이머와 정상을 분류하는 모델을 만드는 전이학습 실습을 해볼 것입니다.

그런데 조금 이상하지 않나요?
이미지 넷 데이터에는 뇌 사진이 단 한 장도 존재하지 않는데, 어떻게 이 전이학습이 의미가 있는 걸까요?

 

이미지 넷처럼 수많은 데이터를 학습해서 깔끔하게 정리된 모델은 면, 질감, 선 등과 같은 기본적인 정보들을 잘 인식할 수 있습니다.

이러한 기본적인 능력을 이어 받아 뇌 사진 몇 장을 학습시키게 된다면, 뇌의 shape을 굉장히 잘 파악할 수 있게 됩니다.

 

바로 이것이 전이학습이 powerful한 이유이지요!


라이브러리 및 데이터 가져오기

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, Activation
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import optimizers
from tensorflow.keras.applications import VGG16

import numpy as np
import matplotlib.pyplot as plt


# 깃허브에 준비된 데이터를 가져옵니다.
!git clone https://github.com/taehojo/data-ch20.git

# 학습셋의 변형을 설정하는 부분입니다. 
train_datagen = ImageDataGenerator(rescale=1./255,          # 픽셀의 값을 0.0~1.0사이로 정규화합니다.
                                  horizontal_flip=True,     # 수평 대칭 이미지를 50% 확률로 만들어 추가합니다.
                                  width_shift_range=0.1,    # 전체 크기의 10% 범위에서 좌우로 이동합니다.
                                  height_shift_range=0.1,   # 마찬가지로 위, 아래로 이동합니다.
                                  validation_split=0.6)     # 전체 데이터의 40%만 훈련에 사용합니다. (전이학습의 효과를 더 극적으로 보기 위해)

train_generator = train_datagen.flow_from_directory(
       './data-ch20/train',   # 학습셋이 있는 폴더의 위치입니다.
       target_size=(150, 150),
       batch_size=5,
       class_mode='binary',
       subset='training')

# 테스트셋은 이미지 부풀리기 과정을 진행하지 않습니다.
test_datagen = ImageDataGenerator(rescale=1./255)  

test_generator = test_datagen.flow_from_directory(
       './data-ch20/test',   # 테스트셋이 있는 폴더의 위치입니다.
       target_size=(150, 150),
       batch_size=5,
       class_mode='binary')

 

training set은 64장, test set은 120장으로 실습을 진행하겠습니다.

training set을 실제 가진 데이터 보다 적게 한 이유는 어느 정도 데이터 양이 적지 않으면 전이학습의 효과가 미미하기 때문입니다. (실제로 training set이 100장을 넘어가니까 전이학습의 효과가 미미한 것을 확인하였습니다.)

 

이 실험은 데이터 양이 적은 상황에서의 전이학습의 효과를 보는 것이 목적이므로, 훈련 셋의 크기를 줄였습니다.


전이학습 없이 학습/평가

# 우리의 모델을 설정합니다.
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), input_shape=(150, 150, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
model.summary()

# 모델의 실행 옵션을 설정합니다.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# 모델을 실행합니다.
model.fit(train_generator, 
          validation_data=test_generator, 
          epochs=30, 
          validation_steps=10,
          verbose=1)

# 테스트 정확도를 출력합니다.
print("\n Test Accuracy: %.4f" % (model.evaluate(test_generator)[1]))

 

상당히 낮은 정확도가 나왔습니다. 이 정도 훈련 셋으로는 특징을 제대로 뽑아내는 것이 어렵다는 뜻이겠죠!


전이학습 적용하여 학습/평가

# VGG16 모델을 불러옵니다.
transfer_model = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
transfer_model.trainable = False

# 우리의 모델을 설정합니다.
finetune_model = Sequential()
finetune_model.add(transfer_model)
finetune_model.add(Flatten())
finetune_model.add(Dense(64, activation='relu'))
finetune_model.add(Dropout(0.5))
finetune_model.add(Dense(1, activation='sigmoid'))

# 모델의 실행 옵션을 설정합니다. 
finetune_model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# 모델을 실행합니다.
finetune_model.fit(train_generator,
                   validation_data=test_generator,
                   epochs=30,
                   validation_steps=10,
                   verbose=1)

# 테스트 정확도를 출력합니다.
print("\n Test Accuracy: %.4f" % (finetune_model.evaluate(test_generator)[1]))

 

전이학습의 효과가 상당합니다..

저도 솔직히 이 정도일 줄은 몰랐는데요, 데이터 양이 적을 때는 전이학습이 정말 효과적인 것 같습니다!!


추가 실험

위 실험 이후, epoch이 너무 작아서 학습이 덜 된 문제는 아닐까 하는 생각이 들었습니다.
그래서 동일 조건으로 epoch만 50까지 늘려서 다시 실험을 진행해보았습니다.

그 결과, 전이학습 없이 만든 모델의 정확도는 0.8917에 그친 반면, 전이학습을 적용한 모델의 정확도는 무려 0.9750까지 증가하였습니다.