본문 바로가기
밑바닥 딥러닝/밑바닥부터 시작하는 딥러닝1

손글씨 숫자 인식

by sxlvxrjxms2s2itsmes2s2 2023. 5. 13.

학습된 매개변수를 사용하여 학습 과정은 생략하고, 추론과정만 구현 (추론과정=신경망의 순전파)

 

MNIST 데이터셋

MNIST 데이터셋을 이용하여 모델을 학습하고, 학습한 모델로 시험 이미지들을 얼마나 정확하게 분류하는지 평가한다. 이를 준비하는 코드는 다음과 같다.

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from mnist import load_mnist # MNIST데이터를 (훈련이미지,훈련레이블), (시험이미지, 시험레이블)로 반환
from PIL import Image

def img_show(img):  #MNIST이미지 화면으로 불러옴
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
img = x_train[0]
label = t_train[0]
print(label)  # 5

print(img.shape)  # (784,)
img = img.reshape(28, 28)  # 형상을 원래 이미지의 크기로 변형
print(img.shape)  # (28, 28)

img_show(img)

load_mnist 함수는 읽은 데이터를 (훈련이미지,훈련레이블), (시험이미지,시험레이블) 형식으로 반환한다. 인수로는 normalize, flatten, one_hot_label 세 가지를 설정할 수 있다.

 

1) nomalize는 입력 이미지의 픽셀값을 0.0~1.0 사이의 값으로 정규화할지를 정한다.

- false일 경우 입력 이미지 픽셀은 원래 값 그대로 0~244 사이의 값 유지

2) flattern은 입력 이미지를 평탄하게 1차원 배열로 만들지를 정한다.

- false일 경우 입력 이미지를 3차원 배열로, true일 경우 1차원 배열로

3) 원-핫 레이블은 레이블을 원-핫 인코딩 형태로 저장할지 정한다. 정답을 뜻하는 원소만 1, 나머지는 0인 배열 

- false면 숫자형태의 레이블을 그대로 저장 / true일때는 인코딩하여 저장

0 > 0001

1 > 0010

2 > 0100

3 > 1000

 

추론을 수행하는 신경망을 구현해본다.

이 신경망은 입력층 뉴런이 이미지의 크기가 28*28이므로 784이고 출력층은 0~9까지의 숫자를 구분하기 때문에 10이 된다. 은닉층은 2개로 첫 번째 은닉층에서 50개의 뉴런을, 두 번째 은닉층에서 100개의 뉴런을 배치하고자 한다.

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import pickle # 파이썬에서 리스트나 클래스 이외의 자료형을 파일로 저장하고자 할때 사용
from mnist import load_mnist # dataset폴더에 있는 mnist라는 파일에서 load_mnist라는 함수를 import 해라
from common.functions import sigmoid, softmax

def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    # flattern = True로 설정해 읽어 들인 이미지는 1차원 넘파이 배열로 저장
    return x_test, t_test

def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network

def predict(network, x): # 각 레이블의 확률을 넘파이 배열로 반환한다. 
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)

    return y

x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
    y = predict(network, x[i])
    p= np.argmax(y) # 확률이 가장 높은 원소의 인덱스를 얻는다.
    if p == t[i]: # 신경망이 숫자를 맞췄다면
        accuracy_cnt += 1 # 그 횟수를 증가시킨다.

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
# len(x)는 전체 이미지 숫자이고 신경망이 맞춘 숫자를 전체 이미지 숫자로 나눠서 정확도를 구한다.

 

배치처리

하나로 묶은 입력 데이터를 배치라고한다.

배치처리는 이미지 1장당 처리 시간을 대폭 줄여준다.

배치처리를 구현해본다.

'''
x, t = get_data()
network = init_network()
accuracy_cnt = 0

for i in range(len(x)):
    y = predict(network,x[i])
    p = np.argmax(y)
    if p == t[i]: # 신경망이 숫자를 맞췄다면
        accuracy_cnt += 1 # 그 횟수를 증가시킨다.
'''

x, t = get_data()
network = init_network()

batch_size = 100
accuracy_cnt = 0

for i in range(0,len(x), batch_size): # 0부터 batch_size 만큼 묶어나간다.
    x_batch = x[i:i+batch_size]
    y_batch = predict(network, x_batch)
    p = np.argmax(y_batch,axis = 1) 
    # 100x10의 배열 중 1차원을 구성하는 각 원소에서(1번째 차원을 축으로) 최대값의 인덱스를 찾도록 한 것
    accuracy_cnt += np.sum(p == t[i:i+batch_size])
    
print('Accuracy:' + str(float(accuracy_cnt)/len(x))) 
# len(x)는 전체 이미지 숫자이고 신경망이 맞춘 숫자를 전체 이미지 숫자로 나눠서 정확도를 구한다.

'밑바닥 딥러닝 > 밑바닥부터 시작하는 딥러닝1' 카테고리의 다른 글

6장  (0) 2023.06.22
5장  (0) 2023.06.02
4장  (0) 2023.06.01
2장  (0) 2023.04.07
3장  (0) 2023.04.07