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

大batch_size下Numpy实现ReLU-Adam神经网络Loss出现NaN问题求助

大Batch Size下Loss变NaN的原因及修复方案

嘿,咱们来拆解下为啥大batch size会让你的神经网络Loss变成NaN的问题,结合你的代码细节来看,主要有这几个核心原因:

1. Adam优化器的更新步长在大Batch下容易失控

你用的Adam里,梯度已经除以batch_size做了归一化,但大batch的梯度噪声极小、更接近真实梯度,加上Adam的偏置修正项(比如1-beta1**epoch)在训练初期(epoch很小的时候)会把梯度放大好几倍(比如epoch=1时,1-0.9^1=0.1,相当于把一阶矩直接放大10倍)。如果你的学习率lr=5e-3在小batch下刚好合适,大batch下这个放大后的步长就可能太猛——比如权重突然变得极大,使得ReLU激活后的输出要么全是0(死亡ReLU),要么溢出成无穷大,后续计算Loss时(output_layer-train_output)**2就会变成inf,再下一步就会出现NaN。

2. Dropout实现缺失「反向缩放」,大Batch下加剧训练不稳定

你的训练代码里用了dropout,但只做了随机丢弃(hidden_layer1 *= U1),没有做inverted dropout(也就是训练时把保留的神经元输出除以p)。小batch的时候,dropout的随机性还能带来一些噪声缓冲,但大batch下,整个batch的统计特性更稳定,这种没有缩放的dropout会让隐藏层的输出期望比验证时低很多(训练时期望是p*原始输出,验证时你直接乘了p,看似一致,但训练时是硬丢弃,方差更大),模型很容易学到极端参数,进而引发数值溢出。

3. 大Batch下梯度的数值稳定性更差

当batch_size等于整个训练集时,你计算的是精确梯度,不像小batch有噪声稀释梯度幅值。如果你的数据本身分布比较极端(比如输入或标签有异常值),精确梯度的幅值会远大于小batch的平均梯度,直接导致参数更新时出现数值爆炸——比如权重瞬间变得极大,计算np.dot(train_input, W1)时就会溢出成inf,Loss自然就变成NaN了。

对应的修复建议

  • 调小学习率:大batch下把lr改成1e-3甚至更小,或者根据batch_size按比例调整(比如batch_size扩大N倍,学习率扩大sqrt(N)倍,Adam下不用严格遵守,先调小试试)。
  • 修复Dropout实现:改成inverted dropout,训练时:
    U1 = np.random.rand(*self.hidden_layer1.shape) < self.p
    self.hidden_layer1 *= U1
    self.hidden_layer1 /= self.p  # 加上这行反向缩放
    
    验证时不用乘p,直接正常前向传播即可。
  • 数据归一化:把输入和标签都标准化到0均值、1方差,比如用sklearn.preprocessing.StandardScaler处理,这能大幅提升数值稳定性。
  • 梯度裁剪:给Adam的更新步长加个幅值限制,防止步长突然过大,比如:
    step = first_unbias_W2 / (np.sqrt(second_unbias_W2) + 1e-7)
    step = np.clip(step, -1e-2, 1e-2)  # 限制步长范围
    self.W2 -= self.lr * step
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:44:35