2024년 2학기/딥러닝

CNN으로 CIFAR-10 이미지 분류 개선 (1)

서사대생 2024. 11. 8. 00:45

딥러닝 과목 9주차 주제가 CNN이었고 Fashion-MNIST 데이터셋을 분류하는 예제가 나왔다.

자유게시판을 훑다 보니 한 학생이 이걸 CIFAR-10으로 바꿔 테스트한 것이 있다.

코드를 받아보니, 노트북에서 출력된 정확도는 다음과 같다.

  • 첫 번째 모델 평가 시 정확도: 0.6032 (약 60.32%)
  • 두 번째 모델 평가 시 정확도: 0.6301 (약 63.01%)

이러한 값들은 검증 데이터에 대한 정확도를 나타낸다.

정확도 60~63%는 CIFAR-10 데이터셋의 기준으로 보면 기본적인 성능 수준이다. CIFAR-10은 10개의 서로 다른 클래스(예: 비행기, 자동차, 새 등)를 가진 비교적 난이도 있는 데이터셋으로, 기본적인 합성곱 신경망(ConvNet) 구조에서는 60~70%의 정확도는 흔하다.

성능을 높이기 위해 다음과 같은 방법을 고려해 볼 수 있다.

  • 모델 구조 개선: 더 깊고 복잡한 합성곱 층 추가 또는 ResNet과 같은 더 발전된 아키텍처 사용.
  • 데이터 증강: 훈련 데이터를 변형하여 모델이 다양한 입력에 대해 더 일반화할 수 있도록 도움.
  • 하이퍼파라미터 튜닝: 학습률, 배치 크기 등 하이퍼파라미터를 조정해 최적화.
  • 전이 학습: 사전 훈련된 모델을 사용해 CIFAR-10에 맞게 조정.

수정 전후 코드 비교

수정 전 코드의 두 번째 모델(conv2)을 기준으로 수정한 코드에서 어떤 부분이 변경되었는지, 그리고 그 변경의 목적과 이유를 설명하겠다.

개요

수정 전 코드(conv2 모델)는 간단한 CNN 구조로, 다음과 같은 레이어로 구성되어 있다.

  • Conv2D: 10개의 필터, 커널 크기 (3, 3), 'relu' 활성화 함수, 'same' 패딩, 입력 형태 (32, 32, 3)
  • MaxPooling2D: 풀 사이즈 (2, 2)
  • Flatten
  • Dropout: 드롭아웃 비율 0.5
  • Dense: 100개의 뉴런, 'relu' 활성화 함수
  • Dense: 10개의 뉴런, 'softmax' 활성화 함수

수정한 코드는 더 깊고 복잡한 CNN 모델로, 추가적인 레이어와 기법을 사용하여 성능을 향상시키고자 한다.

아래에서는 수정한 코드에서 변경된 부분과 그 의도에 대해 상세히 설명하겠다.

1. 임포트 및 초기 설정

수정 전 코드:

from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout

수정한 코드:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, BatchNormalization
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau

변경 사항 및 이유:

  • BatchNormalization 추가: 모델에 배치 정규화 레이어를 추가하기 위해 BatchNormalization을 임포트했다.
  • Optimizers 및 Callbacks 임포트: 학습률 조정 및 조기 종료를 위해 Adam 옵티마이저와 EarlyStopping, ReduceLROnPlateau 콜백을 임포트했다.
  • Sequential 모델 임포트: 모델을 구축하기 위해 Sequential 클래스를 임포트했다.

의도:

  • 배치 정규화 사용: 학습 안정성과 성능 향상을 위해 배치 정규화를 도입했다.
  • 학습 최적화: 옵티마이저와 콜백을 통해 학습 과정을 더 세밀하게 제어하고자 했다.

2. 데이터 전처리 변경

수정 전 코드:

x_train = x_train.reshape(-1, 32, 32, 3)
x_val = x_val.reshape(-1, 32, 32, 3)
x_train = x_train / 255
x_val = x_val / 255

수정한 코드:

x_train = x_train / 255.0
x_val = x_val / 255.0

변경 사항 및 이유:

  • Reshape 제거: 데이터의 형태를 재구성하는 reshape 단계를 제거했다.

의도:

  • CIFAR-10 데이터는 이미 (샘플 수, 32, 32, 3) 형태이므로 reshape가 불필요하다. 이를 제거하여 코드를 간소화하고 불필요한 연산을 줄였다.

3. 모델 아키텍처 변경

수정 전 코드(conv2 모델):

conv2 = tf.keras.Sequential()
conv2.add(Conv2D(10, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
conv2.add(MaxPooling2D((2, 2)))
conv2.add(Flatten())
conv2.add(Dropout(0.5))
conv2.add(Dense(100, activation='relu'))
conv2.add(Dense(10, activation='softmax'))

수정한 코드:

model = Sequential([
    Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)),
    BatchNormalization(),
    MaxPooling2D((2, 2)),
    Dropout(0.25),

    Conv2D(64, (3, 3), activation='relu', padding='same'),
    BatchNormalization(),
    MaxPooling2D((2, 2)),
    Dropout(0.25),

    Conv2D(128, (3, 3), activation='relu', padding='same'),
    BatchNormalization(),
    MaxPooling2D((2, 2)),
    Dropout(0.25),

    Flatten(),
    Dense(256, activation='relu'),
    BatchNormalization(),
    Dropout(0.5),
    Dense(10, activation='softmax')
])

변경 사항 및 이유:

  1. 합성곱 레이어 수 증가 및 필터 수 확대:
    • 변경 전: 합성곱 레이어 1개, 필터 수 10개.
    • 변경 후: 합성곱 레이어 3개, 필터 수 32, 64, 128로 점진적 증가.
    의도:
    • 모델의 표현력 강화: 더 많은 합성곱 레이어와 필터 수 증가를 통해 이미지의 복잡한 특징을 더 잘 학습하도록 했다.
  2. BatchNormalization 레이어 추가:
    • 각 합성곱 레이어 뒤에 BatchNormalization 레이어를 추가했다.
    의도:
    • 학습 안정화 및 속도 향상: 배치 정규화를 통해 내부 공변량 이동(Internal Covariate Shift)을 줄여 학습을 안정화하고 수렴 속도를 높였다.
  3. Dropout 레이어 위치와 비율 조정:
    • 변경 전: Flatten 레이어 뒤에 Dropout(0.5)를 추가.
    • 변경 후: 각 MaxPooling2D 레이어 뒤에 Dropout(0.25)를 추가하고, Dense 레이어 뒤에는 Dropout(0.5)를 유지.
    의도:
    • 과적합 방지 강화: 모델의 각 단계에서 드롭아웃을 적용하여 과적합을 더욱 효과적으로 방지했다.
  4. Dense 레이어의 뉴런 수 증가:
    • 변경 전: Dense(100, activation='relu')
    • 변경 후: Dense(256, activation='relu')
    의도:
    • 모델의 학습 능력 향상: 더 많은 뉴런을 사용하여 복잡한 패턴을 학습할 수 있도록 했다.
  5. Flatten 레이어 위치 유지:
    • 변경 전후: Flatten 레이어는 합성곱 블록 이후에 위치.
    의도:
    • 필수 구조 유지: CNN에서 합성곱 출력 데이터를 1차원으로 변환하여 Dense 레이어에 전달하기 위해 필요하다.
  6. 활성화 함수 및 패딩 방식 유지:
    • 변경 전후: activation='relu', padding='same' 설정 유지.
    의도:
    • 기존의 효과적인 설정 유지: ReLU 활성화 함수와 'same' 패딩은 CNN에서 일반적으로 사용되는 설정이다.

4. 모델 컴파일 변경

수정 전 코드:

conv2.compile(optimizer='nadam', loss='categorical_crossentropy', metrics=['accuracy'])

수정한 코드:

optimizer = Adam(learning_rate=1e-3)
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])

변경 사항 및 이유:

  • 옵티마이저 변경: nadam에서 Adam 옵티마이저로 변경하고, 학습률을 1e-3으로 명시적으로 설정했다.

의도:

  • 학습률을 명시적으로 1e-3으로 설정하여 학습 속도를 조절하고자 했다. 이를 통해 모델의 수렴 속도를 관리하려는 의도가 있었다.
  • 그러나 옵티마이저를 Nadam에서 Adam으로 변경한 것은 특별한 이유나 고려 없이 이루어졌다. 두 옵티마이저는 모두 강력한 성능을 제공하며, 이 변경이 모델의 성능에 큰 영향을 미치지 않았을 것으로 판단된다. 옵티마이저 변경은 실수나 습관적으로 이루어진 것일 수 있다.

5. 콜백 함수 추가

수정 전 코드:

  • 콜백 함수 사용 없음.

수정한 코드:

early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
lr_reduction = ReduceLROnPlateau(monitor='val_loss', patience=3, factor=0.5, min_lr=1e-6)
  • 모델 학습 시 콜백 함수 적용:
callbacks=[early_stopping, lr_reduction]

의도:

  • EarlyStopping:
    • 과적합 방지: 검증 손실이 개선되지 않으면 학습을 조기에 종료하여 과적합을 방지한다.
    • 최적의 모델 유지: restore_best_weights=True를 통해 가장 성능이 좋았던 가중치를 복원한다.
  • ReduceLROnPlateau:
    • 학습률 조정: 검증 손실이 일정 에포크 동안 개선되지 않으면 학습률을 감소시켜 더 세밀한 학습을 유도한다.

6. 모델 학습 설정 변경

수정 전 코드:

history = conv2.fit(x_train, y_train_encoded, epochs=20, validation_data=(x_val, y_val_encoded))

수정한 코드:

history = model.fit(
    x_train, y_train_encoded,
    epochs=50,
    batch_size=32,
    validation_data=(x_val, y_val_encoded),
    callbacks=[early_stopping, lr_reduction]
)

변경 사항 및 이유:

  • 에포크 수 증가: 20에서 50으로 증가.
  • 배치 크기 명시적 설정: batch_size=32로 설정.
  • 콜백 함수 적용: 앞서 정의한 early_stoppinglr_reduction 콜백을 적용.

의도:

  • 충분한 학습 시간 부여: 에포크 수를 늘려 모델이 데이터에 충분히 적합할 수 있도록 했다.
  • 배치 크기 조절: 배치 크기를 명시적으로 설정하여 학습 효율성과 안정성을 향상시켰다.
  • 학습 제어 강화: 콜백을 통해 학습 과정을 동적으로 관리했다.

7. 학습 과정 시각화 개선

수정 전 코드:

  • 각각의 그래프를 별도로 그렸다.

수정한 코드:

plt.figure(figsize=(12, 4))
# 손실 곡선
plt.subplot(1, 2, 1)
# ...
# 정확도 곡선
plt.subplot(1, 2, 2)
# ...
plt.show()

변경 사항 및 이유:

  • 그래프 통합 및 크기 조절: 손실과 정확도 그래프를 한 화면에 나란히 배치하여 시각적인 비교를 쉽게 했다.

의도:

  • 시각화 효율성 향상: 학습 곡선을 한눈에 비교할 수 있도록 그래프를 개선했다.

8. 모델 평가 출력 형식 변경

수정 전 코드:

loss, accuracy = conv2.evaluate(x_val, y_val_encoded, verbose=0)
print(accuracy)

수정한 코드:

loss, accuracy = model.evaluate(x_val, y_val_encoded, verbose=0)
print(f"Validation Accuracy: {accuracy:.4f}")

변경 사항 및 이유:

  • 출력 형식 개선: 정확도를 소수점 네 자리까지 표시하고, 문자열 포맷팅을 사용하여 가독성을 높였다.

의도:

  • 결과 해석 용이성 향상: 결과를 보다 명확하고 보기 좋게 출력했다.

9. 코드 구조 및 가독성 개선

  • 주석 추가 및 코드 정리: 각 단계에 번호를 매기고 주석을 추가하여 코드의 흐름을 명확히 했다.

의도:

  • 코드 유지보수성 향상: 코드의 가독성을 높여 이후 수정이나 이해를 용이하게 했다.

10. 기타 변경 사항

  • 레이블 원-핫 인코딩 시 클래스 수 명시:
    • 수정 전: to_categorical(y_train)
    • 수정 후: to_categorical(y_train, 10)

의도:

  • 명시적 클래스 수 지정: CIFAR-10 데이터셋의 클래스 수를 명시하여 코드의 명확성을 높였다.

결론

수정한 코드수정 전 코드의 두 번째 모델(conv2)에 비해 다음과 같은 점에서 개선되었다.

  • 모델 복잡성 증가: 더 깊은 네트워크와 더 많은 필터를 사용하여 모델의 표현력을 높였다.
  • 정규화 및 안정화 기법 적용: 배치 정규화와 드롭아웃을 적절히 사용하여 학습의 안정성과 일반화 능력을 향상시켰다.
  • 학습 최적화: 학습률 조정과 조기 종료를 통해 효율적인 학습이 가능하도록 했다.
  • 가독성 및 유지보수성 향상: 코드 구조를 개선하고 주석을 추가하여 이해하기 쉽게 만들었다.

이러한 변경을 통해 모델의 성능이 향상될 것으로 기대된다. 다음 글에서 실행 결과를 확인하고, 성능 개선 여부에 대해 추가로 논의하겠다.