# Python3.8 Mnist，手写SGD，2层神经网络，误差反向传播法（高速）

By [Untitled](https://paragraph.com/@0x4c116102691ae5a11413c255a117d413bcb136e4) · 2021-10-09

---

直接上程序，看注释解释，没有批量，没写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
    

![在这里插入图片描述](https://storage.googleapis.com/papyrus_images/462f90d6320e12201626ea785f9dd30b5715188c7e5511085ca1be3217ca22e0.png)

在这里插入图片描述

---

*Originally published on [Untitled](https://paragraph.com/@0x4c116102691ae5a11413c255a117d413bcb136e4/python3-8-mnist-sgd-2)*
