Post

딥러닝 전이학습(Transfer Learning)

딥러닝 전이학습(Transfer Learning)

딥러닝 전이 학습(Transfer Learning) 완벽 가이드: 효율적인 모델 개발 전략

1. 딥러닝 모델의 깊이와 문제점

딥러닝 모델은 Layer를 깊게 쌓을수록 추상화된 특징을 추출하는 능력이 향상됩니다. 하지만 Layer가 깊어질수록 학습 시간이 길어지는 문제가 발생합니다. 이러한 문제를 해결하기 위한 효과적인 방법 중 하나가 바로 전이 학습(Transfer Learning)입니다.

또 다른 문제점으로는 기울기 소실(Vanishing Gradient) 문제가 있습니다. 이는 Layer가 깊어질수록 초기 Layer까지 기울기가 제대로 전달되지 않아 학습이 어려워지는 현상을 말합니다. 이러한 기울기 소실 문제를 해결하기 위해 다양한 네트워크 설계 방법들이 연구되고 있습니다.

  • Deeper: VGGNet, ResNet(Residual Block), DenseNet(Dense Block), NasNet
  • Wider: GoogLeNet, InceptionV4, Xception, MobileNet, MixNet
  • EfficientNet: Wider, Deeper, Resolution을 복합적으로 고려한 모델

2. 전이 학습(Transfer Learning)이란?

전이 학습은 이미 학습된 모델을 가져와서 다른 문제에 적용하는 기술입니다. 일반적으로 대규모 데이터셋으로 학습된 모델은 이미지의 일반적인 특징을 잘 학습하고 있습니다. 이러한 특징 추출 능력을 활용하여 비교적 작은 데이터셋으로도 높은 성능을 얻을 수 있습니다.

3. 딥러닝 모델 개발 시 고려사항

  • 초기화(Initialization): 가중치 초기화 방법은 모델 학습에 큰 영향을 미칩니다. He Normal Initialization, Glorot Uniform Initialization 등 다양한 초기화 방법들이 있습니다.
  • 정규화(Normalization): Batch Normalization 등을 통해 학습 과정에서 데이터 분포를 안정화시켜 학습 속도를 높이고 성능을 향상시킬 수 있습니다.
  • 활성화 함수(Activation Function): ReLU, Sigmoid, Tanh 등 다양한 활성화 함수들이 있으며, 문제에 적합한 활성화 함수를 선택하는 것이 중요합니다.
  • 규제화(Regularization): Dropout 등을 통해 모델의 과적합을 방지하고 일반화 성능을 향상시킬 수 있습니다.
  • 최적화 알고리즘(Optimizer): SGD, Adam, RMSprop 등 다양한 최적화 알고리즘들이 있으며, 적절한 알고리즘을 선택하여 학습 속도와 성능을 높일 수 있습니다.
  • 학습률 스케줄링(Learning Rate Scheduling): 학습 진행에 따라 학습률을 조절하여 학습 효율성을 높일 수 있습니다.

4. 이미지 증강(Image Augmentation)

이미지 증강은 학습 데이터를 늘리는 기술입니다. 이미지 데이터를 회전, 이동, 크기 변경, 밝기 조절 등 다양한 변환을 통해 새로운 데이터를 생성합니다. 이를 통해 모델의 과적합을 방지하고 일반화 성능을 향상시킬 수 있습니다.

import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.preprocessing import image from PIL import Image

def visualize_augmented_images(image_path, num_images=9): try: img = Image.open(image_path) img_array = image.img_to_array(img) img_array = np.expand_dims(img_array, axis=0)

# 이미지 증강 설정 datagen = ImageDataGenerator( horizontal_flip=True, vertical_flip=True, rotation_range=40, zoom_range=0.2, brightness_range=[0.5, 1.5], fill_mode='nearest', channel_shift_range=50.0, ) plt.figure(figsize=(10, 10)) i = 0 for batch in datagen.flow(img_array, batch_size=1): plt.subplot(3, 3, i + 1) plt.imshow(image.array_to_img(batch[0])) plt.axis('off') i += 1 if i >= num_images: break plt.show() except FileNotFoundError: print(f"오류: {image_path} 파일을 찾을 수 없습니다.") except Exception as e: print(f"오류: {e}")

image_path = “/content/카리나.jpg” # 이미지 파일 경로 visualize_augmented_images(image_path)

위 코드는 ImageDataGenerator를 사용하여 이미지 증강을 수행하고, 증강된 이미지를 시각화하는 예제입니다.

5. 전이 학습 모델 구현 예제

import sklearn import scikeras import tensorflow

print(f”Scikit-learn version: {sklearn.version}”) print(f”Scikeras version: {scikeras.version}”) print(f”TensorFlow version: {tf.version}”)

import tensorflow as tf from tensorflow.keras.datasets import cifar10 from tensorflow.keras.models import Sequential, Model, load_model from tensorflow.keras.layers import Dense, Dropout, Flatten, Input, GlobalAveragePooling2D from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau from tensorflow.keras.utils import to_categorical from tensorflow.keras.applications import VGG16, MobileNetV2 # 사전 훈련된 모델 임포트 from tensorflow.keras.optimizers import Adam, RMSprop from scikeras.wrappers import KerasClassifier from sklearn.model_selection import RandomizedSearchCV import numpy as np import os import time import glob import re

# — 1. 기본 설정 및 모델 저장 경로 — # Google Drive 또는 로컬 경로 MODEL_DIR = ‘./cifar10_models/’ # 편의상 로컬 디렉토리 사용 if not os.path.exists(MODEL_DIR): os.makedirs(MODEL_DIR) print(f”디렉토리 생성됨: {MODEL_DIR}”)

# — 데이터 준비 (CIFAR-10) — print(“CIFAR-10 데이터 로딩 및 전처리 시작…”) try: (X_train, Y_train), (X_test, Y_test) = cifar10.load_data()

# 데이터 정규화 X_train = X_train.astype('float32') / 255.0 X_test = X_test.astype('float32') / 255.0 # 레이블 원-핫 인코딩 num_classes = 10 Y_train = to_categorical(Y_train, num_classes) Y_test = to_categorical(Y_test, num_classes) print("데이터 준비 완료.") print(f"X_train shape: {X_train.shape}, Y_train shape: {Y_train.shape}") print(f"X_test shape: {X_test.shape}, Y_test shape: {Y_test.shape}") except Exception as e: print(f"데이터 로딩/처리 중 오류 발생: {e}") print("실행을 중단합니다. 데이터를 확인해주세요.") exit()

# — 1.5 이전 실행에서 저장된 최상의 모델 확인 및 평가 — print(“\n— 이전 최상의 모델 확인 —”) previous_best_model_path = None # 저장된 최종 모델 파일 패턴 검색 (필요시 패턴 조정) final_model_pattern = os.path.join( MODEL_DIR, ‘best_cifar10model_randomized*.keras’) previous_model_files = glob.glob(final_model_pattern)

if previous_model_files: # 수정 시간 기준으로 최신 파일 찾기 previous_model_files.sort(key=os.path.getmtime, reverse=True) previous_best_model_path = previous_model_files[0] print(f”이전에 저장된 최신 모델 발견: {previous_best_model_path}”)

try: print("이전 최신 모델 로드 및 평가 중...") if X_test is not None and Y_test is not None: previous_model = load_model(previous_best_model_path) loss, accuracy = previous_model.evaluate(X_test, Y_test, verbose=0) print(f" - Test Loss: {loss:.4f}") print(f" - Test Accuracy: {accuracy:.4f}") else: # 원본 오타 유지: 건너<0xEB><0x8Skip>니다 -> 건너뜁니다 print(" - 테스트 데이터가 준비되지 않아 평가를 건너뜁니다.") except Exception as e: print(f"이전 모델 로드 또는 평가 중 오류 발생: {e}") previous_best_model_path = None # 오류 시 경로 초기화 else: print("이전에 저장된 최종 모델 파일을 찾을 수 없습니다.")

print(“—————————-\n”)

# — 2. Keras 전이 학습 모델 정의 함수 — def create_transfer_model(base_model_name=’MobileNetV2’, dense_activation=’relu’, input_shape=(32, 32, 3), num_classes=10): “”” 지정된 베이스 모델을 사용하여 전이 학습 모델을 생성합니다. 추가된 Dense 레이어의 활성화 함수 튜닝을 허용합니다. “”” if base_model_name == ‘VGG16’: # weights=’imagenet’은 사전 훈련된 가중치를 사용하겠다는 의미입니다. # 로컬에 가중치 파일이 없으면 Keras가 자동으로 다운로드합니다. base_model = VGG16( weights=’imagenet’, include_top=False, input_shape=input_shape) print(f”VGG16 베이스 모델 로드 완료 (필요시 가중치 다운로드됨).”) elif base_model_name == ‘MobileNetV2’: # weights=’imagenet’은 사전 훈련된 가중치를 사용하겠다는 의미입니다. # 로컬에 가중치 파일이 없으면 Keras가 자동으로 다운로드합니다. base_model = MobileNetV2( weights=’imagenet’, include_top=False, input_shape=input_shape) print(f”MobileNetV2 베이스 모델 로드 완료 (필요시 가중치 다운로드됨).”) else: raise ValueError(f”지원되지 않는 베이스 모델: {base_model_name}”)

# 베이스 모델 레이어 동결 base_model.trainable = False # 커스텀 레이어 추가 inputs = Input(shape=input_shape) x = base_model(inputs, training=False) # 중요: 동결된 레이어에는 training=False 사용 x = GlobalAveragePooling2D()(x) x = Dense(128, activation=dense_activation)(x) # 튜닝 가능한 활성화 함수 x = Dropout(0.5)(x) outputs = Dense(num_classes, activation='softmax')(x) model = Model(inputs, outputs, name=f"Transfer_{base_model_name}") # 참고: 컴파일(옵티마이저, 손실 함수, 메트릭)은 KerasClassifier가 처리합니다. return model

# — 3. 콜백 정의 — early_stopping = EarlyStopping( monitor=’val_loss’, patience=10, verbose=1, restore_best_weights=True) # 최상의 가중치 복원은 유용함

# ReduceLROnPlateau: 검증 손실 개선이 멈췄을 때 학습률을 동적으로 감소시킵니다. reduce_lr = ReduceLROnPlateau( monitor=’val_loss’, factor=0.2, patience=5, min_lr=1e-6, verbose=1)

# ModelCheckpoint 파일 경로 (RandomizedSearch 내 각 fit 마다 임시 파일 사용) # 각 CV 폴드 및 하이퍼파라미터 조합 내에서 최적 모델을 임시 저장하기 위함 checkpoint_path_template = os.path.join( MODEL_DIR, ‘temp_best_in_fit_cifar10.keras’) model_checkpoint = ModelCheckpoint( filepath=checkpoint_path_template, monitor=’val_loss’, verbose=0, # 탐색 중에는 verbose 낮게 유지 save_best_only=True, save_weights_only=False # 전체 모델 저장 )

# 콜백 결합 callbacks = [early_stopping, model_checkpoint, reduce_lr]

# — 4. 하이퍼파라미터 분포 정의 — param_distributions = { ‘model__base_model_name’: [‘MobileNetV2’, ‘VGG16’], # 베이스 모델 튜닝 ‘model__dense_activation’: [‘relu’, ‘tanh’], # Dense 레이어 활성화 함수 튜닝 ‘optimizer’: [Adam, RMSprop], # 옵티마이저 튜닝 (클래스 전달) ‘optimizer__learning_rate’: [0.001, 0.0005, 0.0001], # 학습률 튜닝 ‘batch_size’: [32, 64], # 배치 크기 튜닝 # 필요한 경우 드롭아웃 비율 등 다른 파라미터 추가, 예: ‘model__dropout_rate’: [0.3, 0.5] # (create_transfer_model 함수에서 dropout_rate를 받도록 수정 필요) }

# — 5. KerasClassifier 래퍼 설정 — # 참고: create_transfer_model 함수를 래퍼에 전달합니다. keras_clf = KerasClassifier( model=create_transfer_model, # 빌드된 모델 인스턴스가 아닌 함수 전달 input_shape=(32, 32, 3), # 모델 함수에 필요한 고정 인자 전달 num_classes=num_classes, # 모델 함수에 필요한 고정 인자 전달 loss=”categorical_crossentropy”, # 컴파일 설정: 손실 함수 metrics=[“accuracy”], # 컴파일 설정: 평가 지표 callbacks=callbacks, # 학습 시 사용할 콜백 verbose=0 # 분류기 자체의 verbose=0 설정, RandomizedSearchCV의 verbose로 출력 제어 )

# — 6. RandomizedSearchCV 설정 — n_iterations = 6 # 샘플링할 파라미터 설정 수 (필요에 따라 조정) cv_folds = 3 # 교차 검증 폴드 수 (데이터 크기/시간에 따라 조정)

random_search = RandomizedSearchCV( estimator=keras_clf, # Keras 모델을 래핑한 분류기 param_distributions=param_distributions, # 탐색할 하이퍼파라미터 공간 n_iter=n_iterations, # 시도할 파라미터 조합 수 cv=cv_folds, # 교차 검증 폴드 수 verbose=2, # 각 반복에 대한 진행 상황 표시 레벨 n_jobs=1, # GPU 사용 시 n_jobs=1 설정 권장 (TF와 다중 프로세싱 충돌 방지) random_state=42, # 결과 재현을 위한 난수 시드 refit=True # 최적 파라미터로 전체 학습 데이터에 대해 모델 재학습 여부 (기본값 True) )

# — 7. RandomizedSearchCV 실행 — (주석 번호 수정: 7번) print(f”\nRandomizedSearchCV 시작 (n_iter={n_iterations}, cv={cv_folds})…”) start_time = time.time()

# RandomizedSearchCV 내에서 호출되는 ‘fit’ 메서드의 공통 파라미터 # CV 내에서 validation_split 사용 시 학습 폴드를 추가로 분할하여 검증 데이터로 사용 common_fit_params = { ‘epochs’: 30, # 각 시도당 최대 에포크 (EarlyStopping이 더 일찍 중단시킬 가능성 높음) ‘validation_split’: 0.1 # 각 CV 분할 내에서 검증을 위해 학습 폴드 데이터의 10% 사용 }

# 탐색 실행 (X_train, Y_train 사용) random_result = random_search.fit(X_train, Y_train, **common_fit_params)

end_time = time.time() print(f”\nRandomizedSearchCV 완료. 총 소요 시간: {end_time - start_time:.2f} 초”)

# — 8. 결과 출력 및 최상의 모델 저장 — (주석 번호 수정: 8번)

print( f”\nRandomizedSearch에서 찾은 최고 점수 (교차 검증 평균 accuracy): {random_result.best_score_:.4f}”) print(f”RandomizedSearch에서 찾은 최적 파라미터: {random_result.best_params_}”)

# 최상의 모델 가져오기 (refit=True 이므로 전체 X_train, Y_train에서 최적 파라미터로 재학습됨) # best_estimator_ 속성은 KerasClassifier 래퍼를 가짐 # 실제 Keras 모델은 래퍼의 .model_ 속성을 통해 접근 best_keras_model = random_result.best_estimator_.model_

# 최종 모델 저장 파일 이름 (타임스탬프 사용) timestamp = time.strftime(“%Y%m%d-%H%M%S”) best_model_filename = f”best_cifar10model_randomized{timestamp}.keras” best_model_path = os.path.join(MODEL_DIR, best_model_filename)

try: # RandomizedSearchCV가 찾고 재학습한 최상의 Keras 모델 저장 best_keras_model.save(best_model_path) print(f”\n최상의 모델 (재학습됨)이 저장되었습니다: {best_model_path}”) print(“\n저장된 최상의 모델 최종 평가 (Test Set):”)

# 최종 테스트 데이터로 성능 평가 loss, accuracy = best_keras_model.evaluate(X_test, Y_test, verbose=1) print(f" - Test Loss: {loss:.4f}") print(f" - Test Accuracy: {accuracy:.4f}") # 이전 실행의 최상 모델과 비교 (사용 가능한 경우) if previous_best_model_path: print("\n(참고) 이전 실행 최신 모델과 성능 비교:") # 이전 모델의 성능을 다시 출력하거나 필요 시 재평가 try: previous_model = load_model(previous_best_model_path) prev_loss, prev_accuracy = previous_model.evaluate( X_test, Y_test, verbose=0) print( f" - 이전 실행 최신 모델 Test Accuracy: {prev_accuracy:.4f}") print(f" - 이번 실행 최종 Test Accuracy: {accuracy:.4f}") except Exception as e: print(f" - 이전 모델 재평가 중 오류: {e}")

except Exception as e: print(f”\n최상의 모델 저장 또는 최종 평가 중 오류 발생: {e}”)

# 임시 체크포인트 파일 삭제 (선택 사항) try: # RandomizedSearchCV의 각 fit에서 사용된 임시 파일 삭제 시도 temp_checkpoint_pattern = os.path.join( MODEL_DIR, ‘temp_best_in_fit_cifar10*.keras’) temp_files = glob.glob(temp_checkpoint_pattern) for f in temp_files: if os.path.exists(f): os.remove(f) print(f”\n임시 체크포인트 파일 삭제 완료: {f}”) except Exception as e: print(f”\n임시 체크포인트 파일 삭제 실패: {e}”)

print(“\n스크립트 실행 완료.”)

위 코드는 CIFAR-10 데이터셋을 이용하여 전이 학습 모델을 구현하고, RandomizedSearchCV를 이용하여 하이퍼파라미터를 튜닝하는 예제입니다.

6. 결론: 딥러닝 모델 개발, 이제 효율적으로!

이 튜토리얼에서는 딥러닝 모델 개발 시 고려해야 할 다양한 요소들과 효율적인 모델 개발 전략인 전이 학습에 대해 자세히 알아보았습니다. 예제 코드를 통해 실제 모델을 구현하고 학습하는 과정을 살펴보았습니다. 딥러닝 모델 개발은 복잡하고 어려운 과정이지만, 전이 학습과 효율적인 개발 전략을 활용한다면 더욱 빠르고 효과적으로 원하는 결과를 얻을 수 있습니다.

This post is licensed under CC BY 4.0 by the author.