自制Python-Numpy简易神经网络权重无法下调问题求助
神经网络权重只增不减问题排查与解决建议
我刚接触神经网络编程,正通过Python结合Numpy编写简易神经网络以学习相关知识。目前网络整体运行尚可,但存在一个问题:权重(至少最后一层的权重)从未下降。网络初始阶段权重大幅增长,跳过了最优值,之后增长速率逐渐放缓,但始终不会下调权重以回归最优状态。调整学习率也无法解决该问题,仅能延缓这一现象,现寻求解决建议。
以下是我实现的批量评估、反向传播、Sigmoid、Sigmoid导数及损失函数代码:
def Sigmoid(self, x): return 1.0 / (1.0 + np.exp(-x)) def PrimeSigmoid(self, x): return self.Sigmoid(x) * (1.0 - self.Sigmoid(x)) def _OutputCost(self, aResult, tResult): return [(a - t)**2 for a, t in zip(aResult, tResult)] def _BackProp(self, tData, tGoal): derB = [np.zeros(b.shape) for b in self.gBiases] derW = [np.zeros(w.shape) for w in self.gWeights] activation = tData activations = [tData] zL = [] for b, w in zip(self.gBiases, self.gWeights): z = np.dot(w, activation) + b zL.append(z) activation = self.Sigmoid(z) activations.append(activation) cost = self._OutputCost(activations[-1], tGoal) ps = self.PrimeSigmoid(zL[-1]) deltas = cost * ps derB[-1] = deltas derW[-1] = np.dot(deltas, self.gWeights[-1]) for l in range(2, self.gLayerCount): z = zL[-l] sp = self.PrimeSigmoid(z) deltas = np.dot(deltas, self.gBiases[-l + 1]) * sp derB[-l] = deltas derW[-l] = np.dot(deltas, self.gWeights[-l]) return (derB, derW, np.average(cost, 0)) def _EvalBatch(self, batch, tSpeed): derB = [np.zeros(b.shape) for b in self.gBiases] derW = [np.zeros(w.shape) for w in self.gWeights] costL = [] for d, g in batch: dDerB, dDerW, cost = self._BackProp(d, g) costL.append(cost) derB = [nb + dnb for nb, dnb in zip(derB, dDerB)] derW = [nw + dnw for nw, dnw in zip(derW, dDerW)] self.gBiases = [b + (tSpeed / len(batch)) * nb for b, nb in zip(self.gBiases, derB)] self.gWeights = [w + (tSpeed / len(batch)) * nw for w, nw in zip(self.gWeights, derW)] self.gCost = np.average(np.array(costL), 0)
问题根源与修正方案
你的代码存在几个核心错误,直接导致权重只增不减:
梯度下降方向完全错误
梯度下降的核心是权重 = 权重 - 学习率 × 梯度,你当前的代码用+更新权重和偏置,不管梯度正负,权重只会持续增大。必须把更新逻辑中的加号改成减号:# 修正_EvalBatch中的更新代码 self.gBiases = [b - (tSpeed / len(batch)) * nb for b, nb in zip(self.gBiases, derB)] self.gWeights = [w - (tSpeed / len(batch)) * nw for w, nw in zip(self.gWeights, derW)]反向传播的梯度计算逻辑错误
- 最后一层权重梯度:正确计算是输出层delta与前一层激活值的转置做矩阵乘法,你当前错误地用delta乘自身权重:
# 替换_BackProp中最后一层derW的计算 derW[-1] = np.dot(deltas, activations[-2].T) - 隐藏层delta计算:应该用当前层的权重转置乘以上一层的delta,再乘以Sigmoid导数,你错误地使用了偏置(gBiases)进行矩阵乘法:
# 替换_BackProp中循环内的delta计算 deltas = np.dot(self.gWeights[-l + 1].T, deltas) * sp - 隐藏层权重梯度:同样需要用当前层delta与前一层激活值的转置相乘,你当前用了错误的对象:
# 替换_BackProp中循环内的derW计算 derW[-l] = np.dot(deltas, activations[-l - 1].T)
- 最后一层权重梯度:正确计算是输出层delta与前一层激活值的转置做矩阵乘法,你当前错误地用delta乘自身权重:
损失函数输出格式错误
你当前返回的是Python列表,与numpy数组相乘时可能出现维度或运算逻辑问题,改成直接用numpy数组运算:def _OutputCost(self, aResult, tResult): return (aResult - tResult)**2 # 直接使用numpy数组运算
额外优化建议
- 初始权重不要用过大的值,建议采用正态分布初始化,比如
np.random.normal(0, 1/np.sqrt(input_size), size=weight_shape),避免Sigmoid函数过早进入饱和区导致梯度消失。 - 可以打印每一轮的损失值和权重变化,方便观察训练过程是否正常。
内容的提问来源于stack exchange,提问作者Theuns
相关产品推荐
相关产品推荐

