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()