전이 학습이란?
전이 학습은 한 문제에서 학습된 지식을 관련된 다른 문제에 적용하는 기법입니다. 사람으로 비유하자면, 피아노를 배운 사람이 기타를 더 빨리 배울 수 있는 것과 같습니다. 기존에 습득한 지식과 경험이 새로운 분야를 익히는 데 도움이 되는 원리죠.
딥 러닝에서는 이미 훈련된 모델의 일부(주로 하위 층)를 가져와 새로운 모델에 적용하고, 새로운 데이터로 미세 조정하는 방식으로 이루어집니다.
전이 학습의 장점
- 적은 데이터로도 좋은 성능: 새로운 작업에 대한 데이터가 적어도, 기존 모델의 지식을 활용하여 좋은 성능을 낼 수 있습니다.
- 훈련 시간 단축: 처음부터 모델을 훈련시키는 것보다 훨씬 빠르게 모델을 개발할 수 있습니다.
- 더 나은 일반화: 전이 학습은 종종 더 나은 일반화 성능을 제공합니다.
딥러닝 모델의 구조 이해하기
전이 학습을 이해하기 위해 딥러닝 모델의 구조를 간단히 알아봅시다:
- 입력층: 데이터가 모델에 들어가는 첫 관문입니다.
- 은닉층(Hidden Layers): 여러 계층으로 이루어진 중간 처리 단계입니다.
- 하위 은닉층: 기본적인 패턴(선, 모서리, 색상 등)을 인식합니다.
- 상위 은닉층: 더 복잡한 패턴(눈, 코, 입 등의 특징)을 인식합니다.
- 출력층: 최종 결과를 내보내는 층입니다.
전이 학습의 기본 과정
- 기존 모델 선택: 비슷한 유형의 문제를 해결한 사전 훈련된 모델을 선택합니다.
- 예: 이미지 분류라면 ImageNet으로 훈련된 ResNet, VGG 등이 있습니다.
- 층 재사용 결정: 일반적으로 하위 은닉층은 그대로 가져오고, 상위 은닉층과 출력층은 새 문제에 맞게 수정합니다.
- 하위 은닉층: 기본적인 특징(선, 색상, 텍스처 등)을 인식하므로 대부분의 문제에서 재사용 가능합니다.
- 상위 은닉층: 좀 더 문제 특화된 특징을 인식하므로, 문제 유사성에 따라 재사용 여부를 결정합니다.
- 재사용층 동결(Freezing): 가져온 층의 가중치가 훈련 중에 변하지 않도록 "동결"합니다. 이렇게 하면 기존 지식이 보존됩니다.
- 새 데이터로 훈련: 새 문제에 맞는 데이터로 변형된 모델을 훈련시킵니다.
- 미세 조정(Fine-tuning): 성능을 높이기 위해 동결된 일부 층을 해제하고 낮은 학습률로 추가 훈련할 수 있습니다.
파이썬으로 구현하는 전이 학습 예제
이제 TensorFlow/Keras를 사용한 전이 학습 실습을 해보겠습니다.
패션 MNIST 데이터셋을 특별한 방식으로 분할하여, 두 개의 관련된 작업을 만들어 전이 학습의 효과를 확인해보겠습니다.
1. 필요한 라이브러리 임포트
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
2. 데이터 준비
패션 MNIST 데이터셋을 로드하고 전처리합니다.
X_train_full = X_train_full / 255.0 # 0-1 범위로 정규화
X_test = X_test / 255.0
X_valid, X_train = X_train_full[:5000], X_train_full[5000:]
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]
이제 데이터셋을 두 가지 다른 작업으로 분할합니다:
- 작업 A: 샌들(클래스 5)과 셔츠(클래스 6)를 제외한 8개 클래스 분류
- 작업 B: "이것이 셔츠인가요?"라는 이진 분류 문제
# 샌들이나 셔츠에 해당하는 인덱스 식별
y_5_or_6 = (y == 5) | (y == 6)
# 작업 A 데이터 생성 (샌들/셔츠 제외)
y_A = y[~y_5_or_6]
y_A[y_A > 6] -= 2 # 클래스 7,8,9를 5,6,7로 이동
# 작업 B 데이터 생성 (이진 분류: 셔츠=1, 샌들=0)
y_B = (y[y_5_or_6] == 6).astype(np.float32)
return ((X[~y_5_or_6], y_A), (X[y_5_or_6], y_B))
# 데이터셋 분할 적용
(X_train_A, y_train_A), (X_train_B, y_train_B) = split_dataset(X_train, y_train)
(X_valid_A, y_valid_A), (X_valid_B, y_valid_B) = split_dataset(X_valid, y_valid)
(X_test_A, y_test_A), (X_test_B, y_test_B) = split_dataset(X_test, y_test)
# 작업 B의 학습 데이터를 의도적으로 적게 유지 (전이 학습 효과를 더 잘 보기 위해)
X_train_B = X_train_B[:10]
y_train_B = y_train_B[:10]
여기서 주목할 점은 작업 B의 훈련 데이터를 일부러 10개만 사용한다는 것입니다.
이는 데이터가 제한적일 때 전이 학습의 효과를 더 극적으로 보여주기 위함입니다.
3. 소스 모델(작업 A용) 훈련
먼저 샌들/셔츠를 제외한 8개 클래스를 분류하는 모델 A를 훈련합니다.
np.random.seed(42)
model_A = keras.models.Sequential()
model_A.add(keras.layers.Flatten(input_shape=[28, 28]))
for n_hidden in (300, 100, 50, 50, 50):
model_A.add(keras.layers.Dense(n_hidden, activation="relu"))
model_A.add(keras.layers.Dense(8, activation="softmax"))
model_A.compile(loss="sparse_categorical_crossentropy",
optimizer=keras.optimizers.SGD(learning_rate=1e-2),
metrics=["accuracy"])
history = model_A.fit(X_train_A, y_train_A, epochs=20,
validation_data=(X_valid_A, y_valid_A))
이 모델은 8개 클래스 분류 문제에 대해 훈련되며, 약 93%의 검증 정확도를 달성합니다.
4. 비교 모델(전이 학습 없이) 훈련
비교를 위해, 전이 학습 없이 처음부터 훈련하는 모델 B를 만들어 보겠습니다.
model_B = keras.models.Sequential()
model_B.add(keras.layers.Flatten(input_shape=[28, 28]))
for n_hidden in (300, 100, 50, 50, 50):
model_B.add(keras.layers.Dense(n_hidden, activation="relu"))
model_B.add(keras.layers.Dense(1, activation="sigmoid"))
model_B.compile(loss="binary_crossentropy",
optimizer=keras.optimizers.SGD(learning_rate=1e-2),
metrics=["accuracy"])
history = model_B.fit(X_train_B, y_train_B, epochs=20,
validation_data=(X_valid_B, y_valid_B))
10개의 훈련 데이터만으로는 모델 B가 제대로 학습하지 못하고, 검증 정확도는 약 51% 정도에 그칩니다(거의 랜덤한 추측 수준).
5. 전이 학습 모델 구성
이제 모델 A의 지식을 활용하여 작업 B를 위한 전이 학습 모델을 구성합니다.
# 모델 A의 복사본 생성
model_A_clone = keras.models.clone_model(model_A)
model_A_clone.set_weights(model_A.get_weights())
# 모델 A의 층들을 가져와 모델 B 생성 (출력층 제외)
model_B_on_A = keras.models.Sequential(model_A_clone.layers[:-1])
model_B_on_A.add(keras.layers.Dense(1, activation="sigmoid"))
이 코드에서 주목할 점:
- 먼저 모델 A를 복제합니다(원본을 그대로 유지하기 위해).
- 복제된 모델에서 출력층을 제외한 모든 층을 가져옵니다.
- 이진 분류에 적합한 새로운 출력층(뉴런 1개, 시그모이드 활성화 함수)을 추가합니다.
6. 전이 학습 1단계: 사전 훈련된 층 동결
전이 학습의 첫 단계에서는 모델 A에서 가져온 층들을 '동결'(훈련 불가능하게 설정)하고, 새로운 출력층만 훈련합니다.
# 모델 A에서 가져온 모든 층 동결
for layer in model_B_on_A.layers[:-1]:
layer.trainable = False
model_B_on_A.compile(loss="binary_crossentropy",
optimizer=keras.optimizers.SGD(learning_rate=1e-2),
metrics=["accuracy"])
# 출력층만 훈련
history = model_B_on_A.fit(X_train_B, y_train_B, epochs=4,
validation_data=(X_valid_B, y_valid_B))
이렇게 하면 새로운 출력층이 기존 특징 추출기(모델 A에서 가져온 층들)에 적응할 시간을 갖게 됩니다.
7. 전이 학습 2단계: 미세 조정
두 번째 단계에서는 마지막 은닉층도 함께 훈련하여 모델을 미세 조정합니다.
# 마지막 은닉층의 동결 해제
model_B_on_A.layers[-2].trainable = True
model_B_on_A.compile(loss="binary_crossentropy",
optimizer=keras.optimizers.SGD(learning_rate=1e-2),
metrics=["accuracy"])
# 추가 훈련
history = model_B_on_A.fit(X_train_B, y_train_B, epochs=16,
validation_data=(X_valid_B, y_valid_B))
마지막 은닉층과 출력층을 함께 훈련함으로써 모델은 새로운 작업에 더 적합하게 조정됩니다.
결과 비교
최종 결과를 확인해 보면:
- 전이 학습 없이 처음부터 훈련한 모델 B: 51% 정확도
- 전이 학습을 적용한 모델: 98.7% 정확도
단 10개의 훈련 샘플로도 전이 학습 모델은 거의 완벽한 성능을 보여주었습니다. 이는 모델 A에서 학습한 일반적인 특징들이 모델 B의 작업에도 유용하게 적용되었다는 것을 의미합니다.
전이 학습 사용 시 주의사항
전이 학습이 항상 마법처럼 작동하는 것은 아닙니다. 실무에서 전이 학습을 적용할 때 고려해야 할 몇 가지 중요한 주의사항이 있습니다:
- 재현성 문제: 많은 논문에서 전이 학습의 긍정적인 결과만 보고하는 경우가 있습니다. 연구자들은 종종 "될 때까지 데이터 들들 볶기"라 불리는 방식으로 여러 시도를 해보고 가장 좋은 결과만 발표하기도 합니다.
- 초기 조건에 민감: 타겟 클래스(예: 셔츠)나 랜덤 초기값을 바꾸는 것만으로도 성능이 크게 떨어질 수 있습니다. 심지어 일부 경우에는 전이 학습을 적용했을 때 성능이 오히려 더 나빠지기도 합니다.
- 모든 아키텍처에 적합하지 않음: 전이 학습은 작은 완전 연결 네트워크에서는 잘 작동하지 않는 경향이 있습니다. 이는 작은 네트워크가 패턴을 적게 학습하고, 완전 연결 네트워크가 특정 작업에 너무 특화된(다른 작업에 유용하지 않은) 패턴을 학습하기 때문으로 추정됩니다.
- CNN에서 더 효과적: 전이 학습은 특히 하위 층에서 일반적인 특성을 감지하는 경향이 있는 심층 합성곱 신경망(CNN)에서 더 효과적으로 작동합니다.
- 비판적 평가 필요: 지나치게 긍정적인 논문 결과는 건강한 의심의 눈초리로 바라볼 필요가 있습니다. 연구자들은 종종 연구 과정에서 겪은 많은 실패를 언급하지 않는 경우가 많습니다.
- 시행착오 과정: 성공적인 전이 학습 구현은 보통 수많은 시행착오 끝에 이루어집니다. 이 방법이 잘 작동하는 데에는 특정 조건과 상황이 요구되며, 모든 상황에서 마법처럼 작동하지는 않습니다.
이러한 주의사항을 염두에 두고 전이 학습을 적용한다면, 기대치를 현실적으로 관리하고 보다 효과적으로 모델을 개발할 수 있을 것입니다. 새로운 기술이 현란하게 보이더라도 실제로 큰 도움이 되지 않는 경우도 있습니다.
'전공 > 신경망딥러닝' 카테고리의 다른 글
신경망딥러닝(13)_큰 dataset 처리 with tf dataset API (0) | 2025.04.17 |
---|---|
신경망딥러닝(11)_딥러닝 학습 순서 전체 정리 (0) | 2025.04.10 |
신경망딥러닝(1)_개요 (0) | 2025.04.03 |
신경망딥러닝(1)_batch와 epoke (0) | 2025.04.03 |