关于python:如何避免numpy.exp()溢出

How to avoid an overflow in numpy.exp()

我在堆栈溢出方面读了很多东西,但我仍然不明白如何避免溢出错误。我正在建立一个使用S形函数的神经网络。
但是我不能不对这些错误进行转换或找到解决方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def activation(x):
    return  1/(1+np.exp(-x))

  def dactivation(x):
    return  activation(x)*(1-activation(x))


  def propagateb(self, target, lrate=8.1, momentum=0.1):
        deltas = []
        error = target - self.layers[-1]
        delta = error*dactivation(self.layers[-1])
        deltas.append(delta)
        for i in range(len(self.shape)-2,0,-1):
            delta =np.dot(deltas[0],self.weights[i].T)*dactivation(self.layers[i])
            deltas.insert(0,delta)
        for i in range(len(self.weights)):
            layer = np.atleast_2d(self.layers[i])
            delta = np.atleast_2d(deltas[i])
            dw = np.dot(layer.T,delta)
            self.weights[i] += lrate*dw + momentum*self.dw[i]
            self.dw[i] = dw

        # Return error
        return (error**2).sum()

提高

1
2
ann.py:5: RuntimeWarning: overflow encountered in exp
  return  1/(1+np.exp(-x))

SciPy带有执行此操作的功能,不会向您发出警告:

1
scipy.special.expit(x)

这个想法是,您应该避免在something太大的情况下调用exp(something)。因此,在x >> 0时避免使用exp(x),在x << 0时避免使用exp(-x)

为了实现这一点,您可以先编写一个适用于x> 0的表达式,再编写一个适用于x <0的表达式。

  • 如果x> 0,则可以安全地使用表达式:1/(1+exp(-x))
  • 对于x <0,您可以通过将分子和分母乘以exp(x)来重写该表达式,从而得出exp(x) / (1+exp(x))。如您所见,这里不再有exp(-x)
  • 您可以找到一种适用于两种情况的表达式:

    给定x是一个矩阵,我在这里的个人实验中使用了np.exp(np.fmin(x, 0)) / (1 + np.exp(-np.abs(x))) https://github.com/thirionjl/chains/blob/master/chains/operations/activation_ops.py#L42


    使用numpy整数时必须小心,因为它们没有如此处所述的任意精度。

    对于numpy double,该范围为(-1.79769313486e+308, 1.79769313486e+308)

    也可以看看这个答案,它描述得很好。

    有关numpy dtype及其允许范围的更多信息。


    似乎传入的数据必须是整数,尽管此激活函数应返回浮点数。我认为修复方法很简单,如

    1
    return  1./(1.+np.exp(-x))

    我猜想如果没有此更改,代码将尝试进行整数除法,从而产生错误。