自制三层神经网络预测MNIST结果随机,求问题排查指引
三层MNIST神经网络训练后预测结果随机性异常
自行搭建三层神经网络用于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= dz3 dz2=ReLU_deriv(z2)*w3.T@dz3 dw2 = dz2@A1.T db2 = dz2 dz1=ReLU_deriv(z1)*w2.T@dz2 dw1 = dz1@A.T db1 = 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 learn(): lr=0.00002 w1,b1,w2,b2,w3,b3=init_setup() # read the data from a csv file df=pd.read_csv('data.csv') # Shuffle the data df = df.sample(frac=1).reset_index(drop=True) for epoch in range(0,5): 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\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
问题排查与修复方案
- 学习率衰减逻辑错误:初始学习率
0.00002已经过小,且每轮epoch都将学习率除以10,5轮后学习率变为2e-10,权重几乎无法更新,网络参数接近初始随机值。修复:去掉每轮除以10的逻辑,将初始学习率调整为0.01或0.001,后续可根据收敛情况调整衰减策略。 - 权重初始化不合理:
np.random.randn(...) - 0.8会让初始权重偏向负数,经过ReLU激活后大量神经元输出为0,导致梯度消失。修复:使用He初始化(适配ReLU):w1 = np.random.randn(10,784) * np.sqrt(2/784) b1 = np.zeros((10,1)) # 偏置初始化为0更稳定 - 反向传播梯度计算错误:
m=1/Y.size错误,单样本训练时批量大小为1,m应等于1,当前设置会将梯度缩小10倍,更新幅度不足。- ReLU导数直接修改输入数组
Z,会污染原数据,修复为:def ReLU_deriv(Z): return np.where(Z > 0, 1, 0)
- 输入数据未归一化:MNIST像素值范围是0-255,未归一化会导致权重更新数值不稳定。修复:将输入A除以255,归一化到0-1范围:
A = row.values[1:] / 255.0 - softmax数值稳定性问题:直接计算
np.exp(Z)易出现数值溢出,修复为:def softmax(Z): exp_Z = np.exp(Z - np.max(Z)) # 减去最大值避免溢出 return exp_Z / np.sum(exp_Z) - 未固定随机种子:每次运行初始权重和数据shuffle都是随机的,加上网络未有效学习,导致结果差异大。修复:在代码开头设置随机种子:
np.random.seed(42)
内容的提问来源于stack exchange,提问作者yao3414
相关产品推荐
相关产品推荐

