Java实现反向传播算法训练XOR网络10000轮不收敛问题排查
1. 权重初始化范围错误
你当前使用rand.nextDouble()生成权重,取值范围是*[0,1),所有权重均为正值,会极大增加网络陷入局部最优的概率,XOR任务很容易卡在不收敛的局部点。
修正方法:将初始权重调整为正负对称的范围,比如rand.nextDouble()*2 -1,将取值范围变为[-1,1]*,偏置项w0也做同样调整。
2. 反向传播计算顺序错误
你没有明确给出learn方法的执行逻辑,反向传播必须严格按照**输出层→隐层(从靠近输出层到靠近输入层逐层计算)**的顺序执行:必须先算完所有输出层神经元的upgrade值,再计算隐层的upgrade值。如果顺序颠倒,隐层计算时引用的n.upgrade是上一轮训练的旧值,完全无法传递正确的误差信号。
3. sigmoid导数实现错误
你代码中derivate(out)的实现如果和sigmoid不匹配也会直接导致训练失效。sigmoid函数f(net) = 1/(1+e^-net)的导数可以直接用输出值计算:derivate(out) = out * (1 - out),如果你的实现不是这个逻辑,或者错误用了net值而非out值计算导数,需要修正。
4. 学习率设置不合理
你没有给出超参数theta(学习率)的取值:如果学习率大于1会导致训练震荡不收敛,如果小于0.001会导致10000轮训练迭代次数不足,无法收敛到合适的权重。XOR任务推荐学习率设置在0.1~0.5区间即可。
5. 输入顺序与权重顺序不匹配
需要确认prev列表中神经元的顺序,和weight列表中权重的顺序是一一对应的:即prev.get(i)到本神经元的连接权重,必须是weight.get(i),如果顺序错位,计算的net值完全错误。
6. 隐层多输出兼容隐患(当前XOR场景不触发)
你hiddenLayerLearn方法中int f = next.get(0).prev.indexOf(this);只取了第一个下一层神经元的索引,当输出层神经元数量大于1时,如果不同输出层神经元的prev列表顺序不一致,会导致权重取错,建议改为遍历每个下一层神经元时单独查询本神经元在其prev列表的索引,或者提前固定每层的神经元顺序,统一权重位置。
内容的提问来源于stack exchange,提问作者Balázs Berecz

