Python3.8 Mnist,手写SGD,2层神经网络,误差反向传播法(高速)

本文介绍了一个使用Python实现的手写数字识别神经网络,通过随机梯度下降算法进行训练,能够在MNIST数据集上达到98.5%的识别准确率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值