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

自定义CrossEntropyLoss反向传播时'numpy.ndarray'无backprop属性报错排查

报错排查与修复方案

AttributeError的核心触发点

你在forward方法里把原本要存的层对象给覆盖成数组了:

  • 方法开头本来的写法是对的:self.pred = pred,这里存的是传入的前级网络模块,也就是自定义实现的层/激活函数对象,这类对象本身是带有backprop方法的。
  • 但后面写实现逻辑时你加了一行self.pred = self.scores,这里的self.scores是从层对象的out属性里取出来的计算结果,本质是numpy数组。
    等到执行backprop方法、调用self.pred.backprop(...)的时候,self.pred早已经不是最开始那个有backprop方法的层对象,换成了纯数组,自然会报“numpy数组没有backprop属性”的错。

改完上面的覆盖问题后,还要修正的几处逻辑错误

如果只删掉覆盖的代码不调整计算逻辑,后面还是会出问题:

  • 你写了self.target = self.scores.shape[0],直接把本来要存真实标签的self.target给覆盖成了batch大小的整数,后面算损失根本读不到标签值
  • Softmax的归一化维度错了:现在的写法是对整个数组全局求和归一化,没有按每个样本的维度逐行算,多分类下的概率结果完全不对,还容易因为指数太大出现数值溢出
  • 损失计算逻辑混了别的损失的公式:你后面加的loss += (self.target - self.pred)/self.N是MSE损失的计算逻辑,和交叉熵的公式完全不搭
  • 反向梯度的计算不对:现在写的self.dscores = self.pred -1没有结合标签位置,算出来的梯度和实际要求的交叉熵导数差很远

具体修改步骤

  1. 删掉forward方法里两行错误的赋值覆盖:
    # 这两行直接删掉
    self.target=self.scores.shape[0]
    self.pred=self.scores 
    
    保证self.pred始终存传入的前级层对象,self.target始终存传进来的真实标签数组。
  2. 调整Softmax的计算,加入数值稳定处理,按行逐样本算归一化概率:
    # 减去每行最大值避免exp上溢
    shifted_scores = self.scores - np.max(self.scores, axis=1, keepdims=True)
    exp_scores = np.exp(shifted_scores)
    self.probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    
  3. 按交叉熵的正确公式算损失:取每个样本对应真实类别的概率,算负对数后求batch平均
    N = self.scores.shape[0]
    sample_loss = -np.log(self.probs[np.arange(N), self.target])
    loss = np.sum(sample_loss) / N
    
  4. 修正反向传播的梯度计算,归一化后再传给前级层:
    N = self.scores.shape[0]
    self.dscores = self.probs.copy()
    # 每个样本在对应真实类别的位置减1
    self.dscores[np.arange(N), self.target] -= 1
    # 按batch大小归一化梯度
    self.dscores /= N
    self.pred.backprop(self.dscores)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 18:15:04