[텐서플로우/케라스] MNIST 숫자 분류하기 (softmax)

2020. 4. 21. 12:55노트/Python : 프로그래밍

 

텐서플로우 

 

데이터 불러오기

import tensorflow as tf 
import matplotlib.pyplot as plt 
import random

tf.set_random_seed(777)
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]) # 0~9 digit 
w = tf.Variable(tf.random_normal([784,10]))
b = tf.Variable(tf.random_normal([10]))

함수 및 모델 정의

hf = tf.nn.softmax(tf.matmul(x,w)+b)
cost = tf.reduce_mean(-tf.reduce_sum( y * tf.log(hf) ,axis=1))
train = tf.train.GradientDescentOptimizer(0.1).minimize(cost)

isCorrect = tf.equal(tf.argmax(hf ,1) , tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(isCorrect , tf.float32 ))

numEpochs = 15
batchSize = 100 
numIter = int(mnist.train.num_examples / batchSize )

모델 실행

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    #트레이닝
    for epoch in range(numEpochs): #15에폭 
        avgCv = 0
        for i in range(numIter): #600반복 
            batchX, batchY = mnist.train.next_batch(batchSize)
            _, cv = sess.run([train, cost], feed_dict={x:batchX, y:batchY})
            avgCv += cv / numIter 
        print("epoch:{:04d}, cost:{:.9f}".format(epoch+1, avgCv)) # 4자리수로 출력 
    print("정확도:",accuracy.eval(session=sess, feed_dict={x:mnist.test.images, y:mnist.test.labels}))
    r=random.randint(0,mnist.test.num_examples-1) #난수발생
    print("레이블:",sess.run(tf.argmax(mnist.test.labels[r:r+1],1)))
    print("예측:",sess.run(tf.argmax(hf,1),feed_dict={x:mnist.test.images[r:r+1]}))    

    plt.imshow(mnist.test.images[r:r+1].reshape(28,28),cmap="Greys")
    plt.show()   
    
 >>>
 epoch:0001, cost:2.826302752
epoch:0002, cost:1.061668976
epoch:0003, cost:0.838061328
epoch:0004, cost:0.733232746
epoch:0005, cost:0.669279894
epoch:0006, cost:0.624611839
epoch:0007, cost:0.591160358
epoch:0008, cost:0.563868996
epoch:0009, cost:0.541745189
epoch:0010, cost:0.522673595
epoch:0011, cost:0.506782334
epoch:0012, cost:0.492447652
epoch:0013, cost:0.479955845
epoch:0014, cost:0.468893677
epoch:0015, cost:0.458703488
정확도: 0.8951
레이블: [6]
예측: [6]

 


케라스

 

# 학습 모델 저장 / 불러오기 (keras)
# 다층 퍼셉트론 모델 (히든 레이어 여러개 생성)
# 훈련셋, 검증셋, 시험셋

 

데이터준비

from keras.utils import np_utils
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense , Activation
import numpy as np

(xTrain, yTrain),(xTest,yTest) = mnist.load_data()
# 전처리작업 (스케일링)
xTrain=xTrain.reshape(60000,784).astype('float32')/255.0
xTest=xTest.reshape(10000,784).astype('float32')/255.0 

yTrain=np_utils.to_categorical(yTrain) # 원핫인코딩 
yTest=np_utils.to_categorical(yTest) # 원핫인코딩 

# 검증데이터 나누기 
xVal=xTrain[42000:]
xTrain=xTrain[:42000]  # 순서주의 Val 부터 먼저뽑아야함 
yVal=yTrain[42000:]
yTrain=yTrain[:42000]

 

모델구축

# 모델 구성
model = Sequential()
model.add(Dense(units=64, input_dim=28*28, activation="relu"))
model.add(Dense(units=10, activation="softmax"))

# 모델 학습 
# 모델 학습환경설정 (compile)
model.compile(loss= "categorical_crossentropy", optimizer = "sgd", metrics=["accuracy"])
# 모델 학습 (fit)
model.fit(xTrain,yTrain,epochs=5,batch_size=50, validation_data=(xVal,yVal))

# 모델평가하기(test data)
metrics = model.evaluate(xTest,yTest,batch_size=50)
print("평가결과:"+str(metrics))

>>10000/10000 [==============================] - 0s 13us/step
평가결과:[0.2885529683995992, 0.9204000234603882]

 

모델사용

# 모델 예측하기 
idx = np.random.choice(xTest.shape[0],5)
xHat = xTest[idx]
yHat = model.predict_classes(xHat)

for i in range(5):
    print("예측값:", str(yHat[i]) + " 실제값:"+str(np.argmax(yTest[idx[i]])))
    
>>>
예측값: 7 실제값:7
예측값: 1 실제값:1
예측값: 9 실제값:4
예측값: 3 실제값:3
예측값: 2 실제값:2

 

# 모델 아키텍쳐 확인 
from keras.utils.vis_utils import model_to_dot
from IPython.display import SVG

model.summary()

 


케라스 기반 성능 향상 

  • optimizer = sgd > adam 
  • validation data = test data 

 

데이터 불러오기

from keras.datasets import mnist 
from keras.utils import np_utils
import numpy as np 
import sys 
import tensorflow as tf 

(xTrain, yTrain ), (xTest, yTest)= mnist.load_data()

print(xTrain.shape)
print(yTrain.shape)
print(xTest.shape)
print(yTest.shape)
>>>
(60000, 28, 28)
(60000,)
(10000, 28, 28)
(10000,)

import matplotlib.pyplot as plt

plt.imshow(xTrain[0], cmap="Greys")
plt.show()

for x in xTrain[0]: 
    for i in x:
        sys.stdout.write("%d\t" % i)
    sys.stdout.write("\n") #표준출력장치 (모니터)로 출력하여라 

 

 

yTrain[0]
>>> 5

#원핫인코딩 
yTrain=np_utils.to_categorical(yTrain,10)
yTest=np_utils.to_categorical(yTest,10)

 

모델 구성 

from keras.models import Sequential
from keras.layers import Dense 
from keras.callbacks import ModelCheckpoint, EarlyStopping
import numpy as np 
import tensorflow as tf 
import os

# 모델 구성 
model = Sequential()
model.add(Dense(512, input_dim = 784, activation = 'relu')) # 출력이 512개인 layers 
model.add(Dense(10, activation = 'softmax')) 

# 모델 환경설정 
model.compile(loss="categorical_crossentropy", 
             optimizer = "adam",
             metrics=['accuracy'])
             
# 모델 최적화 
modelDir = './myModel/'
if not os.path.exists(modelDir):  # 만약 myModel directory가 존재하지 않는다면 
    modelPath = "./myModel/{epoch:02d}-{val_loss:.4f}.hdf5"
    os.mkdir(modelDir)
checkpointer = ModelCheckpoint(filepath=modelPath, monitor = 'val_loss', verbose=1 , save_best_only=True )
# ModelCheckpoint: 콜백함수 : 어떤 상황이 되면 시스템에 의해서 호출되는 함수 , 
# keras에서 모델을 학습할 때마다 중간중간에 콜백형태로 알려줌 
# save_best_only: 모델의 정확도가 최고값을 갱신할때만 저장 
es = EarlyStopping(monitor='val_loss', patience=10)

 

모델 실행 

history= model.fit(xTrain, yTrain,validation_data=(xTest,yTest), 
                   epochs=30, batch_size=200, callbacks=[es,checkpointer])

 

모델 평가 

print("테스트 정확도: %.4f" %(model.evaluate(xTest,yTest)[1]))

10000/10000 [==============================] - 0s 40us/step
테스트 정확도: 0.9813

# 테스트 셋의 오차 
yVloss = history.history['val_loss']
# 학습 셋의 오차 
yLoss=history.history['loss']

%matplotlib notebook
xLen = np.arange(len(yLoss))
plt.plot(xLen, yVloss, marker=".", c="red", label="testset_loss")
plt.plot(xLen, yLoss, marker=".", c="blue", label="trainset_loss")
plt.legend()
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()