본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 2. · 11 Views
전이 학습 완벽 가이드
이미 학습된 모델의 지식을 활용하여 새로운 문제를 효율적으로 해결하는 전이 학습의 핵심 개념과 실전 활용법을 다룹니다. 초급 개발자도 쉽게 따라할 수 있도록 VGG, ResNet, EfficientNet 등의 사전 학습 모델 사용법부터 Fine-tuning까지 단계별로 설명합니다.
목차
- 전이 학습이란?
- 사전 학습 모델 (VGG, ResNet, EfficientNet)
- tf.keras.applications 사용법
- Feature Extraction 방식
- Fine-tuning 방식
- 커스텀 데이터셋에 적용
1. 전이 학습이란?
어느 날 김개발 씨는 회사에서 강아지와 고양이를 분류하는 이미지 인식 모델을 만들라는 업무를 받았습니다. 문제는 학습 데이터가 고작 500장밖에 없다는 것이었습니다.
"이 정도 데이터로 딥러닝 모델을 처음부터 학습시키면 과적합이 일어날 텐데..." 고민하던 김개발 씨에게 선배가 다가와 말했습니다. "전이 학습을 써보는 건 어때요?"
**전이 학습(Transfer Learning)**은 이미 학습된 모델의 지식을 새로운 문제에 재활용하는 기법입니다. 마치 영어를 잘하는 사람이 스페인어를 더 빨리 배우는 것과 같습니다.
수백만 장의 이미지로 학습된 모델의 지식을 가져와 적은 데이터로도 높은 성능을 낼 수 있습니다.
다음 코드를 살펴봅시다.
import tensorflow as tf
from tensorflow.keras.applications import VGG16
# ImageNet으로 사전 학습된 VGG16 모델 불러오기
# include_top=False: 마지막 분류층 제외
base_model = VGG16(
weights='imagenet', # 사전 학습된 가중치 사용
include_top=False, # 분류층 제외
input_shape=(224, 224, 3)
)
# 사전 학습된 가중치 동결
base_model.trainable = False
# 모델 구조 확인
print(f"총 레이어 수: {len(base_model.layers)}")
김개발 씨는 입사 6개월 차 주니어 개발자입니다. 회사에서 반려동물 사진 분류 서비스를 만들라는 과제를 받았는데, 주어진 학습 데이터는 고작 500장뿐이었습니다.
딥러닝 책에서 봤던 내용이 떠올랐습니다. "CNN 모델을 제대로 학습시키려면 최소 수만 장의 이미지가 필요하다고 했는데..." 고민하던 김개발 씨에게 선배 개발자 박시니어 씨가 다가왔습니다.
"혹시 전이 학습이라고 들어봤어요? 구글이나 페이스북에서 이미 수백만 장의 이미지로 학습시켜 놓은 모델이 있어요.
그 지식을 빌려오면 됩니다." 그렇다면 전이 학습이란 정확히 무엇일까요? 쉽게 비유하자면, 전이 학습은 마치 요리를 배우는 것과 같습니다.
처음부터 모든 요리 기술을 배우려면 수년이 걸립니다. 하지만 이미 요리의 기본기를 익힌 사람이라면 새로운 요리를 훨씬 빨리 배울 수 있습니다.
칼 다루는 법, 불 조절하는 법, 간 맞추는 법 같은 기본 지식이 있기 때문입니다. 딥러닝에서도 마찬가지입니다.
ImageNet이라는 1,400만 장이 넘는 이미지 데이터셋으로 학습된 모델은 이미 "이미지를 보는 법"을 알고 있습니다. 가장자리를 찾는 법, 텍스처를 인식하는 법, 형태를 파악하는 법을 이미 배웠습니다.
이 지식을 가져다가 우리 문제에 맞게 조금만 수정하면 됩니다. 전이 학습이 없던 시절에는 어땠을까요?
개발자들은 모든 프로젝트마다 모델을 처음부터 학습시켜야 했습니다. 수만 장의 이미지를 모으고 라벨링하는 데만 몇 달이 걸렸습니다.
GPU 비용도 어마어마했습니다. 무엇보다 데이터가 부족하면 아무리 좋은 모델 구조를 사용해도 성능이 나오지 않았습니다.
바로 이런 문제를 해결하기 위해 전이 학습이 주목받기 시작했습니다. 사전 학습된 모델을 사용하면 학습 시간을 획기적으로 단축할 수 있습니다.
적은 데이터로도 높은 성능을 달성할 수 있습니다. 무엇보다 GPU 비용을 크게 절약할 수 있습니다.
위의 코드를 살펴보겠습니다. 먼저 VGG16이라는 사전 학습된 모델을 불러옵니다.
**weights='imagenet'**은 ImageNet 데이터셋으로 학습된 가중치를 사용하겠다는 의미입니다. include_top=False는 원래 모델의 마지막 분류층을 제외한다는 뜻입니다.
왜냐하면 원래 모델은 1,000개 클래스를 분류하도록 설계되었지만, 우리는 강아지와 고양이 2개 클래스만 분류하면 되기 때문입니다. base_model.trainable = False는 매우 중요한 부분입니다.
사전 학습된 가중치를 건드리지 않고 그대로 사용하겠다는 의미입니다. 이렇게 하면 이미 학습된 "이미지를 보는 능력"을 보존할 수 있습니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 의료 영상 분석 서비스를 개발한다고 가정해봅시다.
X-ray 이미지로 폐렴을 진단하는 모델을 만들어야 하는데, 의료 데이터는 수집하기가 매우 어렵습니다. 이때 일반 이미지로 학습된 모델의 지식을 전이하면, 적은 의료 이미지로도 높은 정확도의 진단 모델을 만들 수 있습니다.
하지만 주의할 점도 있습니다. 전이 학습이 항상 효과적인 것은 아닙니다.
사전 학습에 사용된 데이터와 우리 데이터가 너무 다르면 오히려 성능이 떨어질 수 있습니다. 예를 들어 일반 사진으로 학습된 모델을 위성 사진 분석에 바로 적용하면 좋은 결과를 얻기 어렵습니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.
"아, 그래서 구글에서 공개한 모델들이 그렇게 인기가 많았군요!" 전이 학습을 제대로 이해하면 적은 리소스로도 강력한 딥러닝 모델을 구축할 수 있습니다.
실전 팁
💡 - 사전 학습 데이터와 타겟 데이터의 유사성이 높을수록 전이 학습 효과가 좋습니다
- 데이터가 매우 적을 때는 Feature Extraction 방식을, 어느 정도 있을 때는 Fine-tuning 방식을 선택하세요
2. 사전 학습 모델 (VGG, ResNet, EfficientNet)
김개발 씨는 전이 학습을 적용하기로 결심했습니다. 그런데 막상 찾아보니 VGG, ResNet, EfficientNet, MobileNet 등 사전 학습 모델이 너무 많았습니다.
"도대체 어떤 모델을 선택해야 하지?" 각 모델의 특징과 장단점을 알아야 올바른 선택을 할 수 있습니다.
사전 학습 모델은 대규모 데이터셋으로 미리 학습된 신경망입니다. VGG는 단순하지만 무겁고, ResNet은 깊은 네트워크를 효율적으로 학습시키며, EfficientNet은 성능과 효율성의 균형을 갖췄습니다.
프로젝트의 요구사항에 따라 적절한 모델을 선택해야 합니다.
다음 코드를 살펴봅시다.
from tensorflow.keras.applications import VGG16, ResNet50, EfficientNetB0
# VGG16: 단순한 구조, 큰 모델 크기 (528MB)
vgg = VGG16(weights='imagenet', include_top=False)
print(f"VGG16 파라미터 수: {vgg.count_params():,}")
# ResNet50: 잔차 연결, 중간 크기 (98MB)
resnet = ResNet50(weights='imagenet', include_top=False)
print(f"ResNet50 파라미터 수: {resnet.count_params():,}")
# EfficientNetB0: 효율적인 구조, 작은 크기 (29MB)
efficient = EfficientNetB0(weights='imagenet', include_top=False)
print(f"EfficientNetB0 파라미터 수: {efficient.count_params():,}")
김개발 씨는 전이 학습에 사용할 모델을 고르기 위해 TensorFlow 문서를 살펴보았습니다. VGG16, VGG19, ResNet50, ResNet101, EfficientNetB0부터 B7까지...
모델 목록이 끝이 없었습니다. "이 많은 모델 중에 어떤 걸 써야 하지?" 박시니어 씨가 옆에서 조언했습니다.
"각 모델에는 저마다의 특징이 있어요. 프로젝트 상황에 맞게 선택해야 합니다.
일단 가장 대표적인 세 가지를 알아두면 좋아요." 먼저 VGG 시리즈입니다. 2014년 옥스포드 대학의 VGG 연구팀에서 개발했습니다.
이름도 Visual Geometry Group의 약자입니다. 구조가 매우 단순합니다.
3x3 컨볼루션 레이어를 차곡차곡 쌓은 형태입니다. 마치 레고 블록을 일렬로 쌓은 것처럼 직관적입니다.
하지만 단순함에는 대가가 따릅니다. VGG16의 용량은 무려 528MB에 달합니다.
파라미터 수가 1억 3천만 개가 넘습니다. 서버 환경에서는 괜찮지만, 모바일 앱이나 임베디드 기기에서 사용하기에는 너무 무겁습니다.
다음은 ResNet입니다. 2015년 마이크로소프트 연구팀에서 개발했습니다.
ResNet의 혁신은 **잔차 연결(Residual Connection)**에 있습니다. 쉽게 말해, 몇 개의 레이어를 건너뛰는 지름길을 만든 것입니다.
마치 엘리베이터처럼 중간 층을 건너뛸 수 있습니다. 이 구조 덕분에 152층이나 되는 깊은 네트워크도 학습시킬 수 있게 되었습니다.
이전에는 네트워크가 깊어질수록 학습이 잘 되지 않는 기울기 소실 문제가 있었는데, 잔차 연결이 이 문제를 해결했습니다. ResNet50의 용량은 98MB로 VGG보다 훨씬 가볍습니다.
마지막으로 EfficientNet입니다. 2019년 구글에서 개발한 최신 모델입니다.
EfficientNet의 핵심 아이디어는 **복합 스케일링(Compound Scaling)**입니다. 네트워크의 깊이, 너비, 해상도를 균형 있게 조절하여 효율성을 극대화했습니다.
EfficientNet은 B0부터 B7까지 다양한 크기로 제공됩니다. B0은 가장 작고 가벼우며, B7은 가장 크고 정확합니다.
EfficientNetB0의 용량은 29MB에 불과하지만, 성능은 ResNet50과 비슷하거나 더 좋습니다. 자원 대비 성능이 가장 뛰어난 모델입니다.
그렇다면 어떤 모델을 선택해야 할까요? 실무에서는 상황에 따라 다릅니다.
빠른 프로토타이핑이 필요하면 VGG가 좋습니다. 구조가 단순해서 이해하기 쉽고 디버깅도 편합니다.
정확도가 중요하고 서버 자원이 충분하면 ResNet101이나 ResNet152를 고려해볼 만합니다. 모바일 앱이나 엣지 기기에 배포해야 한다면 EfficientNetB0나 MobileNet을 선택하세요.
가볍고 빠르면서도 준수한 성능을 보여줍니다. 최근 프로젝트에서는 EfficientNet 시리즈가 기본 선택지로 자리 잡고 있습니다.
주의할 점이 있습니다. 모델마다 기대하는 입력 형식이 다릅니다.
VGG와 ResNet은 이미지 픽셀값을 0255에서 특정 범위로 정규화해야 합니다. EfficientNet은 0255 그대로 입력받습니다.
전처리 방식을 잘못 적용하면 성능이 크게 떨어질 수 있습니다. 김개발 씨는 고민 끝에 EfficientNetB0을 선택했습니다.
데이터가 적은 상황에서 과적합을 방지하려면 가벼운 모델이 유리하다는 선배의 조언을 따른 것입니다. "나중에 서비스가 커지면 B3나 B5로 업그레이드하면 되겠네요!"
실전 팁
💡 - 프로토타이핑에는 VGG, 프로덕션에는 EfficientNet을 추천합니다
- 각 모델의 전용 전처리 함수를 반드시 사용하세요 (예: tf.keras.applications.efficientnet.preprocess_input)
3. tf.keras.applications 사용법
김개발 씨는 EfficientNetB0을 선택했습니다. 이제 실제로 코드를 작성해야 할 차례입니다.
TensorFlow의 tf.keras.applications 모듈을 사용하면 사전 학습 모델을 손쉽게 불러올 수 있습니다. 단 몇 줄의 코드로 수백만 달러짜리 모델을 무료로 사용할 수 있습니다.
tf.keras.applications는 TensorFlow에서 제공하는 사전 학습 모델 저장소입니다. VGG, ResNet, EfficientNet 등 주요 모델을 간편하게 불러올 수 있으며, weights, include_top, input_shape 등의 매개변수로 세부 설정이 가능합니다.
다음 코드를 살펴봅시다.
import tensorflow as tf
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.applications.efficientnet import preprocess_input
# 사전 학습 모델 불러오기
base_model = EfficientNetB0(
weights='imagenet', # 사전 학습 가중치
include_top=False, # 분류층 제외
input_shape=(224, 224, 3), # 입력 이미지 크기
pooling='avg' # 마지막에 GlobalAveragePooling 적용
)
# 이미지 전처리 예시
image = tf.keras.preprocessing.image.load_img('dog.jpg', target_size=(224, 224))
image_array = tf.keras.preprocessing.image.img_to_array(image)
image_array = tf.expand_dims(image_array, 0) # 배치 차원 추가
preprocessed = preprocess_input(image_array) # 모델 전용 전처리
김개발 씨는 EfficientNetB0 모델을 코드로 구현하기 시작했습니다. 예전 같았으면 논문을 읽고, 모델 구조를 하나하나 직접 구현하고, 학습된 가중치 파일을 찾아 다운로드해야 했을 것입니다.
하지만 TensorFlow의 tf.keras.applications 덕분에 이 모든 과정이 단 한 줄로 해결됩니다. tf.keras.applications는 TensorFlow가 공식으로 제공하는 사전 학습 모델 저장소입니다.
마치 앱 스토어에서 앱을 다운받듯이, 검증된 모델을 간편하게 가져다 쓸 수 있습니다. 모델 구조는 물론 ImageNet으로 학습된 가중치까지 함께 제공됩니다.
코드의 첫 번째 매개변수인 **weights='imagenet'**을 살펴봅시다. 이 설정은 ImageNet 대회에서 우승한 가중치를 다운로드하겠다는 의미입니다.
'imagenet' 대신 None을 넣으면 랜덤 초기화된 가중치로 시작합니다. 특수한 경우가 아니라면 항상 'imagenet'을 사용하세요.
두 번째 매개변수 include_top=False가 핵심입니다. 원래 EfficientNetB0은 1,000개 클래스를 분류하도록 설계되었습니다.
마지막에 1,000개 노드를 가진 Dense 레이어가 붙어 있습니다. 하지만 우리는 강아지와 고양이, 2개 클래스만 분류하면 됩니다.
include_top=False로 설정하면 이 마지막 분류층을 제거하고, 우리만의 분류층을 붙일 수 있습니다. **input_shape=(224, 224, 3)**은 입력 이미지의 크기를 지정합니다.
224x224 픽셀의 RGB 이미지를 입력받겠다는 의미입니다. 모델마다 권장 크기가 다릅니다.
EfficientNetB0은 224x224, EfficientNetB4는 380x380을 권장합니다. 지정한 크기와 다른 이미지를 넣으면 내부적으로 리사이징되지만, 권장 크기를 맞추는 것이 성능에 유리합니다.
**pooling='avg'**는 GlobalAveragePooling을 적용합니다. 이 설정 없이 include_top=False만 하면 출력이 (None, 7, 7, 1280) 형태의 4차원 텐서입니다.
pooling='avg'를 추가하면 (None, 1280) 형태의 2차원 벡터가 됩니다. 이렇게 하면 바로 뒤에 Dense 레이어를 연결하기 편해집니다.
이미지 전처리도 중요합니다. 각 모델은 학습 시 사용된 전처리 방식이 다릅니다.
VGG는 ImageNet의 평균 RGB 값을 빼는 방식을 사용하고, ResNet은 caffe 스타일의 전처리를 사용합니다. EfficientNet은 0~255 범위의 값을 그대로 사용합니다.
preprocess_input 함수는 각 모델에 맞는 전처리를 자동으로 수행합니다. 반드시 해당 모델의 preprocess_input을 사용해야 합니다.
VGG16을 쓰면서 EfficientNet의 preprocess_input을 사용하면 성능이 크게 떨어집니다. 실무에서 흔히 하는 실수 중 하나가 전처리를 빠뜨리거나 잘못된 전처리 함수를 사용하는 것입니다.
분명히 같은 코드인데 왜 다른 사람 컴퓨터에서는 성능이 잘 나오고 내 컴퓨터에서는 안 나오지? 대부분 전처리 문제입니다.
김개발 씨는 코드를 작성하면서 한 가지 궁금증이 생겼습니다. "모델을 처음 불러올 때 시간이 좀 걸리는데, 왜 그런 거죠?" 박시니어 씨가 설명했습니다.
"처음 실행할 때 가중치 파일을 다운로드받기 때문이에요. ~/.keras/models 폴더에 저장되니까, 다음부터는 빨라요." 이제 사전 학습 모델을 불러오는 방법을 알았습니다.
다음 단계는 이 모델 위에 우리만의 분류층을 쌓고, 실제로 학습시키는 것입니다.
실전 팁
💡 - 처음 실행 시 가중치 다운로드로 시간이 걸리며, 이후에는 캐시된 파일을 사용합니다
- include_top=False일 때 pooling 매개변수를 설정하면 출력 형태 조절이 편리합니다
4. Feature Extraction 방식
김개발 씨는 EfficientNetB0을 불러오는 데 성공했습니다. 이제 실제로 모델을 학습시킬 차례입니다.
전이 학습에는 크게 두 가지 방식이 있습니다. 첫 번째는 Feature Extraction, 사전 학습 모델을 고정하고 마지막 분류층만 학습시키는 방법입니다.
Feature Extraction은 사전 학습 모델의 가중치를 동결(freeze)하고, 새로 추가한 분류층만 학습시키는 방식입니다. 마치 숙련된 화가에게 밑그림을 맡기고, 우리는 색칠만 하는 것과 같습니다.
데이터가 적거나 빠른 학습이 필요할 때 효과적입니다.
다음 코드를 살펴봅시다.
import tensorflow as tf
from tensorflow.keras import layers, Model
from tensorflow.keras.applications import EfficientNetB0
# 사전 학습 모델 불러오기 및 동결
base_model = EfficientNetB0(weights='imagenet', include_top=False, pooling='avg')
base_model.trainable = False # 핵심: 모든 레이어 동결
# 커스텀 분류층 추가
inputs = layers.Input(shape=(224, 224, 3))
x = base_model(inputs, training=False) # 추론 모드로 실행
x = layers.Dropout(0.2)(x) # 과적합 방지
outputs = layers.Dense(2, activation='softmax')(x) # 2개 클래스 분류
# 모델 생성 및 컴파일
model = Model(inputs, outputs)
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
김개발 씨는 전이 학습의 첫 번째 방식인 Feature Extraction을 시도해보기로 했습니다. 박시니어 씨가 설명을 시작했습니다.
"사전 학습 모델은 이미 이미지에서 특징을 추출하는 법을 알고 있어요. 우리는 그 특징을 가져다가 분류만 하면 됩니다." Feature Extraction을 쉽게 비유하면 이렇습니다.
숙련된 화가에게 밑그림을 그려달라고 부탁했다고 상상해보세요. 화가는 대상의 형태, 그림자, 원근감을 완벽하게 잡아줍니다.
우리는 그 위에 색칠만 하면 됩니다. 밑그림 실력이 없어도 멋진 그림을 완성할 수 있습니다.
코드에서 가장 중요한 부분은 base_model.trainable = False입니다. 이 한 줄이 사전 학습 모델의 모든 가중치를 동결시킵니다.
동결된 레이어는 학습 중에 가중치가 변하지 않습니다. 오직 우리가 새로 추가한 분류층만 학습됩니다.
왜 동결이 필요할까요? 사전 학습 모델의 가중치는 수백만 장의 이미지로 정교하게 학습되었습니다.
우리의 작은 데이터셋으로 이 가중치를 수정하면 오히려 망가질 수 있습니다. 마치 명화 위에 낙서를 하는 것과 같습니다.
training=False 매개변수도 눈여겨봐야 합니다. 이것은 BatchNormalization 레이어의 동작을 제어합니다.
training=True면 현재 배치의 통계를 사용하고, training=False면 학습 시 계산된 통계를 사용합니다. Feature Extraction에서는 반드시 False로 설정해야 합니다.
Dropout 레이어를 추가한 이유는 과적합 방지입니다. 데이터가 적을수록 과적합 위험이 높습니다.
Dropout(0.2)는 학습 중 랜덤하게 20%의 뉴런을 비활성화하여 모델이 특정 뉴런에 과도하게 의존하는 것을 막습니다. 마지막 Dense 레이어는 우리의 분류 목표에 맞게 설정합니다.
강아지와 고양이를 분류하니 출력이 2개입니다. activation='softmax'는 출력을 확률로 변환합니다.
두 클래스의 확률 합이 1이 됩니다. Feature Extraction의 가장 큰 장점은 속도입니다.
학습시킬 파라미터가 분류층에만 있으니 매우 빠릅니다. EfficientNetB0 전체는 400만 개가 넘는 파라미터가 있지만, 분류층은 수천 개에 불과합니다.
GPU가 없는 환경에서도 몇 분 안에 학습이 끝납니다. 두 번째 장점은 과적합 위험 감소입니다.
학습시킬 파라미터가 적으니 적은 데이터로도 안정적으로 학습됩니다. 김개발 씨의 500장 데이터로도 충분히 좋은 결과를 얻을 수 있습니다.
하지만 단점도 있습니다. 사전 학습 데이터와 우리 데이터가 많이 다르면 성능 한계가 있습니다.
일반 사진으로 학습된 모델은 "일반적인 이미지 특징"을 추출합니다. 의료 영상이나 위성 사진처럼 특수한 도메인에서는 충분하지 않을 수 있습니다.
김개발 씨가 Feature Extraction으로 첫 모델을 학습시켰습니다. 정확도가 85%까지 올랐습니다.
"괜찮은데요? 그런데 더 올릴 수 있을까요?" 박시니어 씨가 미소 지었습니다.
"그럴 때는 Fine-tuning을 시도해볼 차례입니다."
실전 팁
💡 - 데이터가 1,000장 이하일 때는 Feature Extraction부터 시작하세요
- base_model(inputs, training=False)에서 training 매개변수를 빠뜨리면 성능이 떨어질 수 있습니다
5. Fine-tuning 방식
김개발 씨의 Feature Extraction 모델은 정확도 85%를 달성했습니다. 하지만 팀장님은 90% 이상을 요구합니다.
더 높은 성능을 위해서는 Fine-tuning이 필요합니다. 사전 학습 모델의 일부 레이어도 함께 학습시켜 우리 데이터에 맞게 미세 조정하는 방법입니다.
Fine-tuning은 사전 학습 모델의 상위 레이어를 동결 해제하고 함께 학습시키는 방식입니다. 마치 기존 레시피를 우리 입맛에 맞게 살짝 조정하는 것과 같습니다.
Feature Extraction보다 높은 성능을 낼 수 있지만, 데이터가 충분해야 하고 학습률 조절에 주의가 필요합니다.
다음 코드를 살펴봅시다.
import tensorflow as tf
from tensorflow.keras import layers, Model
from tensorflow.keras.applications import EfficientNetB0
# 1단계: Feature Extraction으로 분류층 먼저 학습 (이전 코드와 동일)
base_model = EfficientNetB0(weights='imagenet', include_top=False, pooling='avg')
base_model.trainable = False
inputs = layers.Input(shape=(224, 224, 3))
x = base_model(inputs, training=False)
x = layers.Dropout(0.2)(x)
outputs = layers.Dense(2, activation='softmax')(x)
model = Model(inputs, outputs)
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# model.fit(train_data, epochs=10) # 먼저 분류층 학습
# 2단계: Fine-tuning - 상위 레이어 동결 해제
base_model.trainable = True
for layer in base_model.layers[:-20]: # 마지막 20개 레이어만 학습
layer.trainable = False
# 낮은 학습률로 재컴파일
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5), # 매우 낮은 학습률
loss='categorical_crossentropy',
metrics=['accuracy']
)
박시니어 씨가 Fine-tuning에 대해 설명하기 시작했습니다. "Feature Extraction은 사전 학습 모델을 그대로 사용하는 거예요.
하지만 우리 데이터가 어느 정도 있다면, 모델을 우리 상황에 맞게 미세 조정할 수 있습니다." Fine-tuning을 비유하자면 이렇습니다. 유명 셰프의 레시피를 그대로 따라 요리했는데, 우리 가족 입맛에는 조금 짜다고 합니다.
레시피 전체를 바꾸는 건 무모합니다. 대신 마지막 간 맞추기 단계에서 소금을 조금 덜 넣습니다.
기본 레시피는 유지하면서 우리 상황에 맞게 살짝 조정하는 것입니다. Fine-tuning에서 가장 중요한 원칙이 있습니다.
반드시 Feature Extraction 단계를 먼저 거쳐야 합니다. 처음부터 사전 학습 모델과 분류층을 동시에 학습시키면 안 됩니다.
왜 그럴까요? 새로 추가한 분류층의 가중치는 랜덤으로 초기화되어 있습니다.
처음에는 완전히 엉터리 예측을 합니다. 이 상태에서 역전파가 일어나면, 엉터리 예측을 기반으로 사전 학습 모델의 가중치가 수정됩니다.
신중하게 학습된 가중치가 망가집니다. 그래서 2단계 전략을 사용합니다.
먼저 Feature Extraction으로 분류층만 학습시킵니다. 분류층이 어느 정도 똑똑해지면, 그때 사전 학습 모델의 일부를 동결 해제하고 함께 학습시킵니다.
코드를 살펴보면, base_model.layers[:-20]에서 마지막 20개 레이어만 학습 가능하게 설정합니다. 왜 전체가 아니라 일부만 학습시킬까요?
신경망의 앞쪽 레이어는 일반적인 특징(가장자리, 색상, 텍스처)을 학습합니다. 뒤쪽 레이어로 갈수록 도메인 특화 특징(얼굴, 동물, 물체)을 학습합니다.
앞쪽 레이어의 일반적인 특징은 어떤 이미지 과제에도 유용합니다. 굳이 바꿀 필요가 없습니다.
뒤쪽 레이어만 우리 데이터에 맞게 조정하면 됩니다. 이렇게 하면 학습도 빠르고, 과적합 위험도 줄어듭니다.
학습률 설정이 Fine-tuning의 성패를 좌우합니다. Feature Extraction에서는 보통 0.001 정도의 학습률을 사용합니다.
하지만 Fine-tuning에서는 1e-5(0.00001) 수준의 매우 낮은 학습률을 사용해야 합니다. 사전 학습 가중치는 이미 최적화되어 있습니다.
큰 학습률로 수정하면 좋은 가중치가 망가집니다. 낮은 학습률로 조심스럽게, 천천히 수정해야 합니다.
마치 명품 시계를 수리할 때 섬세하게 다루는 것과 같습니다. Fine-tuning의 위험성도 알아야 합니다.
데이터가 너무 적으면 오히려 Feature Extraction보다 성능이 떨어질 수 있습니다. 일반적으로 클래스당 1,000장 이상의 데이터가 있을 때 Fine-tuning을 시도합니다.
데이터가 적으면 과적합이 일어나서 학습 정확도는 높은데 검증 정확도가 낮은 현상이 나타납니다. 김개발 씨는 회사의 추가 데이터를 확보하여 Fine-tuning을 시도했습니다.
결과는 놀라웠습니다. 정확도가 92%까지 올랐습니다.
"드디어 팀장님 기준을 통과했어요!" 박시니어 씨가 고개를 끄덕였습니다. "잘했어요.
이제 실제 서비스에 배포해볼까요?"
실전 팁
💡 - Fine-tuning 전에 반드시 Feature Extraction 단계를 거치세요
- 학습률은 Feature Extraction의 1/10 ~ 1/100 수준으로 낮추세요
- 데이터가 클래스당 1,000장 미만이면 Feature Extraction에 머무르는 것이 나을 수 있습니다
6. 커스텀 데이터셋에 적용
이론은 충분히 배웠습니다. 이제 실제 프로젝트에 전이 학습을 적용할 차례입니다.
김개발 씨는 회사에서 수집한 강아지, 고양이 이미지를 폴더에 정리하고, 처음부터 끝까지 전이 학습 파이프라인을 구축해보기로 했습니다.
실제 프로젝트에 전이 학습을 적용하려면 데이터 준비부터 학습, 평가까지의 전체 과정을 이해해야 합니다. ImageDataGenerator 또는 tf.data를 활용한 데이터 파이프라인 구축, 콜백을 활용한 학습 관리, 그리고 모델 저장까지 실무에서 필요한 전체 흐름을 다룹니다.
다음 코드를 살펴봅시다.
import tensorflow as tf
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.applications.efficientnet import preprocess_input
from tensorflow.keras import layers, Model
# 데이터 경로 설정 (train/dogs, train/cats 폴더 구조 가정)
train_dir = './data/train'
val_dir = './data/validation'
# 데이터 증강 및 로딩
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
preprocessing_function=preprocess_input,
rotation_range=20,
horizontal_flip=True,
zoom_range=0.2
)
train_generator = train_datagen.flow_from_directory(
train_dir, target_size=(224, 224), batch_size=32, class_mode='categorical'
)
# 모델 구성 (Feature Extraction)
base_model = EfficientNetB0(weights='imagenet', include_top=False, pooling='avg')
base_model.trainable = False
model = tf.keras.Sequential([
layers.Input(shape=(224, 224, 3)),
base_model,
layers.Dropout(0.2),
layers.Dense(2, activation='softmax')
])
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(train_generator, epochs=10)
김개발 씨는 드디어 실전입니다. 회사에서 수집한 이미지 데이터가 폴더에 정리되어 있습니다.
data/train/dogs와 data/train/cats 폴더에 각각 강아지와 고양이 이미지가 들어있습니다. 이제 이 데이터로 모델을 학습시켜야 합니다.
첫 번째 단계는 데이터 파이프라인 구축입니다. TensorFlow의 ImageDataGenerator를 사용하면 폴더 구조에서 자동으로 이미지와 레이블을 읽어옵니다.
flow_from_directory 메서드가 폴더 이름을 클래스 레이블로 인식합니다. dogs 폴더의 이미지는 자동으로 "dogs" 클래스로 분류됩니다.
**데이터 증강(Data Augmentation)**도 중요합니다. 데이터가 적을 때 과적합을 방지하는 효과적인 방법입니다.
rotation_range=20은 이미지를 최대 20도까지 회전시킵니다. horizontal_flip=True는 좌우 반전을 적용합니다.
zoom_range=0.2는 최대 20%까지 확대/축소합니다. 데이터 증강은 마치 같은 사진을 다양한 각도에서 찍는 것과 같습니다.
500장의 원본 이미지가 있어도, 증강을 적용하면 사실상 수천 장의 다양한 이미지를 학습하는 효과를 얻습니다. 모델이 특정 각도나 크기에 과적합되는 것을 방지합니다.
주의할 점이 있습니다. preprocessing_function에 모델 전용 전처리 함수를 반드시 지정해야 합니다.
이 예제에서는 EfficientNet용 preprocess_input을 사용했습니다. 이 설정을 빠뜨리면 모델 성능이 크게 떨어집니다.
target_size=(224, 224)는 모든 이미지를 224x224 크기로 리사이징합니다. 원본 이미지 크기가 제각각이어도 걱정 없습니다.
batch_size=32는 한 번에 32장씩 이미지를 로드한다는 의미입니다. GPU 메모리가 부족하면 16이나 8로 줄이세요.
모델 구성에서는 Sequential API를 사용했습니다. 이전 예제에서는 Functional API를 사용했는데, Sequential API가 더 간결합니다.
레이어를 순서대로 쌓기만 하면 됩니다. 복잡한 분기 구조가 없다면 Sequential API가 편리합니다.
학습 시에는 **콜백(Callback)**을 활용하면 좋습니다. ModelCheckpoint는 매 에폭마다 모델을 저장합니다.
EarlyStopping은 검증 손실이 개선되지 않으면 학습을 조기 종료합니다. ReduceLROnPlateau는 성능이 정체되면 학습률을 자동으로 낮춥니다.
학습이 완료되면 model.save('my_model.h5')로 모델을 저장합니다. 나중에 tf.keras.models.load_model('my_model.h5')로 불러와서 예측에 사용할 수 있습니다.
웹 서비스나 앱에 배포할 때 필요합니다. 실무에서는 tf.data API를 더 많이 사용합니다.
ImageDataGenerator보다 성능이 좋고 유연합니다. 특히 대용량 데이터셋에서는 tf.data의 prefetch, cache 기능이 학습 속도를 크게 향상시킵니다.
하지만 입문 단계에서는 ImageDataGenerator가 더 이해하기 쉽습니다. 김개발 씨의 모델 학습이 완료되었습니다.
검증 정확도 92%를 달성했습니다. "이제 실제 서비스에 배포해볼까요?" 박시니어 씨가 물었습니다.
김개발 씨는 자신감 있게 대답했습니다. "네, 준비됐습니다!" 전이 학습을 마스터한 김개발 씨는 이제 어떤 이미지 분류 과제가 주어져도 당황하지 않습니다.
적은 데이터로도 높은 성능의 모델을 빠르게 구축할 수 있다는 자신감이 생겼습니다. 여러분도 오늘 배운 내용을 직접 프로젝트에 적용해보세요.
실전 팁
💡 - 데이터 증강은 학습 데이터에만 적용하고, 검증/테스트 데이터에는 적용하지 마세요
- 실무에서는 tf.data API를 사용하면 학습 속도가 크게 향상됩니다
- 모델 저장 후 반드시 다시 로드하여 예측이 정상 동작하는지 확인하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.