from PIL import Image
import numpy as np
import sys
from datetime import datetime
import json
class Dot(object):
def forward(self, X, W):
self.X=X
self.W=W
return np.dot(X, W)
def backward(self, dout):
return np.dot(dout, self.W.T), np.dot(self.X.T, dout)
class Add(object):
def forward(self, D, B):
return D+B
def backward(self, dout):
return np.sum(dout, axis=0)
class Affine(object):
def __init__(self):
self.dot=Dot()
self.add=Add()
def forward(self, X, W, B):
T=self.dot.forward(X, W)
return self.add.forward(T, B)
def backward(self, dout):
dB = self.add.backward(dout)
dX, dW = self.dot.backward(dout)
return dX, dW, dB
class Relu(object):
def forward(self, A):
self.mask=(A<=0)
A[self.mask]=0
return A
def backward(self, dout):
dout[self.mask]=0
return dout
class SoftmaxWithLoss(object):
def softmax(self, A):
A=A-A.max(axis=1, keepdims=True)
T=np.exp(A)
return T/np.sum(T, axis=1, keepdims=True)
def crossEntropyError(self, Z, Label):
delta=0.000000001
return -np.sum(np.log(Z+delta)*Label)/Z.shape[0]
def forward(self, A, Label):
self.Z=self.softmax(A)
self.Label=Label
return self.Z, self.crossEntropyError(self.Z, Label)
def backward(self, dout=1):
return (self.Z-self.Label)*dout/self.Z.shape[0]
class SimpleImageClassifier(object):
def __init__(self):
self.N0=28*28
self.N1=10
self.N2=10
self.N3=10
self.lr=0.01
self.MAX_NUM=100000
self.affine1=Affine()
self.relu1 =Relu()
self.affine2=Affine()
self.relu2 =Relu()
self.affine3=Affine()
self.softmax_with_loss=SoftmaxWithLoss()
self.loadWB()
print("self.W1\n",self.W1)
print("self.B1\n",self.B1)
print("self.W2\n",self.W2)
print("self.B2\n",self.B2)
print("self.W3\n",self.W3)
print("self.B3\n",self.B3)
print("")
def loadImg(self):
lst_img = []
for i in range(0, 10):
img = Image.open("img/{num}.jpg".format(num=i))
lst_img.append({"data":img.tobytes(), "label":i})
return lst_img
def predictWithLoss(self, X, Label):
A1=self.affine1.forward(X, self.W1, self.B1)
Z1= self.relu1.forward(A1)
A2=self.affine2.forward(Z1, self.W2, self.B2)
Z2= self.relu2.forward(A2)
A3=self.affine3.forward(Z2, self.W3, self.B3)
Z3, l = self.softmax_with_loss.forward(A3, Label)
return Z3, l
def getNumericalGradient(self):
D = self.softmax_with_loss.backward(dout=1)
dZ2, dW3, dB3 = self.affine3.backward(D)
dA2 = self.relu2.backward(dZ2)
dZ1, dW2, dB2 = self.affine2.backward(dA2)
dA1 = self.relu1.backward(dZ1)
dX, dW1, dB1 = self.affine1.backward(dA1)
return dW1,dB1,dW2,dB2,dW3,dB3
def updateWB(self, grad_W1,grad_B1,grad_W2,grad_B2,grad_W3,grad_B3):
def updateW(W, grad_W):
W-=self.lr*grad_W
def updateB(B, grad_B):
B-=self.lr*grad_B
updateW(self.W1, grad_W1)
updateB(self.B1, grad_B1)
updateW(self.W2, grad_W2)
updateB(self.B2, grad_B2)
updateW(self.W3, grad_W3)
updateB(self.B3, grad_B3)
def train(self):
X=[]
Label=[]
lst_img=self.loadImg()
for dic in lst_img:
b=max(dic["data"][:self.N0])
X.append([ a/b for a in dic["data"][:self.N0] ])
t=[0]*self.N3
t[dic["label"]]=1
Label.append(t)
X=np.array( X )
Label=np.array( Label )
self.showDetail(X, Label, i=-1)
for i in range(0, self.MAX_NUM):
self.predictWithLoss(X, Label)
grad_W1,grad_B1,grad_W2,grad_B2,grad_W3,grad_B3 = self.getNumericalGradient()
self.updateWB(grad_W1,grad_B1,grad_W2,grad_B2,grad_W3,grad_B3)
if i%20==0:
self.showDetail(X, Label, i)
self.showDetail(X, Label, i=self.MAX_NUM)
def showDetail(self, X, Label, i=0):
msg="i={i} time:{time}".format(i=i, time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(msg)
Z, l = self.predictWithLoss(X, Label)
print(Z)
print(l)
print("")
self.saveWB(out_file="wb.json", additional_data={"i":msg, "Z":Z.tolist(), "loss":l})
def saveWB(self, out_file="wb.json", additional_data={}):
dic={"W1":self.W1.tolist(), "B1":self.B1.tolist(), "W2":self.W2.tolist(), "B2":self.B2.tolist(), "W3":self.W3.tolist(), "B3":self.B3.tolist(), "additional_data":additional_data}
fout=open(out_file, "a+")
fout.write(json.dumps(dic))
fout.write("\n")
fout.close()
def loadWB(self, in_file="wb.json"):
WB=
dic=json.loads(WB)
self.W1=np.array( dic["W1"] )
self.B1=np.array( dic["B1"] )
self.W2=np.array( dic["W2"] )
self.B2=np.array( dic["B2"] )
self.W3=np.array( dic["W3"] )
self.B3=np.array( dic["B3"] )
def whichNumber(self, img_file):
img = Image.open(img_file)
data=img.tobytes()
X=[]
b=max(data[:self.N0])
X.append([ a/b for a in data[:self.N0] ])
Z, l=self.predictWithLoss(X, [0]*10)
print(Z[0])
b=max(Z[0])
num=np.where(Z[0]==b)[0][0]
print("num={num}, rate={rate}".format(num=num, rate=b))
return num
def main():
a=SimpleImageClassifier()
a.whichNumber("img/9.jpg")
if "__main__"==__name__:
main()