본문 바로가기

코딩/텐서플로우

비전공자의 코딩 독학 - 파이썬&텐서플로우(10) <MNIST>

반응형

안녕하세요.

오늘의 파이썬 코딩 독학 주제는 MNIST 입니다.

 

MNIST는 손으로 쓴 숫자들의 이미지를 모아놓은 데이터셋으로써

0부터 9까지의 숫자를 28*28 픽셀 크기로 구성해놓은 이미지 집합입니다.

 

MNIST는 머신러닝에서 상당히 유명한 예제 중 하나로써

전처리도 잘 되어있어서 번거로운 작업없이 바로 머신러닝을 진행할 수 있습니다.

 

 

1. 텐서플로우 외에 필요한 라이브러리

 

tensorflow.examples.tutorials.mnist.input_data : MNIST 예제가 들어있는 라이브러리입니다.

 

 

2. 전체 소스코드

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)


X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])

W1 = tf.Variable(tf.random_normal([784, 256], stddev=0.01))
L1 = tf.nn.relu(tf.matmul(X, W1))

W2 = tf.Variable(tf.random_normal([256, 256], stddev=0.01))
L2 = tf.nn.relu(tf.matmul(L1, W2))

W3 = tf.Variable(tf.random_normal([256, 10], stddev=0.01))
model = tf.matmul(L2, W3)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

batch_size = 100
total_batch = int(mnist.train.num_examples / batch_size)

for epoch in range(15):
    total_cost = 0

    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)

        _, cost_val = sess.run([optimizer, cost], feed_dict = {X:batch_xs, Y:batch_ys})


        total_cost += cost_val

    print('Epoch:', '%04d' % (epoch + 1), 'Avg. cost=', '{:.3f}'.format(total_cost / total_batch))

print('최적화 완료')


is_correct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))

accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

print('정확도:', sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))

 

 

3. 소스코드의 목적

MNIST 데이터셋을 이용하여

2개의 은닉층을 통해

손글씨 이미지를 학습시켜보겠습니다.

 

아래 그림이 바로 MNIST 데이터셋에 들어있는

손글씨 이미지입니다.

 

 

4. 소스코드 분석

아래의 코드로 MNIST 데이터를 mnist/data/ 디렉토리에 다운받을 수 있습니다.

루트 폴더에 mnist와 data폴더가 생성되며 그 안에 데이터가 다운로드 됩니다.

이후 데이터를 one-hot 인코딩 방식으로 불러들입니다.

mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)

 

MNIST의 손글씨 이미지는 28*28픽셀이므로

총 784개의 특징으로 이루어져 있습니다.

또한 0부터 9까지의 숫자가 표현되어 있으므로

10개의 분류로 나눌 수 있습니다.

아래의 코드를 통해 입력값과 출력값을 정의하겠습니다.

X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])

머신러닝을 할 때 여러개의 이미지를 한번에 학습시키는게 좋지만

높은 성능이 필요하므로 보통은 데이터를 적당한 크기로 잘라서 학습시킵니다.

이와 같은 데이터 정제 과정을 미니배치(Minibatch)라고 부릅니다.

위의 코드에서 텐서의 첫번째 차원이 None이라고 입력되어있는데,

이 자리에는 한번에 학습시킬 이미지의 개수를 지정하는 값이 들어갑니다.

원하는 갯수로 정확히 지정할수도 있지만

그냥 None이라고 입력하면 텐서플로우가 임의로 계산해줍니다.

 

아래의 코드를 이용해

2개의 은닉층을 가진 신경망을 만들어줍니다.

W1 = tf.Variable(tf.random_normal([784, 256], stddev=0.01))
L1 = tf.nn.relu(tf.matmul(X, W1))

W2 = tf.Variable(tf.random_normal([256, 256], stddev=0.01))
L2 = tf.nn.relu(tf.matmul(L1, W2))

W3 = tf.Variable(tf.random_normal([256, 10], stddev=0.01))
model = tf.matmul(L2, W3)

위와 같은 코드를 입력하게 되면

아래 그림과 같은 신경망이 만들어 지게 됩니다.

tf.random_normal() 함수에서 stddev=0.01이라고 작성하면

표준편차가 0.01인 정규분포를 가지는 임의의 값으로 변수를 초기화시킵니다. 

tf.matmul() 함수를 이용해서 입력값에 각각의 가중치를 곱해줍니다.

tf.nn.relu() 함수를 이용해서 ReLU함수를 활성화 함수로 사용합니다.

 

아래의 코드에서

tf.nn.softmax_cross_entropy_with_logits_v2() 함수를 사용하여

각 이미지에 대해 예측값과 실제값의 차이값인 손실값을 구해주고,

tf.reduce_mean() 함수를 사용해서 미니배치 손실값의 평균을 구해줍니다.

tf.train.AdamOptimizer() 함수로 최적화를 수행하여 손실값을 최소화하여줍니다.

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

 

아래의 코드에서

신경망 모델을 초기화하고 학습을 진행할 세션을 시작합니다.

init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

 

MNIST는 데이터가 수만개에 달하므로

모든 데이터를 학습하면 너무 오랜 시간이 걸리게 됩니다.

따라서 아래와 같은 코드를 사용하여

미니배치 사이즈를 100개로 지정해줍니다.

또한 학습 데이터의 총 개수인

mnist.train.num_examples를 배치 크기로 나누어서

미니배치가 몇 개인지를 지정해줍니다.

batch_size = 100
total_batch = int(mnist.train.num_examples / batch_size)

 

이제 아래 코드를 입력하여

MNIST데이터 전체를 15번 반복해서 학습하도록 지정해줍니다.

여기서 데이터 전체를 한번 학습하는 것을 에포크(Epoch)라고 합니다. 

for epoch in range(15):
    total_cost = 0

 

아래 코드를 이용해서

미니배치의 총 갯수만큼 반복학습하도록 지정합니다.

    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)

        _, cost_val = sess.run([optimizer, cost], feed_dict = {X:batch_xs, Y:batch_ys})

mnist.train.next_batch(batch_size) 함수를 사용해서

학습할 데이터를 배치 사이즈에 맞춰 가져옵니다.

이후 입력값은 batch_xs에,

출력값은 batch_ys에 저장합니다.

이후 sess.run() 함수를 사용하여 최적화를 진행하고

손실값을 저장해줍니다.

이때 feed_dict 매개변수에 입력값 X와 출력값 Y를 넣어줍니다.

 

아래 코드를 이용해서

손실값을 저장해주고,

학습이 한 바퀴 끝나면, 해당 바퀴의 평균 손실값을 출력합니다.

        total_cost += cost_val

    print('Epoch:', '%04d' % (epoch + 1), 'Avg. cost=', '{:.3f}'.format(total_cost / total_batch))

print('최적화 완료')

 

이번에는 학습 결과를 출력해보겠습니다.

아래 코드를 이용해서

예측값인 model과 출력값인 Y를 비교합니다.

is_correct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))

tf.argmax() 함수를 이용해서 두 번째 차원의 값 중 최댓값의 인덱스를 뽑아냅니다.

tf.equal() 함수를 이용해서 예측값과 실제값이 같은지를 비교해줍니다.

 

다음 코드에서

tf.cast() 함수를 통해 is_correct를 0과1로 변환해줍니다.

이후

tf.reduce_mean() 함수를 이용해서 평균을 내줍니다.

그럼 정확도를 구할 수 있습니다.

accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

 

다음 코드에서

테스트 이미지를 다루는 객체인

mnist.test를 이용해서

학습의 정확도를 출력해줍니다.

print('정확도:', sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))

 

 

5. 결과 확인

정상적으로 학습이 진행되었다면

위 사진과 같은 결과값이 출력됩니다.

 

오늘은 MNIST로 손글씨 학습을 진행하였습니다.

반응형