编写深度学习代码时Sigmoid函数如何避免除零错误
Sigmoid实现的除零/数值错误规避方案
你当前使用的sigmoid实现未做任何数值稳定性防护,并不会在正向传播阶段直接触发除零,但会在输入取极端值时出现指数溢出,导致激活值被截断为0或1,最终在反向传播计算梯度时触发除零错误。
问题产生的具体逻辑
原生公式A = 1 / (1 + np.exp(-Z))的数值风险来自两个极端场景:
- 当Z为绝对值极大的负数时,
-Z为极大正数,np.exp(-Z)会上溢为inf,此时计算得到的A会被截断为0,后续反向传播如果对A做除法、取对数运算,就会直接触发除零、对数域错误。 - 当Z为绝对值极大的正数时,
-Z为极小负数,np.exp(-Z)会下溢为0,此时计算得到的A会被截断为1,同样会在反向传播阶段引发数值错误。
规避逻辑
核心是利用sigmoid的数学等价性,对输入的正负区间做分支计算,从根源上避免大值指数运算:
- 对所有满足
Z >= 0的元素,保留原公式1/(1 + np.exp(-Z)):此时-Z <= 0,np.exp(-Z)取值范围在(0, 1]之间,不会出现指数上溢,计算结果稳定。 - 对所有满足
Z < 0的元素,使用等价变形公式np.exp(Z) / (1 + np.exp(Z)):此时Z < 0,np.exp(Z)取值范围在(0, 1)之间,同样不会出现指数溢出,计算结果不会被异常截断。 - 额外防护:如果需要进一步兜底,可以在所有除法运算的分母上添加一个极小的平滑项(如
1e-8),彻底避免分母为0的极端情况。
数值稳定版实现代码
import numpy as np def sigmoid(Z): """ 逐元素计算Z的sigmoid激活值(数值稳定版本) 参数 --------- Z : array 仿射变换层的输出值 返回值 ------- A : array 经过sigmoid激活后的输出值 Z : array 仿射变换层的原始输出值(供反向传播阶段缓存复用) """ A = np.zeros_like(Z, dtype=np.float64) # 生成正负区间掩码做分支计算 pos_mask = Z >= 0 neg_mask = ~pos_mask # 正区间计算逻辑 A[pos_mask] = 1 / (1 + np.exp(-Z[pos_mask])) # 负区间计算逻辑 exp_z_neg = np.exp(Z[neg_mask]) A[neg_mask] = exp_z_neg / (1 + exp_z_neg) return A, Z
内容的提问来源于stack exchange,提问作者user2458922
相关产品推荐
相关产品推荐

