One layer SoftMax Classifier, "Handwriting recognition"

 

import lib needed

In [1]:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import re
from glob import glob
 

begin, load data

In [2]:
def load_data(train_path='train/',test_path='test/'):
    train_list=glob(r'train/*.png')
    pattern = re.compile(r'num(\d).png')
    train_id = np.array([float(pattern.search(img_name).groups()[0]) for img_name in train_list])
    train_data=np.concatenate([np.array(Image.open(img_name)).reshape(1,784) for img_name in train_list],axis=0).astype(np.float)
    test_list=glob(r'test/*.png')
    test_id=np.array([float(pattern.search(img_name).groups()[0]) for img_name in test_list])
    test_data=np.concatenate([np.array(Image.open(img_name)).reshape(1,784) for img_name in test_list],axis=0).astype(np.float)
    return train_id,train_data,test_id,test_data
 

load data, print the shape of data

In [3]:
train_id,train_data,test_id,test_data=load_data()
train_id.shape,train_data.shape,test_id.shape,test_data.shape
Out[3]:
((60000,), (60000, 784), (10000,), (10000, 784))
 

convert the shape of id/label

e.g. data_id "3" can be converted to [0,0,0,1,0,0,0,0,0,0]

In [5]:
train_val=np.zeros((train_id.shape[0],10))
for i in range(train_id.shape[0]):
    train_val[i,train_id[i].astype('int')]=1
 

split data into minibatches

In [6]:
mini_batch_num=100
mini_batch_size=600
 

define function need, such as softmax, propagation,back_propagation

In [7]:
def softmax(x):
    x=x-np.max(x) #using softmax(x)=softmax(x+c)
    exp_x=np.exp(x)
    softmax_x=exp_x/sum(np.exp(x))
    return softmax_x
 if you want to know more about softmax, https://segmentfault.com/a/1190000010039529?utm_source=tag-newest  is recommended to you

use cross entrophy to compute loss, this is part of propagation

In [8]:
def propa(train_x,train_y,W,b): #propagation
    yt=softmax(np.dot(train_x,W)+b)
    loss=-np.sum(train_y.T.dot(np.log(yt))) #cross entrophy
    dy=(yt-train_y).T
    return dy,loss
 if you wan to know more about softmax's cross entrophy, https://blog.csdn.net/lilong117194/article/details/81542667  is recommended to you

update W

In [9]:
def back_propa(train_data,train_id,W,b,alpha,data_size):
    for i in range(data_size):
        dy,loss=propa(train_data[i,:],train_id[i,:],W,b)
        dy=dy.reshape(1,10)
        p=train_data[i,:]
        p=p.reshape(784,1)
        dW=alpha*np.dot(p,dy)
        W-=dW
    return W,loss
 

initialize W and b

In [14]:
W=np.zeros((784,10))
b=1
 

loop and update, also print accurancy of our traindataset

In [16]:
for i in range(mini_batch_num):
    for iteration in range(20):
        lb=(mini_batch_size*i)
        ub=(mini_batch_size*(i+1))
        mini_batch_data=train_data[lb:ub,:]
        mini_batch_id=train_val[lb:ub,:]
        W,loss=back_propa(mini_batch_data,mini_batch_id,W,b,0.01,600)
        count=0
        for j in range(600):
            if np.argmax(softmax(train_data[j,:].dot(W)))==train_id[j].astype('int'):
                count+=1
        acc=count/600
    if i%10==0:
        print('batch={},acc={}'.format(i+1,acc))
 
e:\Anaconda3\lib\site-packages\ipykernel_launcher.py:3: RuntimeWarning: divide by zero encountered in log
  This is separate from the ipykernel package so we can avoid doing imports until
 
batch=1,acc=1.0
batch=11,acc=0.8833333333333333
batch=21,acc=0.865
batch=31,acc=0.8983333333333333
batch=41,acc=0.8766666666666667
batch=51,acc=0.8883333333333333
batch=61,acc=0.8733333333333333
batch=71,acc=0.845
batch=81,acc=0.89
batch=91,acc=0.8766666666666667
 

predict in the test dataset

In [17]:
for j in range(test_id.shape[0]):
    if np.argmax(softmax(test_data[j,:].dot(W)))==test_id[j].astype('int'):
        count+=1
acc=count/test_id.shape[0]
print(acc)
 
0.9103
posted @ 2019-10-07 16:42  runsdeep  阅读(312)  评论(0编辑  收藏  举报