1. 코드 목적 및 역할 분석
TensorFlow의 Keras API를 사용해 손글씨 숫자 데이터셋(MNIST)에 대한 간단한 신경망 모델을 구성·학습·평가
최종적으로 테스트 결과를 시각화
데이터 로드 → 정규화 → 모델 정의(Sequential) → 컴파일 → 학습(fit) → 평가(evaluate) → 예측(predict) → 시각화(show predictions) 의 전 과정을 학습
2. 필수 라이브러리
import tensorflow as tf # 딥러닝 프레임워크
import matplotlib.pyplot as plt # 결과 시각화
- TensorFlow: tf.keras API를 통해 모델 구성, 학습, 평가, 예측을 수행
- Matplotlib: 학습 결과(이미지 + 예측값)를 한눈에 볼 수 있도록 배열 형태로 출력
3. 주요 기능 개요
1. MNIST 데이터 로드: tf.keras.datasets.mnist.load_data()
2. 픽셀 정규화: 0–255 범위를 0–1 실수로 스케일링
3. Sequential 모델 구성
- Flatten → Dense(128, relu) → Dense(10, softmax)
4. 모델 컴파일
- optimizer=adam
- loss=sparse_categorical_crossentropy
- metrics=['accuracy']
5. 모델 학습 : model.fit(..., epochs=5)
6. 모델 평가: model.evaluate(...) → 테스트 정확도 출력
7. 예측: model.predict(X_test) → 각 클래스 확률 벡터 생성
8. 결과 시각화:
- 160개 테스트 이미지를 16×10 그리드로 출력
- 예측이 정답과 일치하면 파란색, 아니면 빨간색 레이블 표시
4. 코드 뜯기
* 데이터 로드 & 정규화
# 데이터셋
mnist = tf.keras.datasets.mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 데이터 정규화 (0 ~ 1)
X_train = X_train / 255.0
X_test = X_test / 255.0
- MNIST 데이터셋을 (훈련_이미지, 훈련_레이블), (테스트_이미지, 테스트_레이블) 형태로 불러오기
- X_train.shape == (60000, 28, 28), y_train.shape == (60000,).
- 픽셀 값(255)을 실수(01)로 스케일링 하여 학습 안정성, 수렴 속도 향상
* 모델 구성
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
- Flatten: 2D(28×28) → 1D(784)로 변환
- 첫 번째 Dense(128, relu): 완전연결 은닉층, 뉴런 128개, ReLU 활성화
- 두 번째 Dense(10, softmax): 10개 클래스 확률 출력, 합이 1인 분포
* 컴파일
model.compile(
optimizer = 'adam',
loss = 'sparse_categorical_crossentropy',
metrics = ['accuracy']
)
- Adam 옵티마이저: 학습률 자동 조정, 모멘텀 적용
- 손실 함수: 정수 레이블(y_train)을 받을 때 sparse_categorical_crossentropy
- 평가지표: accuracy
* 학습
model.fit(X_train, y_train, epochs=5)
# 에포크 5회 반복 학습, 각 에포크마다 훈련 손실(loss)과 정확도(acc) 로그 출력)
Epoch 1/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 5s 2ms/step - accuracy: 0.8766 - loss: 0.4316
Epoch 2/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 5s 2ms/step - accuracy: 0.9630 - loss: 0.1258
Epoch 3/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 4s 2ms/step - accuracy: 0.9753 - loss: 0.0800
Epoch 4/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 4s 2ms/step - accuracy: 0.9828 - loss: 0.0581
Epoch 5/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 5s 2ms/step - accuracy: 0.9865 - loss: 0.0448
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.9673 - loss: 0.1019
<학습 결과 해석>
1. 초기 기울기 (1 -> 2Epoch)
- 1회차에서 정확도 88% 손실 0.43 -> 2회차에서 정확도 93% 손실 0.12로 급격히 개선
- 모델이 MNIST 기본 패턴 (굵기 형태) 학습에 매우 빠르게 적응했음을 의미
2. 수렴 (2 -> 5Epoch)
- 2->3회차 : 정확도 +1.2% 손실 -0.04
- 3-> 5회차 : 정확도 +0.7% 손실 -0.03
에포크가 진행될 수록 기울기가 완만해지는 전형적인 수렴 곡선
3. 일반화 성능
- 훈련 최종 정확도 98.7% 테스트 정확도는 97.2%
- 훈련 대비 테스트 정확도 차이 약 1.5% 과적합 위험 낮음. 일반화 잘 됨.
* 평가
test_loss, test_acc = model.evaluate(X_test, y_test)
print(f'테스트 정확도 : {test_acc:.4f}')
--
테스트 정확도 : 0.9723
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step
- 테스트 세트에서 최종 손실과 정확도 계산
* 예측
predictions = model.predict(X_test)
#predictions.shape == (10000, 10)
# 각 샘플마다 10개 클래스 확률 벡터 반환
* 시각화 함수 정의
def plot_image(i, predictions_array, true_label, img):
plt.grid(False); plt.xticks([]); plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = tf.argmax(predictions_array)
true = true_label[i]
color = 'blue' if predicted_label==true else 'red'
plt.xlabel(f'예측:{predicted_label.numpy()}, 정답:{true}', color=color)
- 그리드 눈금 제거
- tf.argmax로 가장 높은 확률 인덱스(예측 클래스) 추출
- 정답과 비교해 레이블 색상 결정
* 결과 출력
plt.rc('font', family='Malgun Gothic')
plt.figure(figsize=(16, 12))
for i in range(160):
plt.subplot(16, 10, i+1)
plot_image(i, predictions[i], y_test, X_test[i])
plt.tight_layout()
plt.show()
