手动实现L层深度神经网络 3隐藏层下成本未下降问题求助
问题说明
手动从零实现深度神经网络前向传播、反向传播逻辑,采用梯度下降优化成本误差,但网络配置3个隐藏层时成本始终无下降趋势,核心反向传播实现代码如下:
def backward_propagation(parameters, AL, cache, X, Y): m = X.shape[1] L = len(parameters)//2 grads = {} cache['A' + str(0)] = X dZ = AL-Y A_prev = cache['A' + str(L-1)] dW = (1/m)*np.dot(dZ,A_prev.T) db = (1/m)*np.sum(dZ,axis=1,keepdims=True) grads["dW"+str(L)] = dW grads["db"+str(L)] = db grads["dZ"+str(L)] = dZ for l in range(L-1,0,-1): # 从输出层前一层反向遍历 A = cache['A' + str(l)] W = parameters['W' + str(l+1)] dZ_next = grads["dZ"+str(l+1)] A_prev = cache['A' + str(l-1)] temp = np.zeros(A.shape) temp[A < 0] = 0 temp[A >= 0] = 1 dZ = np.dot(W.T,dZ_next)*temp dW = (1/m)*np.dot(dZ,A_prev.T) db = (1/m)*np.sum(dZ,axis=1,keepdims=True) grads["dW"+str(l)] = dW grads["db"+str(l)] = db grads["dZ"+str(l)] = dZ return grads
核心Bug定位
- ReLU激活导数计算对象错误:ReLU的导数需要基于层的线性输出
Z计算,你当前用激活后的输出A计算导数存在本质问题——ReLU的输出A = max(0, Z)本身不存在负值,所以你构造的temp矩阵所有元素都会是1,相当于ReLU层完全没有做负半轴梯度归零的操作,3层隐藏层的深度下梯度会直接爆炸,参数更新完全失控,成本自然无法下降。 - 缓存数据缺失:从代码逻辑看,你的前向传播缓存里只存了各层激活值
A,没有存各层的线性输出Z,这也是导致你反向传播时错拿A算导数的直接原因。
代码改进建议
- 修复前向传播缓存逻辑:前向传播计算时,把每一层的线性输出
Z和激活输出A一起存入cache,反向传播计算ReLU导数时,直接取对应层的Z计算:dZ = np.dot(W.T, dZ_next) * (Z > 0).astype(float),替换掉原来用A计算temp的逻辑。 - 替换权重初始化方式:深网络不要用过大尺度的随机初始化或者全0初始化,隐藏层权重统一用He初始化:
W[l] = np.random.randn(当前层神经元数, 上一层神经元数) * np.sqrt(2 / 上一层神经元数),偏置可以初始化为0,从初始化层面避免梯度消失/爆炸。 - 增加梯度校验环节:实现数值梯度计算函数,对反向传播输出的解析梯度做校验,两者误差在1e-7量级时说明梯度计算逻辑完全正确,可从根源排除反向传播的计算错误。
- 超参数调优先做基线测试:先把学习率设置在1e-3~1e-2区间做小样本测试,避免学习率过大导致参数震荡、成本不收敛;先在1层隐藏层的浅网络上跑通代码、确认成本正常下降,再逐步加深网络层数。
- 核对前向传播匹配逻辑:确认前向传播每一层的线性计算、激活计算维度完全匹配,输出层激活和损失函数对应正确:二分类任务用sigmoid输出搭配二元交叉熵损失,多分类任务用softmax输出搭配多类交叉熵损失。
内容的提问来源于stack exchange,提问作者Sriram
相关产品推荐
相关产品推荐

