딥러닝 과목 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개, 필터 수 10개.
- 변경 후: 합성곱 레이어 3개, 필터 수 32, 64, 128로 점진적 증가.
- 모델의 표현력 강화: 더 많은 합성곱 레이어와 필터 수 증가를 통해 이미지의 복잡한 특징을 더 잘 학습하도록 했다.
- BatchNormalization 레이어 추가:
- 각 합성곱 레이어 뒤에
BatchNormalization
레이어를 추가했다.
- 학습 안정화 및 속도 향상: 배치 정규화를 통해 내부 공변량 이동(Internal Covariate Shift)을 줄여 학습을 안정화하고 수렴 속도를 높였다.
- 각 합성곱 레이어 뒤에
- Dropout 레이어 위치와 비율 조정:
- 변경 전:
Flatten
레이어 뒤에Dropout(0.5)
를 추가. - 변경 후: 각
MaxPooling2D
레이어 뒤에Dropout(0.25)
를 추가하고,Dense
레이어 뒤에는Dropout(0.5)
를 유지.
- 변경 전:
- Dense 레이어의 뉴런 수 증가:
- 변경 전:
Dense(100, activation='relu')
- 변경 후:
Dense(256, activation='relu')
- 모델의 학습 능력 향상: 더 많은 뉴런을 사용하여 복잡한 패턴을 학습할 수 있도록 했다.
- 변경 전:
- Flatten 레이어 위치 유지:
- 변경 전후:
Flatten
레이어는 합성곱 블록 이후에 위치.
- 필수 구조 유지: CNN에서 합성곱 출력 데이터를 1차원으로 변환하여 Dense 레이어에 전달하기 위해 필요하다.
- 변경 전후:
- 활성화 함수 및 패딩 방식 유지:
- 변경 전후:
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_stopping
과lr_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)에 비해 다음과 같은 점에서 개선되었다.
- 모델 복잡성 증가: 더 깊은 네트워크와 더 많은 필터를 사용하여 모델의 표현력을 높였다.
- 정규화 및 안정화 기법 적용: 배치 정규화와 드롭아웃을 적절히 사용하여 학습의 안정성과 일반화 능력을 향상시켰다.
- 학습 최적화: 학습률 조정과 조기 종료를 통해 효율적인 학습이 가능하도록 했다.
- 가독성 및 유지보수성 향상: 코드 구조를 개선하고 주석을 추가하여 이해하기 쉽게 만들었다.
이러한 변경을 통해 모델의 성능이 향상될 것으로 기대된다. 다음 글에서 실행 결과를 확인하고, 성능 개선 여부에 대해 추가로 논의하겠다.