基于Numpy的神经网络无法学习(准确率停滞10%)求助
MNIST分类模型准确率仅10%且固定输出同一结果的问题排查与修复
我用Numpy搭建了一个基础人工神经网络(ANN),针对MNIST手写数字数据集(10分类)进行训练,但模型预测准确率始终维持在10%左右,更换数据集后问题仍存在。进一步排查发现,模型全程只输出同一个数字作为预测结果,怀疑是反向传播环节出现变量错误,以下是完整代码:
import numpy as np import pandas as pd from matplotlib import pyplot as plt data = pd.read_csv('train.csv') data = np.array(data) m, n = data.shape np.random.shuffle(data) data_train = data.T X_train = data_train[1:n] Y_train = data_train[0] def init_params(): W1 = np.random.randn(10, 784) b1 = np.random.rand(10, 1) W2 = np.random.randn(10, 10) b2 = np.random.randn(10, 1) return W1, b1, W2, b2 def ReLU(Z): return np.maximum(0, Z) def softmax(Z): e = np.exp(Z - Z.max(axis=0, keepdims=True)) return e/e.sum(axis=0, keepdims=True) def forward_prop(W1, b1, W2, b2, X): Z1 = W1.dot(X) + b1 A1 = ReLU(Z1) Z2 = W2.dot(A1) + b2 A2 = softmax(Z2) return Z1, A1, Z2, A2 def one_hot(Y): one_hot_Y = np.zeros((Y.size, Y.max() + 1)) one_hot_Y[np.arange(Y.size), Y] = 1 one_hot_Y = one_hot_Y.T return one_hot_Y def deriv_ReLU(Z): return (Z > 0).astype(int) def back_prop(Z1, A1, Z2, A2, W2, X, Y): m = Y.size one_hot_Y = one_hot(Y) dZ2 = A2 - one_hot_Y dW2 = 1 / m * dZ2.dot(A1.T) db2 = 1 / m * np.sum(dZ2, 1).reshape(-1, 1) dZ1 = W2.T.dot(dZ2) * deriv_ReLU(Z1) dW1 = 1 / m * dZ1.dot(X.T) db1 = 1 / m * np.sum(dZ1, 1).reshape(-1, 1) return dW1, db1, dW2, db2 def update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, alpha): W1 = W1 - alpha * dW1 db1 = b1 - alpha * db1 W2 = W2 - alpha * dW2 db2 = b2 - alpha * db2 return W1, b1, W2, b2 def get_predictions(A2): return np.argmax(A2, 0) def get_accuracy(predictions, Y): print(predictions, Y) return np.sum(predictions == Y) / Y.size def gradient_descent(X, Y, iterations, alpha): W1, b1, W2, b2 = init_params() for i in range(iterations): Z1, A1, Z2, A2 = forward_prop(W1, b1, W2, b2, X) dW1, db1, dW2, db2 = back_prop(Z1, A1, Z2, A2, W2, X, Y) W1, b1, W2, b2 = update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, alpha) if (i % 50): print(f'Iteration: {i}') print(f'Accuracy: {get_accuracy(get_predictions(A2), Y)}') return W1, b1, W2, b2 W1, b1, W2, b2 = gradient_descent(X_train, Y_train, 100, 0.1)
问题根源与修复方案
1. 偏置更新变量错误(核心问题)
在update_params函数中,偏置更新的变量名写错:
- 错误代码:
db1 = b1 - alpha * db1、db2 = b2 - alpha * db2 - 正确写法:
b1 = b1 - alpha * db1、b2 = b2 - alpha * db2
这个错误导致模型的偏置参数从未更新,始终停留在初始值,模型无法学习到有效特征,只能输出固定结果。
2. 未做数据归一化
MNIST数据集的像素值范围是0-255,未归一化会导致矩阵乘积W1.dot(X)的数值过大,引发ReLU激活函数饱和,梯度消失,模型无法收敛。需要将输入数据归一化到0-1区间:
X_train = data_train[1:n] / 255.0
3. 迭代打印条件错误
gradient_descent中的打印条件if (i % 50)会在i不是50的倍数时打印,不符合“每50次迭代输出一次”的预期,应修改为:
if i % 50 == 0:
4. 初始偏置的分布选择(可选优化)
b1使用np.rand生成0-1均匀分布,换成np.randn(标准正态分布)更符合神经网络参数初始化的常规做法,避免初始值过度偏向某一区间。
修正后的完整代码
import numpy as np import pandas as pd from matplotlib import pyplot as plt data = pd.read_csv('train.csv') data = np.array(data) m, n = data.shape np.random.shuffle(data) data_train = data.T # 数据归一化 X_train = data_train[1:n] / 255.0 Y_train = data_train[0] def init_params(): W1 = np.random.randn(10, 784) # 换成标准正态分布初始化偏置 b1 = np.random.randn(10, 1) W2 = np.random.randn(10, 10) b2 = np.random.randn(10, 1) return W1, b1, W2, b2 def ReLU(Z): return np.maximum(0, Z) def softmax(Z): e = np.exp(Z - Z.max(axis=0, keepdims=True)) return e/e.sum(axis=0, keepdims=True) def forward_prop(W1, b1, W2, b2, X): Z1 = W1.dot(X) + b1 A1 = ReLU(Z1) Z2 = W2.dot(A1) + b2 A2 = softmax(Z2) return Z1, A1, Z2, A2 def one_hot(Y): one_hot_Y = np.zeros((Y.size, Y.max() + 1)) one_hot_Y[np.arange(Y.size), Y] = 1 one_hot_Y = one_hot_Y.T return one_hot_Y def deriv_ReLU(Z): return (Z > 0).astype(int) def back_prop(Z1, A1, Z2, A2, W2, X, Y): m = Y.size one_hot_Y = one_hot(Y) dZ2 = A2 - one_hot_Y dW2 = 1 / m * dZ2.dot(A1.T) db2 = 1 / m * np.sum(dZ2, 1).reshape(-1, 1) dZ1 = W2.T.dot(dZ2) * deriv_ReLU(Z1) dW1 = 1 / m * dZ1.dot(X.T) db1 = 1 / m * np.sum(dZ1, 1).reshape(-1, 1) return dW1, db1, dW2, db2 def update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, alpha): W1 = W1 - alpha * dW1 # 修正偏置更新变量 b1 = b1 - alpha * db1 W2 = W2 - alpha * dW2 b2 = b2 - alpha * db2 return W1, b1, W2, b2 def get_predictions(A2): return np.argmax(A2, 0) def get_accuracy(predictions, Y): return np.sum(predictions == Y) / Y.size def gradient_descent(X, Y, iterations, alpha): W1, b1, W2, b2 = init_params() for i in range(iterations): Z1, A1, Z2, A2 = forward_prop(W1, b1, W2, b2, X) dW1, db1, dW2, db2 = back_prop(Z1, A1, Z2, A2, W2, X, Y) W1, b1, W2, b2 = update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, alpha) # 修正打印条件 if i % 50 == 0: print(f'Iteration: {i}') print(f'Accuracy: {get_accuracy(get_predictions(A2), Y):.4f}') return W1, b1, W2, b2 W1, b1, W2, b2 = gradient_descent(X_train, Y_train, 500, 0.1)
效果验证
修正后,模型的准确率会随着迭代次数逐步提升,通常迭代500次后能达到85%以上的准确率,不会再出现固定输出同一数字的情况。
内容的提问来源于stack exchange,提问作者Ambaka Le Gregam
相关产品推荐
相关产品推荐

