본 포스팅은 “케라스 창시자에게 배우는 딥러닝” - (길벗출판사, 프랑소와 숄레 지음, 박해선 옮김)을 바탕으로 공부한 내용을 정리한 것입니다.
- MNIST 손글씨 데이터
- 손글씨 분류 문제
- 케라스에 데이터셋 적재
- 신경망 구조
- 컴파일
- 이미지 데이터 준비
- 레이블 준비
- 모델 학습
- 테스트 세트에서 모델 적용
1. MNIST 손글씨 데이터
흑백 손글씨 숫자 이미지 (28 X 28 픽셀)을 10개의 범주 (0~9)로 분류하는 문제.
6만 개의 훈련 이미지와 1만 개의 테스트 이미지로 구성 되어 있다.
train과 test 비율은 보통 6:1, 6:2, 7:1 등으로 사용한다. 여기서는 6:1이 되겠다.
MNIST 문제는 딥러닝계의 “hello world”라고 한다.
2. 손글씨 분류 문제
케라스에 데이터셋 적재
1
2
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
MNIST 데이터셋은 Numpy 배열 형태로 케라스에 이미 포함되어 있어서 import
해준다.
train_images
와 train_labels
가 모델이 학습해야 할 훈련 세트 (training set)를 구성한다.
모델은 test_images
와 test_labels
로 구성된 테스트 세트 (test set)에서 테스트 된다.
이미지는 Numpy 배열로 인코딩되어 있고, 레이블은 0 ~ 9의 숫자 배열이다.
이미지와 레이블은 일대일 관계이다.
다음은 훈련 데이터를 살펴보는 과정이다.
정돈된 데이터의 실제 학습에는 필요없지만, 공부를 위해 구조를 확인하는 과정이다.
1
2
3
train_images.shape
len(train_labels)
train_labels
[결과]
1
2
3
(60000, 28, 28)
60000
array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)
unit 8 타입의 (60000, 28, 28) 크기의 [0, 255] 사이의 값을 가지는 배열임을 확인할 수 있다.
다음은 테스트 데이터이다.
1
2
3
test_images.shape
len(test_labels)
test_labels
[결과]
1
2
3
(10000, 28, 28)
10000
array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)
테스트 데이터는 unit 8 타입의 (10000, 28, 28) 크기의 [0, 255] 사이의 값을 가지는 배열이다.
다섯 번째 train_images를 matplotlib 라이브러리로 확인해보자.
1
2
3
4
5
import matplotlib.pyplot as plt
digit = train_images[4]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
작업 순서는 다음과 같다.
훈련 데이터 train_images
와 train_labels
를 네트워크에 주입시켜서 이미지와 레이블을 연관시킬 수 있도록 학습된다.
test_images
에 대한 예측을 네트워크에 요청하면 이 예측이 test_labels
와 맞는지 확인을 할 것이다.
다음으로는 신경망을 생성한다.
신경망 구조
1
2
3
4
5
6
from tensorflow.keras import models
from tensorflow.keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))
신경망의 핵심 구성 요소는 층 (layer)다.
여과기 같은 일종의 데이터 처리 필터라고도 생각 할 수 있다.
완전 연결 (fully connected)된 신경망 층인 Dense 층 2개가 연속되어 있다.
마지막 층은 소프트맥스 (softmax) 층이다.
10개의 확률 점수가 들어 있는 배열로, 모두 더하면 1이다.
즉, 각 점수는 현재 숫자 이미지가 0 ~ 9의 숫자 중 하나에 속할 확률이다.
첫 번째 층의 활성화 함수로 relu 함수가 사용되었다.
비선형 함수를 사용하여 딥러닝 모델의 레이어를 깊게 가져갈 수 있다고 한다.
대표적으로 사용되는 활성화 함수는 다음과 같다.
- Sigmoid 함수
- Tanh 함수
- ReLU (Rectified Linear Unit) 함수
- Leaky ReLU
- PReLU
- ELU (Exponential Linear Unit)
- Maxout
간단하고 빠른 편인 ReLU를 먼저 사용하고 Leakly ReLU, PReLU, ELU 등도 사용해본다. simoid와 tanh는 지양
신경망이 훈련 준비를 마치기 위한 컴파일 단계에 포함되기 위해 세가지가 더 필요하다.
- 손실함수 (loss function)
- 옵티마이저 (optimizer)
- 훈련과 테스트 과정을 모니터링 할 지표 (해당 예제에서는 정확도만)
컴파일
1
2
3
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
손실함수와 옵티마이저에 대해서는 다다음 포스팅에서 자세하게 작성 예정이다.
이미지 데이터 준비
1
2
3
4
5
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
훈련에 앞서, 데이터를 네트워크에 맞는 크기로 reshape하고 모든 값을 0 ~ 1로 스케일링 한다.
이미지의 경우 일반적으로 픽셀의 최댓값인 255로 나눈다고 한다.
레이블 준비
1
2
3
4
from tensorflow.keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
레이블을 범주형으로 인코딩 해주었다.
모델 학습
1
network.fit(train_images, train_labels, epochs=5, batch_size=128)
훈련 과정동안 손실 (loss)와 정확도 (accuracy)가 출력되었다.
훈련 데이터에 대해 0.989(98.9%)의 정확도를 금방 달성했다.
epochs, batch_size는 다다음 포스팅에 작성 예정 중이다.
테스트 세트에서 모델 적용
1
2
test_loss, test_acc = network.evaluate(test_images, test_labels)
print('test_acc:', test_acc)
훈련 세트의 정확도보다 낮은 테스트 세트의 97.8%는 과대적합 (overfitting)의 이유이다.
머신 러닝 모델이 훈련 데이터보다 새로운 데이터에서 성능이 낮아지는 경향을 뜻한다.
참고
“케라스 창시자에게 배우는 딥러닝” - (길벗출판사, 프랑소와 숄레 지음, 박해선 옮김)
- 깃허브: http://github.com/gilbutITbook/006975
- 길벗출판사 홈페이지: http://www.gilbut.co.kr
- tensorflow 2.4 버전 코드 https://github.com/rickiepark/deep-learning-with-python-notebooks/tree/tf2