纯Numpy实现三层单神经元神经网络权重无变化问题求助
问题分析与修复方案
问题描述
尝试用Numpy实现一个三层神经网络(输入层+ReLU隐藏层+Sigmoid输出层,每层仅1个神经元),通过梯度下降和均方误差(MSE)训练。数据集为随机生成的年龄数据:输入年龄>18时输出为1,否则为0。
现象:权重和偏置初始化为2,无论迭代多少epoch,权重与偏置均无变化,但损失值却在下降。网络结构如下:(x)---((y1 = w1 * x + b1)|(z1 = relu(y1)))----((y2 = w2 * z1 + b2)|(z2 = sigmoid(y2)))
错误分析
代码存在多个关键bug导致权重偏置无法更新:
- Sigmoid导数函数逻辑错误:
d_of_sig函数中遍历空列表y(与函数内变量重名),且计算式错误,应使用输入值计算x*(1-x)。 - ReLU导数的输入错误:计算
dz1dy1时,应传入ReLU的输入y1而非输出z1,因为ReLU导数基于输入是否大于0判断。 - 链式求导函数变量遗漏:多个链式求导循环中存在变量遍历不完整的问题,无法正确累积每个样本的梯度。
- 未利用Numpy向量化:用列表循环实现运算,既低效又易出现索引错误。
修复后的完整代码
import numpy as np import random as r # 数据集生成 x = [] y = [] for i in range(100): age = r.randint(0, 80) x.append(age) y.append(1 if age > 18 else 0) # 转换为numpy数组,支持向量化运算 x = np.array(x, dtype=np.float32) y = np.array(y, dtype=np.float32) # 前向传播函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def relu(x): return np.maximum(0, x) def mse(y_true, y_pred): return np.mean((y_true - y_pred)**2) # 反向传播导数函数 def dmse(y_true, y_pred): return 2 * (y_true - y_pred) def d_relu(x): return np.where(x > 0, 1, 0) def d_sigmoid(x): return x * (1 - x) # 梯度下降实现 def gradient_descent(x, y, lr, epoch): w1 = w2 = b1 = b2 = 2.0 for i in range(epoch): # 前向传播 y1 = w1 * x + b1 z1 = relu(y1) y2 = w2 * z1 + b2 z2 = sigmoid(y2) cost = mse(y, z2) # 反向传播计算梯度 dcdz2 = dmse(y, z2) dz2dy2 = d_sigmoid(z2) # 第二层权重/偏置梯度 dw2 = np.mean(dcdz2 * dz2dy2 * z1) db2 = np.mean(dcdz2 * dz2dy2) # 第一层权重/偏置梯度 dz1dy1 = d_relu(y1) dw1 = np.mean(dcdz2 * dz2dy2 * w2 * dz1dy1 * x) db1 = np.mean(dcdz2 * dz2dy2 * w2 * dz1dy1) # 更新参数 w2 -= lr * dw2 b2 -= lr * db2 w1 -= lr * dw1 b1 -= lr * db1 # 可选:每10轮打印损失 if (i+1) % 10 == 0: print(f"Epoch {i+1}, Cost: {cost:.4f}") return w2, b2, w1, b1, cost # 执行训练 print(gradient_descent(x, y, 0.001, 300))
关键修改说明
- 修复导数计算:修正Sigmoid和ReLU导数的逻辑错误,确保梯度计算准确。
- 向量化重构:改用Numpy数组和向量化运算,简化代码并避免循环索引错误。
- 调整学习率:将原学习率0.1改为0.001,防止梯度爆炸,保证训练稳定。
- 优化参数更新:直接通过Numpy的均值计算批量梯度,替代复杂的循环累加。
内容的提问来源于stack exchange,提问作者PallabGhosh
相关产品推荐
相关产品推荐

