You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从零实现的单隐藏层MLP无法学习,损失持续上升求排查

嘿,我太懂这种从零撸MLP结果模型完全不干活还反向搞事情的挫败感了!下面我帮你梳理几个无库实现时最容易踩的坑,这些大概率就是你模型学不起来、损失还飙升的罪魁祸首:

排查核心问题

1. 权重初始化踩了大坑

如果你的__init__里是直接用random.random()生成0-1的权重,那基本直接宣判“模型死刑”——过大的初始值会让sigmoid激活函数直接进入饱和区(输出趋近于0或1),此时梯度几乎为0,反向传播根本更新不了权重;要是你初始值全设成0,还会导致神经元对称,永远学不出差异化特征。

  • 正确姿势:用小范围随机值初始化,比如从-0.1到0.1之间取随机数,或者用1/√输入维度来缩放权重,避免激活饱和。

2. 激活函数的梯度算错了

你用到了sigmoid(从math.exp能看出来),那反向传播时的梯度必须严格对应:sigmoid的导数是σ(x)*(1-σ(x))。如果这里算错了,梯度方向直接反转,权重越更新越离谱,损失自然一路飙升。

  • 额外提醒:XOR是二分类任务,输出层用sigmoid没问题,但要确保损失函数和输出匹配(比如用均方误差或交叉熵)。

3. 反向传播的链式法则搞反了

这是无库实现最容易翻车的环节,尤其是隐藏层到输出层、输入层到隐藏层的梯度传递:

  • 输出层的误差项应该是(预测值-真实值)*输出层激活导数;
  • 隐藏层的误差项是输出层误差 × 输出层权重矩阵转置 × 隐藏层激活导数;
    要是你把矩阵乘法的顺序搞反了,或者漏乘了激活导数,权重更新逻辑完全错误,模型根本不可能学习。

4. 学习率设置不合理

学习率太大,权重更新会“冲过头”,直接跳过最优解导致损失震荡飙升;学习率太小,模型龟速学习,看起来像完全没动静。

  • 建议先从0.01或0.1开始试,慢慢调整到合适的值。

5. 损失函数计算逻辑错误

比如你用均方误差的话,标准写法是0.5*(预测值-真实值)**2(加0.5是为了求导后简化计算),如果搞反了预测和真实值的顺序,或者漏了平方,哪怕不影响梯度方向,也会拖累学习效率,甚至让你看到的损失上升是“假信号”。

实用调试小技巧
  1. 打印中间值:正向传播时打印隐藏层的激活值,要是大部分都接近0或1,说明权重初始化太大导致激活饱和;反向传播时打印梯度值,看看是不是全为0或者异常大。
  2. 先测简单任务:别直接上XOR,先让模型学个简单的线性任务(比如y=x),如果线性任务都学不会,那肯定是正向/反向传播的基础逻辑错了。
  3. 逐行核对公式:把你的反向传播代码和标准单隐藏层MLP的公式逐行对比,尤其是权重更新部分:
    • 输出层权重更新:weights_out -= 学习率 × 输出层误差 × 隐藏层激活值
    • 隐藏层权重更新:weights_hidden -= 学习率 × 隐藏层误差 × 输入值
参考权重初始化示例

给你贴个符合要求的__init__片段,对应你的代码结构:

import random
from math import exp

class MLP:
    def __init__(self, num_inputs, num_hidden, num_outputs):
        self.num_inputs = num_inputs
        self.num_hidden = num_hidden
        self.num_outputs = num_outputs
        
        # 小范围随机初始化权重,避免激活饱和
        self.weights_hidden = [[random.uniform(-0.1, 0.1) for _ in range(num_inputs)] 
                               for _ in range(num_hidden)]
        self.weights_output = [[random.uniform(-0.1, 0.1) for _ in range(num_hidden)] 
                               for _ in range(num_outputs)]
        
        # 偏置也要同步小范围初始化
        self.bias_hidden = [random.uniform(-0.1, 0.1) for _ in range(num_hidden)]
        self.bias_output = [random.uniform(-0.1, 0.1) for _ in range(num_outputs)]

内容的提问来源于stack exchange,提问作者KOB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:29:04