直接上程序,看注释解释,没有批量,没写batch norm
main.py
#main.py启动文件
import numpy
import random
import os
import file_io
import network
import functions
#file_io.init_weight()#第一次执行的时候需要,并且将下行的 while True改成while False
while True:
a,b,c,d,e,f=file_io.read_weight()
w_i_h1=numpy.array(a)
w_h1_h2=numpy.array(b)
w_h2_o=numpy.array(c)
d1=numpy.array(d)
d2=numpy.array(e)
d3=numpy.array(f)
w_i_h1=w_i_h1.reshape((784,200))
w_h1_h2=w_h1_h2.reshape((200,200))
w_h2_o=w_h2_o.reshape((200,10))
rate=0.01#建议0.01
n=network.n_network(w_i_h1,w_h1_h2,w_h2_o,d1,d2,d3,rate)
y=[0,0,0,0,0,0,0,0,0,0]
s=int(input("1:训练 2:分析 3:正确率(1000张) 4:重置权重 0:退出:"))
while s!=1 and s!=2 and s!=3 and s!=4 and s!=0:
s=int(input("输入错误,重新输入:1:训练 2:分析 3:正确率(1000张) 4:重置权重 0:退出:"))
if s==1:#训练
times=1000000#训练1000000张图片
for m in range(times):
if (m+1)%1000==0:
print("---------------------------"+str((m+1)/times*100)+"%"+"---------------------------")
#n.save_weight()
t=[]
z=[]
i=random.randint(0,9)
path="mnist_train/"+str(i)+"/"
for j in range(10):
y[j]=0
y[i]=1
#print(y)
fn_list=os.listdir(path)
#print(path)
sample = random.sample(fn_list,1)
for i,name in enumerate(sample):
z.append(file_io.img2vec(path+name))
t=numpy.array(y)
x=numpy.array(z)
n.train(x,t)
if (m+1)%10000==0:#每10000张图片保存一次权重
n.save_weight()
elif s==2:#验证一张随机图片的正确与否
j=random.randint(0,9)
path="mnist_test/"+str(j)+"/"
print(j)
fn_list=os.listdir(path)
sample = random.sample(fn_list,1)
for i,name in enumerate(sample):
x=[]
x.append(file_io.img2vec(path+name))
y=n.check(x)
print(functions.softmax(y))
#print(numpy.argmax(y))
if numpy.argmax(y)==j:
print("正确")
else:
print("错误")
elif s==3:#验证1000张图片的正确率
corret=0
all=1000
for k in range(all):
j=random.randint(0,9)
#j=1
path="mnist_test/"+str(j)+"/"
#print()
fn_list=os.listdir(path)
sample = random.sample(fn_list,1)
for i,name in enumerate(sample):
x=[]
x.append(file_io.img2vec(path+name))
y=n.check(x)
#y=softmax(y)
#print(numpy.argmax(y))
if numpy.argmax(y)==j:
corret+=1
print("正确率:"+str(corret/all*100)+"%")
elif s==4:#重置权重
file_io.init_weight()
print("重置权重完成")
elif s==0:
break
network.py
#network.py 构建神经网络,以及一些主要的算法
import numpy
import openpyxl
import random
import os
import functions
import layer
import collections
class n_network:
def __init__(self,w_i_h1,w_h1_h2,w_h2_o,d1,d2,d3,rate):#初始化,w_i_h、w_h_o、w_h2_o是权重矩阵,d1、d2、d3是偏量数组,rate学习率
self.rate=rate
self.w_i_h1=w_i_h1
self.w_h1_h2=w_h1_h2
self.w_h2_o=w_h2_o
self.d1=d1
self.d2=d2
self.d3=d3
self.layers=collections.OrderedDict()
self.layers["Affine1"]=layer.Affine(self.w_i_h1,self.d1)
self.layers["sigmoid1"]=layer.sigmoid()
self.layers["Affine2"]=layer.Affine(self.w_h1_h2,self.d2)
self.layers["sigmoid2"]=layer.sigmoid()
self.layers["Affine3"]=layer.Affine(self.w_h2_o,self.d3)
self.lastlayer=layer.softmaxtwithloss()
def save_weight(self):#用于将学习到的权重保存到XLSX文件
wb_i_h1=openpyxl.Workbook()
ws_i_h1=wb_i_h1.active
for i in range(784):
row = []
for j in range(200):
row.append(self.w_i_h1[i][j])
ws_i_h1.append(row)
wb_i_h1.save("w_i_h1.xlsx")
wb_h1_h2=openpyxl.Workbook()
ws_h1_h2=wb_h1_h2.active
for i in range(200):
row = []
for j in range(200):
row.append(self.w_h1_h2[i][j])
ws_h1_h2.append(row)
wb_h1_h2.save("w_h1_h2.xlsx")
wb_h2_o=openpyxl.Workbook()
ws_h2_o=wb_h2_o.active
for i in range(200):
row = []
for j in range(10):
row.append(self.w_h2_o[i][j])
ws_h2_o.append(row)
wb_h2_o.save("w_h2_o.xlsx")
db1=openpyxl.Workbook()
ds1=db1.active
row=[]
for i in range(200):
row.append(self.d1[i])
ds1.append(row)
db1.save("d1.xlsx")
db2=openpyxl.Workbook()
ds2=db2.active
row=[]
for i in range(200):
row.append(self.d2[i])
ds2.append(row)
db2.save("d2.xlsx")
db3=openpyxl.Workbook()
ds3=db3.active
row=[]
for i in range(10):
row.append(self.d3[i])
ds3.append(row)
db3.save("d3.xlsx")
def check(self,input_arr):#验证输入与输出
x=input_arr
for l in self.layers.values():
x=l.forward(x)
return x
def loss(self,x,t):#用于计算损失值
y=self.check(x)
return self.lastlayer.forward(y,t)
def grandient(self,x,t):#误差反向传播,计算损失
dout=1
dout=self.lastlayer.backward(dout)
layers=list(self.layers.values())
layers.reverse()
for l in layers:
dout=l.backward(dout)
grad={}
grad["w_i_h1"]=self.layers["Affine1"].dw
grad["d1"]=self.layers["Affine1"].db
grad["w_h1_h2"]=self.layers["Affine2"].dw
grad["d2"]=self.layers["Affine2"].db
grad["w_h2_o"]=self.layers["Affine3"].dw
grad["d3"]=self.layers["Affine3"].db
return grad
def train(self,x,t):
self.loss(x,t)#先正向走一遍
#以下是将误差加入各个权重
grad=self.grandient(x,t)
grad["w_i_h1"]=grad["w_i_h1"].reshape((784,200))
grad["d1"].shape=(200)
grad["w_h1_h2"].shape=(200,200)
grad["d2"].shape=(200)
grad["w_h2_o"].shape=(200,10)
grad["d3"].shape=(10)
self.w_i_h1-=self.rate*grad["w_i_h1"]
self.w_h1_h2-=self.rate*grad["w_h1_h2"]
self.w_h2_o-=self.rate*grad["w_h2_o"]
self.d1-=self.rate*grad["d1"]
self.d2-=self.rate*grad["d2"]
self.d3-=self.rate*grad["d3"]
layer.py
#layer.py,各层的正反向算法
import numpy
import random
import os
import network
import functions
import scipy.special
class softmaxtwithloss:#softmax层,以及计算损失值
def __init__(self):
self.loss=None
self.y=None
self.t=None
def forward(self,y,t):
self.t=t
self.y=functions.softmax(y)
self.loss=functions.cross_entropy_error(self.y,self.t)
return self.loss
def backward(self,dout):
dout=1
dx=self.y-self.t
return dx
class Affine:#神经元层
def __init__(self,w,b):
self.w=w
self.b=b
self.x=None
self.dw=None
self.db=None
def forward(self,x):
self.x=x
out=numpy.dot(x,self.w)+self.b
return out
def backward(self,dout):
dx=numpy.dot(dout,self.w.T)
self.dw=numpy.dot(self.x.T,dout)
self.db=dout
return dx
class sigmoid:#sigmiod层
def __init__(self):
self.out=None
def forward(self,x):
out=scipy.special.expit(x)
self.out=out
return out
def backward(self,dout):
dx=dout*(1.0-self.out)*self.out
return dx
functions.py
#functions.py 一些函数方法
import numpy
import scipy.special
import openpyxl
from PIL import Image
import random
import os
import network
def softmax(a):
c=numpy.max(a)
exp_a=numpy.exp(a-c)
sum_exp_a=numpy.sum(exp_a)
num=exp_a/sum_exp_a
return num
def cross_entropy_error(a,b):
delta=0.00000001
c=-numpy.sum(b*numpy.log(a+delta))
return c
file_io.py
#file_io.py 文件存取
import numpy
import openpyxl
from PIL import Image
import os
def init_weight():#初始化权重及存入文件
w_i_h1=numpy.random.randn(784,200)/numpy.sqrt(784)
w_h1_h2=numpy.random.randn(200,200)/numpy.sqrt(200)
w_h2_o=numpy.random.randn(200,10)/numpy.sqrt(200)
d1=numpy.random.randn(200)/numpy.sqrt(784)
d2=numpy.random.randn(200)/numpy.sqrt(200)
d3=numpy.random.randn(10)/numpy.sqrt(200)
wb_i_h1=openpyxl.Workbook()
ws_i_hi=wb_i_h1.active
for i in range(784):
row = []
for j in range(200):
row.append(w_i_h1[i][j])
ws_i_hi.append(row)
wb_i_h1.save("w_i_h1.xlsx")
wb_h1_h2=openpyxl.Workbook()
ws_h1_h2=wb_h1_h2.active
for i in range(200):
row = []
for j in range(200):
row.append(w_h1_h2[i][j])
ws_h1_h2.append(row)
wb_h1_h2.save("w_h1_h2.xlsx")
wb_h2_o=openpyxl.Workbook()
ws_h2_o=wb_h2_o.active
for i in range(200):
row = []
for j in range(10):
row.append(w_h2_o[i][j])
ws_h2_o.append(row)
wb_h2_o.save("w_h2_o.xlsx")
db1=openpyxl.Workbook()
ds1=db1.active
row=[]
for i in range(200):
row.append(d1[i])
ds1.append(row)
db1.save("d1.xlsx")
db2=openpyxl.Workbook()
ds2=db2.active
row=[]
for i in range(200):
row.append(d2[i])
ds2.append(row)
db2.save("d2.xlsx")
db3=openpyxl.Workbook()
ds3=db3.active
row=[]
for i in range(10):
row.append(d3[i])
ds3.append(row)
db3.save("d3.xlsx")
def read_weight():#读取文件内的权重
w_i_h1=[]
wb_i_h1=openpyxl.load_workbook("w_i_h1.xlsx")
ws_i_h1=wb_i_h1.active
for i in range(784):
for j in range(200):
w_i_h1.append(ws_i_h1.cell(i+1,j+1).value)
w_h1_h2=[]
wb_h1_h2=openpyxl.load_workbook("w_h1_h2.xlsx")
ws_h1_h2=wb_h1_h2.active
for i in range(200):
for j in range(200):
w_h1_h2.append(ws_h1_h2.cell(i+1,j+1).value)
w_h2_o=[]
wb_h2_o=openpyxl.load_workbook("w_h2_o.xlsx")
ws_h2_o=wb_h2_o.active
for i in range(200):
for j in range(10):
w_h2_o.append(ws_h2_o.cell(i+1,j+1).value)
d1=[]
db1=openpyxl.load_workbook("d1.xlsx")
ds1=db1.active
for i in range(200):
d1.append(ds1.cell(1,i+1).value)
d2=[]
db2=openpyxl.load_workbook("d2.xlsx")
ds2=db2.active
for i in range(200):
d2.append(ds2.cell(1,i+1).value)
d3=[]
db3=openpyxl.load_workbook("d3.xlsx")
ds3=db3.active
for i in range(10):
d3.append(ds3.cell(1,i+1).value)
return w_i_h1,w_h1_h2,w_h2_o,d1,d2,d3
def img2vec(fname):#将图片转换成数值为(-1,1)的矩阵
im = Image.open(fname).convert('L')
im = im.resize((28,28))
tmp = numpy.array(im)
vec = tmp.ravel()/255*2-1
return vec
训练文件夹mnist_train和测试文件夹mnist_test的内容,0-9共10个文件夹,分别保存0-9的数字图片
将rate=0.0001,最后可将正确率收敛在98.5%左右