머신러닝

1-6 TensorFlow 1.15.0 과 2.0 버전 사이에서 Keras MNIST 예제

coding art 2020. 1. 26. 13:13
728x90

Keras 라이브러리 지원 하에서 MNIST hand written digits 예제를 다루어 보자. MNIST 예제는 현재 아직도 미국에서 개인들이 사용하는 우편물에서 반드시 수기로 기입해야 하는 지역 코드 즉 ZIP 코드를 대상으로 09까지의 숫자를 6만개의 학습용(training) 데이터와 동일한 품질의 테스트용 데이터 1만개를 디지털화하여 데이터베이스를 구성하였고 LeCUN이 인터넷에 정리하여 올려 두었다. 다음의 그림을 참조하자.

 

 

 

수많은 수기 문자들이 있겠지만 인간의 지능으로 숫자 클라스 “0”에서 “9”까지를 보면 인식이 가능하다. 다양한 형태로 쓰여진 예를 들면 “0”의 다양한 수기 샘플들이 있겠지만 이들 모두는 하나의 라벨 값 “0” 으로 두면 될 것이다.

 

MNIST 수기문자에서 동일한 라벨 값을 가지게 되는 많은 수의 샘플들은 동일(identical)한 숫자를 의미하지만 각각의 샘플은 구별가능(distinguishable)하다고 볼 수 있을 것이다. 이러한 의미에서 통계역학의 이론인 볼츠만의 확률분포를 차용하여 머신러닝에 적용이 가능해진다. 볼츠만 확률분포의 물리적 대상은 동일한 종류의 기체분자 입자들을 대상으로 입자 하나하나가 구분이 가능한 즉 위치나 운동량이 다를 수밖에 없는 기체 분자들의 운동에너지에 따른 확률 분포를 결정 짓게 된다.

 

MNIST 문자 인식 예제를 실행시켜 보자. 이 예제는 tensorflow 버전 1.15.0 2.0에서 공통적으로 실행이 가능하다. 구글 tensorflow 홈페이지의 keras 예제는 하나의 은닉층(hidden layer)을 가지는 97.6% 수준의 인식률을 보여 주는 뉴럴 네트워크 예제를 제시하고 있으나 머신 러닝 초보자라면 은닉층이 없는 가장 단순한 예제 코드부터 실행시켜 볼 필요가 있다. 이 단순한 코드에서 최대 92.5% 수준의 인식률이 얻어진다.

 

다음의 예제 코드의 구조를 살펴보자. 수많은 머신 러닝 코드 예제가 있겠지만 다음의 표준적인 구조에서 은닉층을 추가하는 것 외에는 크게 벗어나지 않는다.

 

개개의 MNIST 숫자 데이터 28X28 픽셀 구조로 표현되며 이 매트릭스형 데이터 구조를 한 줄 한 줄 펴서(Flatten) 1X784 입력 데이터로 변환할 필요가 있다. 각 데이터에 대하여 784X10 웨이트 매트릭스를 도입하여 입력 데이터와 곱하면 1X10 리스트 구조의 데이터가 얻어지며(Dense) 이에 10개의 랜덤한 바이아스 값을 생성하여 더해 주고 학습용 데이터에서 미리 부여된 라벨 값에 해당하는 10 비트 One-hot 코드를 사용하여 학습(training) 시켜 웨이트 매트릭스의 값을 결정한다. 학습의 첫 시작에서는 랜덤한 값을 사용하며 cost 함수를 사용하여 경사하강법을 적용하는 반복 계산을 통해 One-hot 코드 라벨 값과 100% 일치하는 수준의 학습을 시키게 된다. 만약 은닉층이 추가되어 있다면 합성함수에 대한 경사하강법 적용을 위해 Back-propagation 기법이 적용된다.

 

이렇게 결정된 웨이트 값을 사용하여 테스트 데이터를 처리하면 테스트 데이터의 라벨 값을 추정을 통해 판정해 낼 수 있게 된다.

한편 Flatten Dense 로 구성되는 Keras Sequential 명령 사용의 또 다른 표현법에 관해서 알아보자.

MNIST 문제를 풀기 위한 TensorFlow 구버전 (TensorFlow2.0 이전의 1.15.0 까지)코드에서 읽어 들여야 할 개개의 입력 데이터는 1X784로 구성되며 tf.placeholder(tf.float32,[None, 784]) 명령 표현을 사용한다. None이란 MNIST 데이터베이스 구성 단계에서 설정해둔 정수로서 학습데이타 경우에는 60,000 이며 테스트 데이터 경우에는 10,000 을 뜻한다. 반면에 Keras 라이브러리를 사용할 때에는 학습이나 테스트 데이터들이 1X784 가 아닌 28X28로 읽혀진다. 따라서 앞서의 MNIST Keras 코드는 1X784 라는 1차원 형식의 입력 데이터 구조를 반영하여 코드를 다음과 같이 작성할 수도 있음에 유의하자. 즉 여기서 input_shape(784,)(None, 784)를 의미한다. 이 용법은 Keras 코딩에 자주 사용되는 용법이므로 유의하도록 하자.

 

 

 

#keras_tf2_mnist_01.py

import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)