One layer SoftMax Classifier, "Handwriting recognition"

  • 2019 年 10 月 7 日
  • 筆記

 

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:Anaconda3libsite-packagesipykernel_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