自己搭建的简单神经网络,预测结果不准确,无法返回确定结果

问题遇到的现象和发生背景

刚接触神经网络不久,最近在尝试自己构建一个简单的3层神经网络,来预测经典的MNIST数据集。网上看了一些代码受了一些启发,自己又写了的一些,代码运行的时候并没报错,
但是网络的学习过程应该是出了些问题。预测结果似乎都是“随机的”。每次跑相同的代码重置网络并重新学习,预测相同的图像片总是给出完全不一样的预测结果。想问问有人知道是什么问题么,万分感谢!

问题相关代码,请勿粘贴截图
import pandas as pd
import numpy as np
from PIL import Image
import os
np.set_printoptions(formatter={'float_kind':'{:f}'.format})
def init_setup():
    #three layers perception
    w1=np.random.randn(10,784)-0.8
    b1=np.random.rand(10,1)-0.8
    #second layer
    w2=np.random.randn(10,10)-0.8
    b2=np.random.randn(10,1)-0.8
    #third layer
    w3=np.random.randn(10,10)-0.8
    b3=np.random.randn(10,1)-0.8
    return w1,b1,w2,b2,w3,b3}
def activate(A):
    #激活函数
    # use ReLU function as the activation function
    Z=np.maximum(0,A)
    return Z
def softmax(Z):
    return np.exp(Z)/np.sum(np.exp(Z))

def forward_propagation(A,w1,b1,w2,b2,w3,b3):
#每层数据尺寸
# input A :(784,1)-> A1: (10,1) ->A2: (10,1) -> prob: (10,1)
    z1=w1@A+b1
    A1=activate(z1)
    z2=w2@A1+b2
    A2=activate(z2)
    z3=w3@A2+b3
    prob=softmax(z3)

    return z1,A1,z2,A2,z3,prob
def one_hot(Y:np.ndarray)->np.ndarray:

    one_hot=np.zeros((10, 1)).astype(int)
    
    one_hot[Y]=1
    return one_hot

def back_propagation(A,z1,A1:np.ndarray,z2,A2:np.ndarray,z3,prob,w1,w2:np.ndarray,w3,Y:np.ndarray,lr:float):

    m=1/Y.size

    dz3=prob-Y 
    # print('loss ', np.sum(dz3))
    dw3=m*dz3@A2.T

    db3= np.sum(dz3)
    dz2=ReLU_deriv(z2)*w3.T@dz3
    dw2 =  dz2@A1.T
    db2 =  np.sum(dz2)
    dz1=ReLU_deriv(z1)*w2.T@dz2
    dw1 = dz1@A.T
    db1 =  np.sum(dz1)
    return db1,dw1,dw2,db2,dw3,db3
def ReLU_deriv(Z):
    Z[Z>0]=1
    Z[Z<=0]=0
    return Z 
def step(lr,w1,b1,w2,b2,w3,b3,dw1,db1,dw2,db2,dw3,db3):
    w1 = w1 - lr * dw1

    b1 = b1 - lr * db1    
    w2 = w2 - lr * dw2  
    b2 = b2 - lr * db2
    w3 = w3 - lr * dw3 
    b3 = b3 - lr * db3       
    return w1,b1,w2,b2,w3,b3

def data_tocsv():
    #将训练集数据保存在一个csv中
    first=np.zeros((1,785))
    dir=r'C:\Users\Di Yao\Desktop\MNIST - JPG - training\{}'
    for num in range(10):
        path=dir.format(str(num))
        for i in os.listdir(path):
            img=Image.open(path+'\\'+i)
            array=np.asarray(img)
            array=array.reshape(1,784)
            array=np.append(num,array)
            first=np.vstack((first,array))
    print(first[0,])
    np.savetxt("foo.csv", first, delimiter=",")
    # data=first[1:,]
    # return data


def learn():
   #让网络学习,返回优化过的参数
    lr=0.1
    w1,b1,w2,b2,w3,b3=init_setup()
    #从csv中读取训练数据
    df=pd.read_csv('foo.csv')
    # 随机打乱数据
    df = df.sample(frac=1).reset_index(drop=True)
    for epoch in range(0,30):
        # lr=lr/10
        for _,row in df.iterrows():
            A=row.values[1:]
            A=A.reshape(784,1)
            Y=int(row.values[0])
            Y=one_hot(Y)
            z1,A1,z2,A2,z3,prob=forward_propagation(A,w1,b1,w2,b2,w3,b3)
            db1,dw1,dw2,db2,dw3,db3=back_propagation(A,z1,A1,z2,A2,z3,prob,w1,w2,w3,Y,lr)
            w1,b1,w2,b2,w3,b3=step(lr,w1,b1,w2,b2,w3,b3,dw1,db1,dw2,db2,dw3,db3)
    return  w1,b1,w2,b2,w3,b3

#用优化过的参数预测一张图片
optimize_params=learn()
w1,b1,w2,b2,w3,b3=optimize_params
img=Image.open(r'C:\Users\Di Yao\Desktop\MNIST - JPG - training\2\16.jpg')
A=np.asarray(img)
A=A.reshape(-1,1)
z1,A1,z2,A2,z3,prob=forward_propagation(A,w1,b1,w2,b2,w3,b3)
print(prob)
print(np.argmax(prob))

运行三次代码,结果如下

>>>[[0.020815] >>>[[0.025916] >>>[[0.161880]
    [0.019490]     [0.031197]     [0.104364]
    [0.113170]     [0.006868]     [0.093192]
    [0.051033]     [0.426709]     [0.041726]
    [0.107867]     [0.043123]     [0.062953]
    [0.009533]     [0.001528]     [0.324685]
    [0.148977]     [0.080894]     [0.102557]
    [0.333544]     [0.273520]     [0.043415]
    [0.147408]     [0.049245]     [0.009269]
    [0.048163]]    [0.060999]]    [0.055960]]
>>>7           >>>3           >>>5

这里预测结果应该为2,如图片路径所示,但是运行相同的代码三次,我得到了三个截然不同的结果。我知道神经网络中确有随机性,但是优化过后的参数不是应该差不多吗?为什么想同的图片每一次的概率可以差这么多呢。几天都没有发现问题出在了哪里
盲猜可能是梯度下降哪里有问题导致这个网络无法学习 但是几天也没找到原因在哪里 希望帮看一下 。万分感谢!

我个人建议可以用torch来实现,用numpy手写MLP难度有点大。(你有没有求导?)结果随机是因为你的层
是随机数,每次运行一遍就会有所不同。我这里有一段用numpy写的MLP(比较简陋),可以做个参考

import numpy as np
import math
x = np.linspace(-math.pi, math.pi, 2000)
y = np.sin(x)#y和x有一定的关系更好
a = np.random.randn()
def relu(x):
    return np.maximum(0, x)
learning_rate = 0.00001
for t in range(2000):
    y_pred = relu(a*x)
    loss = np.square(y_pred - y).sum()#求loss
    grad_y_pred = 2.0 * (y_pred - y)#求导数
    grad_a = x*grad_y_pred.sum()
    a -= learning_rate * grad_a
    print(loss)

还有一段用torch写的

import torch
import math
x = torch.linspace(-math.pi, math.pi, 2000)
y = torch.sin(x)
xx = x.unsqueeze(-1)
model = torch.nn.Sequential(torch.nn.Linear(1, 3), 
                            torch.nn.Linear(3, 1),
                            torch.nn.Flatten(0, 1))
loss_fn = torch.nn.MSELoss(reduction='sum')
learning_rate = 1e-6
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for t in range(2000):
    y_pred = model(xx)
    loss = loss_fn(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

首先要看在trainning set上的预测结果是不是够好,如果traing set上的结果不够好的话:
可以改变loss function,一般来说分类的时候,使用“mse”的预测结果不如“cross_entropy”。
调整适当的batch_size,不宜过大或者过小,100是个不错的选择。
可以加深网络,不过由于sigmod函数问题,可能训练结果不够好,可以改为relu函数作为激活函数。
对数据进行前期处理非常重要,在输入到网络之前,应该将网络nomalized。
当训练结果比较好,而预测结果比较差时:
early stopping,早点停止训练
在每一层上加入dropout,training上的结果会变差,但是test上的结果会变得更好。

没看到你模型有保存呀,你每次运行都是新的,当然结果不一样了

每次运行都是重新训练模型,最终的结果是有可能不一样的,可以把每次的训练模型进行保存,然后用相同的模型来预测,再看下结果

刚开始学习神经网络的话不建议使用图像识别案例,视觉类的应用中数据复杂度较高、冗余度更高,入门可以使用确定性的数据进行训练和测试,比如黑白棋、五子棋等棋局数据

神经网络欠拟合是不是每次输出结果都一样,称为欠拟合,都准确无误称为过拟合?

不是的rbsci。神经网络训练有训练集和测试集,一般数据比为7:3或8:2。训练集用于生成神经网络的逻辑,测试集用于验证神经网络的正确性。
如果训练集的准确率很高,而测试集很低,说明训练集模拟出的逻辑仅对训练集适用,而和实际差异很大,这种现象称为过拟合。
如果训练集和测试集准确率都很低,说明由于数据本身原因,或神经网络的不良特性,导致神经网络无法符合实际逻辑,这种现象称为欠拟合。
若派神经网络计算棒初始化失败是什么原因?


1)首先我们要确定节点名字是否正确,查看对于的节点名字跟2801生成的节点名字是否一致;2)是否有将一个*.rules的文件拷贝到/etc/udev/rules.d/目录下,这个文件的作用就是设置节点的权限、max_sectors2048(usb接口为例,这个值设置为2048比128速度提升30%),这个文件中的ATTR{vendor}如果固件程序改变,对于的pidvid也需要改变;如果没有拷贝这个文件,需要手动修改,可参看一下命令:(a)$cd/sys/devices(b)$find-name"max_sectors"./pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0/max_sectors//以我的开发板为例,可参考(c)$cd./pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/host4/target4:0:0/4:0:0:0/(d)$catmax_sectors2048(e)usb2.0的接口可能显示240的值。
可以修改为2048,我们芯片最好搭载的是usb3.0的接口,修改命令如下:(f)$su#echo2048>max_sectors3)节点权限设置节点777权限sudochmod777/dev/sg*。
BP神经网络在预测时输入与输出的个数不匹配的问题

你用的是Demux模块,错误的原因是输入和输出信号的维数不匹配。
Demux模块的基本作用是把一个输入信号给展开成多个输出信号,有两种工作模式,即向量模式和总线选择(Busselection)模式,取决于你是否选中了Busselectionmode参数(注意:MathWorks公司不鼓励使用Busselection模式来展开总线信号)。
猜测你很可能是按照默认情况下使用向量模式,所以下面的讨论以向量模式为前提。
Demux模块的参数Numberofoutputs可以是标量或向量,如果是标量,则指定了输出的个数;如果是向量,则向量的元素个数对应输出个数。
关于该参数的详细规定可以用docdemux查看相关文档。
可能导致出错的主要有以下两种情况(其他条件下,Simulink会采取一种比较合理的方式来理解你的输入参数):如果Numberofoutputs为标量,该标量的值大于输入向量的元素个数;如果Numberofoutputs为向量,向量各元素均为正且求和与输入向量的元素个数不等。
人力风险中,会出现哪些风险情况导致项目失败?

memcpy在什么情况下会失败

1、memcpy在使用时注意不可用字符串,如果是字符串会导致段错误,可以使用asprintf函数复制字符串,从而导致memcpy的段错误。
2、即memcpy不能拷贝目的地址(dest)和源地址(src)内存空间有重合的部分,更为确切的说应该是当目的地址大于源地址的时候,不能够有重合部分,否则源地址重合部分数据会发生错误。
3、当copy越界时,可能会出现程序异常。扩展资料:如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。
如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。
source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。
而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。参考资料来源:百度百科-memcpy。
神经网络具体是什么?

神经网络由大量的神经元相互连接而成。每个神经元接受线性组合的输入后,最开始只是简单的线性加权,后来给每个神经元加上了非线性的激活函数,从而进行非线性变换后输出。
每两个神经元之间的连接代表加权值,称之为权重(weight)。不同的权重和激活函数,则会导致神经网络不同的输出。举个手写识别的例子,给定一个未知数字,让神经网络识别是什么数字。
此时的神经网络的输入由一组被输入图像的像素所激活的输入神经元所定义。在通过非线性激活函数进行非线性变换后,神经元被激活然后被传递到其他神经元。重复这一过程,直到最后一个输出神经元被激活。
从而识别当前数字是什么字。
神经网络的每个神经元如下基本wx+b的形式,其中x1、x2表示输入向量w1、w2为权重,几个输入则意味着有几个权重,即每个输入都被赋予一个权重b为偏置biasg(z)为激活函数a为输出如果只是上面这样一说,估计以前没接触过的十有八九又必定迷糊了。
事实上,上述简单模型可以追溯到20世纪50/60年代的感知器,可以把感知器理解为一个根据不同因素、以及各个因素的重要性程度而做决策的模型。举个例子,这周末北京有一草莓音乐节,那去不去呢?
决定你是否去有二个因素,这二个因素可以对应二个输入,分别用x1、x2表示。此外,这二个因素对做决策的影响程度不一样,各自的影响程度用权重w1、w2表示。
一般来说,音乐节的演唱嘉宾会非常影响你去不去,唱得好的前提下即便没人陪同都可忍受,但如果唱得不好还不如你上台唱呢。所以,我们可以如下表示:x1:是否有喜欢的演唱嘉宾。
x1=1你喜欢这些嘉宾,x1=0你不喜欢这些嘉宾。嘉宾因素的权重w1=7x2:是否有人陪你同去。x2=1有人陪你同去,x2=0没人陪你同去。
是否有人陪同的权重w2=3。这样,咱们的决策模型便建立起来了:g(z)=g(w1x1+w2x2+b),g表示激活函数,这里的b可以理解成为更好达到目标而做调整的偏置项。
一开始为了简单,人们把激活函数定义成一个线性函数,即对于结果做一个线性变化,比如一个简单的线性激活函数是g(z)=z,输出都是输入的线性变换。
后来实际应用中发现,线性激活函数太过局限,于是引入了非线性激活函数

你的训练代码缺少了一个核心就是,在每个epoch训练完后,评估一下模型的性能。每次测试模型结果都不一样,可能是模型还没有拟合到位,所以你三次训练出来的模型都存在不足,故此每次预测都是错的。正常来说minist 训练20个epoch完全收敛了的,你需要考虑一下调整你的学习率。因为通常我们设置的学习率都是0.0001-0.05之间,大部分人喜欢设置为0.001,你的学习率为0.1太大,这可能是导致模型没能正常收敛的原因。如果你调好了适当的学习率,模型训练收敛,每次测试的结果应该都是差不多的