반응형

전체 Source는 Github에 있습니다.

1. Keras로 MNIST 모델생성

from keras.datasets import mnist
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import Adam 
from keras.utils import np_utils

# MNIST 데이터 읽어 들이기 --- (※1)
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# 데이터를 float32 자료형으로 변환하고 정규화하기 --- (※2)
X_train = X_train.reshape(60000, 784).astype('float32')
X_test  = X_test.reshape(10000, 784).astype('float')
X_train /= 255
X_test  /= 255

# 레이블 데이터를 0-9까지의 카테고리를 나타내는 배열로 변환하기 --- (※2a)
y_train = np_utils.to_categorical(y_train, 10)
y_test  = np_utils.to_categorical(y_test, 10)

# 모델 구조 정의하기 --- (※3)
model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(10))
model.add(Activation('softmax'))

# 모델 구축하기 --- (※4)
model.compile(loss='categorical_crossentropy',
              optimizer=Adam(),
              metrics=['accuracy'])

# 데이터 훈련하기 --- (※5)
hist = model.fit(X_train, y_train, epochs = 100)

# 테스트 데이터로 평가하기 --- (※6)
score = model.evaluate(X_test, y_test, verbose=1)
print('loss=', score[0])
print('accuracy=', score[1])

# 모델 저장하기 --- (※6)
model.save('keras_mnist.h5')  # creates a HDF5 file 'my_model.h5'
print("keras_mnist Image Classification Model Save OK")

2. 필기인식 Data Load

손글씨 숫자 데이터로 MNIST 에서 공개하고 있는 데이를 사용. 이미지 데이터는 각 픽셀을 Grayscale 256단계로 나타내며, 왼쪽 위부터 오른쪽 아래로 차례차례 픽셀이 나열된 형태. 0은 기본 배경색(흰색)이고, 1 ~ 255가 실제 손글씨가 적힌 부분을 나타냄 (28 X 28 픽셀)

import numpy as np
import os
import urllib.request
import gzip
import struct
import base64

def download_data(url, force_download=True): 
    fname = url.split("/")[-1]
    if force_download or not os.path.exists(fname):
        urllib.request.urlretrieve(url, fname)
    return fname

def read_data(label_url, image_url):
    with gzip.open(download_data(label_url)) as flbl:
        magic, num = struct.unpack(">II", flbl.read(8))
        label = np.frombuffer(flbl.read(), dtype=np.int8)
    with gzip.open(download_data(image_url), 'rb') as fimg:
        magic, num, rows, cols = struct.unpack(">IIII", fimg.read(16))
        image = np.frombuffer(fimg.read(), dtype=np.uint8).reshape(len(label), rows, cols)
    return (label, image)

path='http://yann.lecun.com/exdb/mnist/'

(train_lbl, train_img) = read_data(path+'train-labels-idx1-ubyte.gz', path+'train-images-idx3-ubyte.gz')
(val_lbl, val_img) = read_data(path+'t10k-labels-idx1-ubyte.gz', path+'t10k-images-idx3-ubyte.gz')

처음 10 개의 이미지를 레이블(Lable)과 함께 출력함

%matplotlib inline
import matplotlib.pyplot as plt

for i in range(10):
    plt.subplot(1,10,i+1)
    plt.imshow(train_img[i], cmap='Greys_r')
    plt.axis('off')
plt.show()
print('Label: %s' % (train_lbl[0:10],))
 

3. 모델 불러오기

import numpy as np
from keras.models import load_model

model = load_model('keras_mnist.h5')

모델 테스트

img = val_img[0]

plt.imshow(img, cmap='Greys_r')
plt.axis('off')
plt.show()
re_val_img = img.reshape(1, 784).astype('float32')

prob = model.predict(re_val_img/255)[0]
#prob = model.predict(val_img[0:1].astype(np.float32)/255)[0]

assert max(prob) > 0.99, "Low prediction accuracy."
print ('Classified as %d with probability %f' % (prob.argmax(), max(prob)))

4. Input Form 그리기

input_form = """
<style type="text/css">
  canvas { border: 1px solid black; }
</style>

<div id="board">

  <canvas id="myCanvas" width="200px" height="200px">
    Sorry, your browser doesn't support canvas technology.
  </canvas>

  <p>
    <button id="classify" onclick="classify()">
      Classify
    </button>

    <button id="clear" onclick="myClear()">
      Clear
    </button>
    Result: 
    <input type="text" id="result_output" size="5" value="">
  </p>

</div>
"""

5. Script 작성

javascript = """
<script type = "text/JavaScript" src = "https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js?ver=1.4.2" > </script>

<script type = "text/javascript" >
    function init() {
        var myCanvas = document.getElementById("myCanvas");
        var curColor = $('#selectColor option:selected').val();
        if (myCanvas) {
            var isDown = false;
            var ctx = myCanvas.getContext("2d");
            var canvasX, canvasY;
            ctx.lineWidth = 8;
            $(myCanvas).mousedown(function(e) {
                isDown = true;
                ctx.beginPath();
                var parentOffset = $(this).parent().offset();
                canvasX = e.pageX - parentOffset.left;
                canvasY = e.pageY - parentOffset.top;
                ctx.moveTo(canvasX, canvasY);
            }).mousemove(function(e) {
                if (isDown != false) {
                    var parentOffset = $(this).parent().offset();
                    canvasX = e.pageX - parentOffset.left;
                    canvasY = e.pageY - parentOffset.top;
                    ctx.lineTo(canvasX, canvasY);
                    ctx.strokeStyle = curColor;
                    ctx.stroke();
                }
            }).mouseup(function(e) {
                isDown = false;
                ctx.closePath();
            });
        }
        $('#selectColor').change(function() {
            curColor = $('#selectColor option:selected').val();
        });
    }

init();

function handle_output(out) {
    console.log(out);
    var res = null;
    // if output is a print statement
    if(out.msg_type == "stream"){
       res = out.content.data;
    }
    // if output is a python object
    else if(out.msg_type === "execute_result"){
       res = out.content.data["text/plain"];
    }
    // if output is a python error
    else if(out.msg_type == "pyerr"){
       res = out.content.ename + ": " + out.content.evalue;
    }
    // if output is something we haven't thought of
    else{
       res = out.msg_type;  
    }
    document.getElementById("result_output").value = res;
}

function classify() {
    var kernel = IPython.notebook.kernel;
    var myCanvas = document.getElementById("myCanvas");
    data = myCanvas.toDataURL('image/png');
    document.getElementById("result_output").value = "";
    kernel.execute("classifyML('" + data + "')", {
        'iopub': {
            'output': handle_output
        }
    }, {
        silent: false
    });
}

function myClear() {
    var myCanvas = document.getElementById("myCanvas");
    myCanvas.getContext("2d").clearRect(0, 0, myCanvas.width, myCanvas.height);
}
</script>
"""

6. 테스트

from IPython.display import HTML
import cv2
import numpy as np

def classifyML(img):
    img = base64.b64decode(img[len('data:image/png;base64,'):])
    img = cv2.imdecode(np.fromstring(img, np.uint8), -1)
    img = cv2.resize(img[:,:,3], (28,28))
    img = img.astype(np.float32).reshape((1,784))/255.0
    print(model.predict(img)[0].argmax())
    return model.predict(img)[0].argmax()

HTML(input_form + javascript)

Jupyter Notebook에서 실행하여 테스트 할 수 있습니다.

반응형