読者です 読者をやめる 読者になる 読者になる

ニューラルネットワークで手書き文字認識

Python Neural Network

前回の記事でニューラルネットワークを使って為替レートを予測してみましたが、 せっかくなので、それを少し改良してTensorflowのチュートリアルと同じく手書き文字認識を試してみました。

import cv2
import numpy as np
from itertools import *

digit_w=28
digit_h=28
dim_in=digit_w*digit_h
dim_out=10
hidden_count=128
learn_rate=0.005
limit=50000

#weight and bias
w1 = np.random.rand(hidden_count, dim_in)-0.5
w2 = np.random.rand(dim_out, hidden_count)-0.5
b1 = np.random.rand(hidden_count)-0.5
b2 = np.random.rand(dim_out)-0.5

# activation function
def activation(x):
    return np.maximum(0, x)
    #return 1.0/(1.0+np.exp(-x))
    
# differential
def activation_dash(x):
    return (np.sign(x) + 1) / 2
    #return (1-activation(x))@activation(x)

#forward calculation
def forward(x):
    #return w2 @ activation(w1 @ x + b1) + b2
    return np.dot(w2,activation(np.dot(w1,x)+b1))+b2
    

# backpropagation
def backward(x, diff):
    global w1, w2, b1, b2
    #v1 = (diff @ w2) * activation_dash(w1 @ x + b1)
    #v2 = activation(w1 @ x + b1)

    v1=np.dot(diff,w2)*activation_dash(np.dot(w1,x)+b1)
    v2=activation(np.dot(w1,x)+b1)

    w1 -= learn_rate * np.outer(v1, x)
    b1 -= learn_rate * v1
    w2 -= learn_rate * np.outer(diff, v2)
    b2 -= learn_rate * diff

#column and row number of mnist images
image_shape=np.zeros((10,2),dtype=int)
#number of all mnist data
data_num=np.zeros((10,1),dtype=int)

#count number of mnist data
images=[]
for idx in range(0,10):
    images.append(cv2.imread("mnist_img/mnist_train"+str(idx)+".jpg",0)) #load images
    image=images[idx]
    image_shape[idx,0]=len(image[:,1])/digit_h
    image_shape[idx,1]=len(image[1,:])/digit_w-1
    data_num[idx]=image_shape[idx,0]*image_shape[idx,1]

train_count=int(sum(data_num))
train_x=np.zeros((train_count,dim_in))
train_y=np.zeros((train_count,dim_out),dtype=int)

#load input data
cnt=0
temp_num=0
for idx in range(0,10):
    print ("load image:"+str(idx))
    train_y[temp_num:temp_num+int(data_num[idx]),idx]=1 #set output data
    temp_num+=int(data_num[idx])
    image=images[idx]
    for i in range(0,image_shape[idx,0]):
        for j in range(0,image_shape [idx,1]):
            temp=image[digit_h*i:digit_h*(i+1),digit_w*j:digit_w*(j+1)]/255.0 #cut images
            train_x[cnt]=[flatten for inner in temp for flatten in inner] #flatten matrix
            cnt+=1

#main
idxes = np.arange(train_count)
_error=limit*[0]
batch_size=100
for epoc in range(limit):
    np.random.shuffle(idxes)
    error = 0
    cnt=0
    for idx in idxes:
        y = forward(train_x[idx])
        diff = y - train_y[idx] 
        error += diff ** 2
        cnt+=1
        backward(train_x[idx], diff)
        if cnt==batch_size:
           break

    _error[epoc]=error    
    print(epoc+1,error.sum(),y)

result=train_count*[0]
for idx in range(train_count):
    result[idx]=forward(train_x[idx])

#accuracy rate
eval=np.argmax(train_y,axis=1)==np.argmax(result,axis=1)
print (float(eval.sum())/eval.size)

np.savetxt("estimated.csv",result,delimiter=",")
np.savetxt("train_y.csv",train_y,delimiter=",")
np.savetxt("error.csv",_error,delimiter=",")

np.savetxt("w1.csv",w1,delimiter=",")
np.savetxt("w2.csv",w2,delimiter=",")
np.savetxt("b1.csv",b1,delimiter=",")
np.savetxt("b2.csv",b2,delimiter=",")


文字のデータはネットを探してjpg化されたものを拾ってきました。

Index of /~roweis/data

0から9までの手書き文字がそれぞれ1枚ずつ用意されていて、 それをグレースケールで一次元のデータとして読み込んでいます。 ※値は255で正規化。

データが読み込めたら後は、学習させるだけです。

上のプログラムに記載されているノード数、学習回数、学習率で実行すると、 約94%の正答率でした。学習したデータに対する正答率なので、もう少し高くても良い気もしますが、 特に何の工夫もしていませんので、こんなものでしょうか。

やる気があれば、ディープラーニングのプログラムを組んで、もう一回試してみたいです。



Python機械学習プログラミング 達人データサイエンティストによる理論と実践 impress top gearシリーズ

広告を非表示にする