728x90
반응형


데이터 입력부터 가중치 업데이트, 그리고 테스트까지 어떤 순서로 진행되는지 알아보려고 합니다.
이 글에서는 딥러닝의 학습 전 과정에 대해, 특히 Activation FunctionOptimizer의 역할을 확실히 구별하여 전체 흐름을 이해하기 쉽게 정리했습니다.

1. 딥러닝 학습의 전체 흐름 요약

  1. 데이터 입력
  2. 순전파 (Forward Propagation)
  3. 손실 함수 계산 (Loss)
  4. 역전파 (Backpropagation)
  5. 옵티마이저로 가중치 업데이트
  6. 위 과정을 여러 Epoch 반복
  7. 학습 완료 후 테스트 데이터로 성능 평가

2. Step by Step 자세히 설명

1️⃣ 데이터 입력 및 전처리

  • 학습에 사용할 데이터를 모델에 넣습니다.
  • 예: 이미지 → 픽셀 값, 텍스트 → 임베딩 벡터 등
  • 표준화 등을 통해 전처리를 합니다.

2️⃣ 순전파 (Forward Propagation)

입력 데이터를 이용해 초기 예측값(y^hat)을 계산하는 과정입니다.

🔸 2-1. 가중치 연산

       z=w⋅x+b

🔸 2-2. 활성화 함수(Activation Function)

       a = f(z)

  • ReLU, Sigmoid, Tanh 등 사용
  • 선형으로 z를 계산한 뒤에 출력값에는 비선형성을 부여하여 복잡한 문제 해결 가능

이 과정이 여러 레이어(뉴런들)들을 거치면서 반복됩니다.

3️⃣ 출력층 → 예측값 도출

  • 마지막 레이어에서 초기 예측값 을 출력
  • 마지막 레이어에서는 Softmax (분류), Linear (회귀) 등 사용

4️⃣ 손실 함수 계산 (Loss Function)

  • 예측값과 실제값 사이의 오차를 계산합니다.

        L=loss(y,y^hat)

  • 예:
    • 이진 분류: Binary Cross-Entropy
    • 다중 분류: Categorical Cross-Entropy
    • 회귀: Mean Squared Error (MSE)

5️⃣ 역전파 (Backpropagation)

이제 이 Loss를 기준으로 각 파라미터(w, b)에 대해 미분을 시작합니다. 손실 값을 줄이기 위해 각 가중치가 얼마나 영향을 줬는지 계산합니다. 

  • 가중치에 대한 미분, bias에 대한 미분
  • 핵심은 "출력층부터 입력층으로 거꾸로" 가는 것 입니다.

6️⃣ 옵티마이저(Optimizer)로 가중치 업데이트

경사(gradient)를 이용해 파라미터를 조정합니다.

  • SGD

  • Adam, RMSProp 등은 이 과정을 더 정교하게 개선

7️⃣ Epoch만큼 반복 학습

  • 위 과정을 전체 데이터셋에 대해 수천~수만 번 반복
  • 모델이 점점 똑똑해짐!
 
model.fit(x_train, y_train, epochs=10)

8️⃣ (선택) Validation으로 중간 성능 확인

  • 학습 중 과적합 여부 확인
  • 조기 종료(Early Stopping), 학습률 조정 등에 사용
model.fit(x_train, y_train, validation_data=(x_val, y_val))

 

9️⃣ 테스트(Test) 데이터로 성능 평가

학습에 사용되지 않은 데이터를 이용해 모델의 일반화 능력 평가
 
test_loss, test_accuracy = model.evaluate(x_test, y_test)
print("Test Accuracy:", test_accuracy)
  • 역전파 ❌ 없음
  • 가중치 업데이트 ❌ 없음
  • 순전파만 수행하여 예측값을 출력

3. 정리

Activation Function 뉴런의 출력 결정, 비선형성 부여
Optimizer 손실을 줄이기 위해 파라미터 업데이트
Epoch 전체 데이터셋을 1번 학습하는 단위
Test 단계 학습에 사용되지 않은 데이터로 성능 확인

이 글 하나로 딥러닝의 학습과 테스트 전 과정을 흐름을 이해하셨길 바랍니다.
감사합니다!

728x90
반응형
728x90
반응형

전이 학습이란?

전이 학습은 한 문제에서 학습된 지식을 관련된 다른 문제에 적용하는 기법입니다. 사람으로 비유하자면, 피아노를 배운 사람이 기타를 더 빨리 배울 수 있는 것과 같습니다. 기존에 습득한 지식과 경험이 새로운 분야를 익히는 데 도움이 되는 원리죠.

딥 러닝에서는 이미 훈련된 모델의 일부(주로 하위 층)를 가져와 새로운 모델에 적용하고, 새로운 데이터로 미세 조정하는 방식으로 이루어집니다.

 

 

전이 학습의 장점

  1. 적은 데이터로도 좋은 성능: 새로운 작업에 대한 데이터가 적어도, 기존 모델의 지식을 활용하여 좋은 성능을 낼 수 있습니다.
  2. 훈련 시간 단축: 처음부터 모델을 훈련시키는 것보다 훨씬 빠르게 모델을 개발할 수 있습니다.
  3. 더 나은 일반화: 전이 학습은 종종 더 나은 일반화 성능을 제공합니다.

 

딥러닝 모델의 구조 이해하기

전이 학습을 이해하기 위해 딥러닝 모델의 구조를 간단히 알아봅시다:

  • 입력층: 데이터가 모델에 들어가는 첫 관문입니다.
  • 은닉층(Hidden Layers): 여러 계층으로 이루어진 중간 처리 단계입니다.
    • 하위 은닉층: 기본적인 패턴(선, 모서리, 색상 등)을 인식합니다.
    • 상위 은닉층: 더 복잡한 패턴(눈, 코, 입 등의 특징)을 인식합니다.
  • 출력층: 최종 결과를 내보내는 층입니다.

 

전이 학습의 기본 과정

  1. 기존 모델 선택: 비슷한 유형의 문제를 해결한 사전 훈련된 모델을 선택합니다.
    • 예: 이미지 분류라면 ImageNet으로 훈련된 ResNet, VGG 등이 있습니다.
  2. 층 재사용 결정: 일반적으로 하위 은닉층은 그대로 가져오고, 상위 은닉층과 출력층은 새 문제에 맞게 수정합니다.
    • 하위 은닉층: 기본적인 특징(선, 색상, 텍스처 등)을 인식하므로 대부분의 문제에서 재사용 가능합니다.
    • 상위 은닉층: 좀 더 문제 특화된 특징을 인식하므로, 문제 유사성에 따라 재사용 여부를 결정합니다.
  3. 재사용층 동결(Freezing): 가져온 층의 가중치가 훈련 중에 변하지 않도록 "동결"합니다. 이렇게 하면 기존 지식이 보존됩니다.
  4. 새 데이터로 훈련: 새 문제에 맞는 데이터로 변형된 모델을 훈련시킵니다.
  5. 미세 조정(Fine-tuning): 성능을 높이기 위해 동결된 일부 층을 해제하고 낮은 학습률로 추가 훈련할 수 있습니다.

 

파이썬으로 구현하는 전이 학습 예제

이제 TensorFlow/Keras를 사용한 전이 학습 실습을 해보겠습니다.

패션 MNIST 데이터셋을 특별한 방식으로 분할하여, 두 개의 관련된 작업을 만들어 전이 학습의 효과를 확인해보겠습니다.

1. 필요한 라이브러리 임포트

import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

2. 데이터 준비

패션 MNIST 데이터셋을 로드하고 전처리합니다.

(X_train_full, y_train_full), (X_test, y_test) = keras.datasets.fashion_mnist.load_data()
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: "이것이 셔츠인가요?"라는 이진 분류 문제
def split_dataset(X, y):
    # 샌들이나 셔츠에 해당하는 인덱스 식별
    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를 훈련합니다.

tf.random.set_seed(42)  # 재현성을 위한 시드 설정
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"))

 

이 코드에서 주목할 점:

  1. 먼저 모델 A를 복제합니다(원본을 그대로 유지하기 위해).
  2. 복제된 모델에서 출력층을 제외한 모든 층을 가져옵니다.
  3. 이진 분류에 적합한 새로운 출력층(뉴런 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의 작업에도 유용하게 적용되었다는 것을 의미합니다.

 

 

전이 학습 사용 시 주의사항

전이 학습이 항상 마법처럼 작동하는 것은 아닙니다. 실무에서 전이 학습을 적용할 때 고려해야 할 몇 가지 중요한 주의사항이 있습니다:

  1. 재현성 문제: 많은 논문에서 전이 학습의 긍정적인 결과만 보고하는 경우가 있습니다. 연구자들은 종종 "될 때까지 데이터 들들 볶기"라 불리는 방식으로 여러 시도를 해보고 가장 좋은 결과만 발표하기도 합니다.
  2. 초기 조건에 민감: 타겟 클래스(예: 셔츠)나 랜덤 초기값을 바꾸는 것만으로도 성능이 크게 떨어질 수 있습니다. 심지어 일부 경우에는 전이 학습을 적용했을 때 성능이 오히려 더 나빠지기도 합니다.
  3. 모든 아키텍처에 적합하지 않음: 전이 학습은 작은 완전 연결 네트워크에서는 잘 작동하지 않는 경향이 있습니다. 이는 작은 네트워크가 패턴을 적게 학습하고, 완전 연결 네트워크가 특정 작업에 너무 특화된(다른 작업에 유용하지 않은) 패턴을 학습하기 때문으로 추정됩니다.
  4. CNN에서 더 효과적: 전이 학습은 특히 하위 층에서 일반적인 특성을 감지하는 경향이 있는 심층 합성곱 신경망(CNN)에서 더 효과적으로 작동합니다.
  5. 비판적 평가 필요: 지나치게 긍정적인 논문 결과는 건강한 의심의 눈초리로 바라볼 필요가 있습니다. 연구자들은 종종 연구 과정에서 겪은 많은 실패를 언급하지 않는 경우가 많습니다.
  6. 시행착오 과정: 성공적인 전이 학습 구현은 보통 수많은 시행착오 끝에 이루어집니다. 이 방법이 잘 작동하는 데에는 특정 조건과 상황이 요구되며, 모든 상황에서 마법처럼 작동하지는 않습니다.

이러한 주의사항을 염두에 두고 전이 학습을 적용한다면, 기대치를 현실적으로 관리하고 보다 효과적으로 모델을 개발할 수 있을 것입니다. 새로운 기술이 현란하게 보이더라도 실제로 큰 도움이 되지 않는 경우도 있습니다.

728x90
반응형
728x90
반응형

 

전체 데이터셋 : 1000개 데이터

batch size : 100

각 epoke 당 batch 수 : 10

 

네트워크 구성

ReLU -> ReLU -> softMax

 

세 개의 activation 함수를 통과 한다고 할때 10epoke는 무슨일이 일어나냐?

  1. 첫 번째 배치가 전체 네트워크(ReLU → ReLU → Softmax)를 통과합니다.
  2. 첫 번째 배치에 대한 손실을 계산하고 가중치를 업데이트합니다.
  3. 두 번째 배치가 전체 네트워크를 통과합니다.
  4. 두 번째 배치에 대한 손실을 계산하고 가중치를 업데이트합니다.
  5. ...
  6. 열 번째 배치가 전체 네트워크를 통과합니다.
  7. 열 번째 배치에 대한 손실을 계산하고 가중치를 업데이트합니다.

이렇게 10개의 배치가 모두 처리되면 1 에포크가 완료됩니다. 그 다음 2 에포크가 시작되어 같은 과정이 반복됩니다.

각 배치마다 네트워크의 모든 층(ReLU → ReLU → Softmax)을 통과하고, 모든 배치가 처리되어야 1 에포크가 완료된다고 보시면 됩니다.

 

 

 

그렇다면 Batch Norm은 무엇일까요?

 

배치 정규화(Batch Normalization, 줄여서 Batch Norm)는 딥러닝 모델 훈련 시 성능을 향상시키는 기법입니다. 2015년에 Sergey Ioffe와 Christian Szegedy가 제안한 이 방법은 현재 대부분의 딥러닝 모델에서 널리 사용되고 있습니다.

배치 정규화의 주요 기능과 장점은 다음과 같습니다:

  1. 정규화 과정: 각 배치의 데이터를 평균이 0, 분산이 1이 되도록 정규화합니다. 즉, 각 층의 입력 분포를 일정하게 유지합니다.
  2. 내부 공변량 이동(Internal Covariate Shift) 감소: 훈련 과정에서 각 층의 입력 분포가 계속 변하는 문제를 해결합니다.
  3. 학습 속도 향상: 더 높은 학습률을 사용할 수 있게 하여 훈련 속도를 크게 향상시킵니다.
  4. 정규화 효과: 가중치 정규화와 유사한 효과를 제공하여 과적합을 줄입니다.
  5. 그래디언트 소실/폭발 문제 완화: 깊은 네트워크에서 발생하는 그래디언트 소실이나 폭발 문제를 줄여줍니다.
 
그렇다면 왜 우리는 Batch Norm으로 위의 그림과 같이 다른 Batch를 비슷하게 정규화 하는 것일까요?
  1. 학습 과정의 불안정성 문제: 딥러닝 모델을 훈련할 때, 앞쪽 층의 가중치가 조금만 변해도 뒤쪽 층에 전달되는 데이터 분포가 크게 변할 수 있습니다. 이렇게 되면 뒤쪽 층들은 지속적으로 변화하는 입력 분포에 적응해야 하므로 학습이 느려지고 불안정해집니다.
  2. 그래디언트 소실과 폭발 문제: 깊은 신경망에서는 역전파 과정에서 그래디언트가 점점 작아지거나(소실) 너무 커지는(폭발) 문제가 발생합니다. 배치 정규화는 활성화 값들을 적절한 범위로 유지시켜 이 문제를 완화합니다.
  3. 학습률 민감성 감소: 배치 정규화가 없으면 적절한 학습률을 찾기가 매우 어렵습니다. 너무 크면 발산하고, 너무 작으면 학습이 너무 느립니다. 배치 정규화는 더 넓은 범위의 학습률에서 안정적으로 학습할 수 있게 해줍니다.
  4. 초기 가중치에 대한 의존성 감소: 배치 정규화 없이는 가중치 초기화 방법이 매우 중요합니다. 배치 정규화를 사용하면 초기화 방법에 대한 민감도가 줄어듭니다.
  5. 정규화 효과로 인한 일반화 성능 향상: 배치 정규화는 약한 형태의 정규화 역할을 하여 모델이 훈련 데이터에 과적합되는 것을 방지하고 테스트 데이터에 대한 성능을 향상시킵니다.

 

그렇다면 그래디언트 소실과 폭발은 무엇인가요?

 

그래디언트 소실(Vanishing Gradient)

  1. 수학적 원인: 활성화 함수(특히 시그모이드나 하이퍼볼릭 탄젠트)의 미분값이 특정 구간에서 매우 작습니다(0에 가까움).
  2. 전파 과정: 역전파 시 이 작은 미분값들이 곱해지며 점점 더 작아집니다.
  3. 결과: 앞쪽 층으로 갈수록 그래디언트가 거의 0에 가까워져, 가중치가 거의 업데이트되지 않습니다.
  4. 실질적 의미: 깊은 네트워크의 앞쪽 층들은 학습이 매우 느리거나 거의 이루어지지 않게 됩니다.

그래디언트 폭발(Exploding Gradient)

  1. 수학적 원인: 가중치 초기화가 부적절하거나, 네트워크 구조에 문제가 있을 때 발생합니다.
  2. 전파 과정: 역전파 시 그래디언트 값이 점점 커지게 됩니다.
  3. 결과: 그래디언트 값이 너무 커져 가중치 업데이트가 불안정해집니다.
  4. 실질적 의미: 학습이 발산하고 모델이 수렴하지 않게 됩니다.

과적합(Overfitting)

  1. 통계적 원인: 모델이 훈련 데이터의 노이즈나 특이점까지 학습하게 됩니다.
  2. 복잡성 측면: 모델의 용량(파라미터 수)이 필요 이상으로 클 때 발생합니다.
  3. 데이터 관점: 훈련 데이터가 적거나 편향되어 있을 때 더 심해집니다.
  4. 결과: 훈련 데이터에서는 성능이 매우 좋지만, 테스트 데이터에서는 성능이 떨어집니다.
  5. 실질적 의미: 모델이 일반화 능력을 잃고 특정 훈련 데이터에만 최적화되어 새로운 데이터에 대응하지 못하게 됩니다.
728x90
반응형

+ Recent posts