Python 的 numpy.exp 函数中的溢出错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40726490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 23:54:51  来源:igfitidea点击:

Overflow Error in Python's numpy.exp function

pythonnumpyscipy

提问by Fcoder

I want to use numpy.explike this:

我想这样使用numpy.exp

cc = np.array([
    [0.120,0.34,-1234.1]
])

print 1/(1+np.exp(-cc))

But this gives me error:

但这给了我错误:

/usr/local/lib/python2.7/site-packages/ipykernel/__main__.py:5: RuntimeWarning: overflow encountered in exp

I can't understand why? How can I fix this? It seems the problem is with third number (-1234.1)

我不明白为什么?我怎样才能解决这个问题?似乎问题出在第三个数字上(-1234.1)

回答by Praveen

As fuglede says, the issue here is that np.float64can't handle a number as large as exp(1234.1). Try using np.float128instead:

正如 fuglede 所说,这里的问题是np.float64无法处理像exp(1234.1). 尝试使用np.float128

>>> cc = np.array([[0.120,0.34,-1234.1]], dtype=np.float128)
>>> cc
array([[ 0.12,  0.34, -1234.1]], dtype=float128)
>>> 1 / (1 + np.exp(-cc))
array([[ 0.52996405,  0.58419052,  1.0893812e-536]], dtype=float128)

Note however, that there are certain quirks with using extended precision. It may not work on Windows; you don't actually get the full 128 bits of precision; and you might lose the precision whenever the number passes through pure python. You can read more about the details here.

但是请注意,使用扩展精度存在某些怪癖。它可能不适用于 Windows;您实际上并没有获得完整的 128 位精度;每当数字通过纯 python 时,您可能会失去精度。您可以在此处阅读有关详细信息的更多信息。

For most practical purposes, you can probably approximate 1 / (1 + <a large number>)to zero. That is to say, just ignore the warning and move on. Numpy takes care of the approximation for you (when using np.float64):

对于大多数实际用途,您可能可以近似1 / (1 + <a large number>)为零。也就是说,只需忽略警告并继续前进。Numpy 为您处理近似值(使用时np.float64):

>>> 1 / (1 + np.exp(-cc))
/usr/local/bin/ipython3:1: RuntimeWarning: overflow encountered in exp
  #!/usr/local/bin/python3.4
array([[ 0.52996405,  0.58419052,  0.        ]])

If you want to suppress the warning, you could use scipy.special.expit, as suggested by WarrenWeckesser in a comment to the question:

如果你想抑制警告,你可以使用scipy.special.expit,正如 WarrenWeckesser 在对问题的评论中所建议的那样:

>>> from scipy.special import expit
>>> expit(cc)
array([[ 0.52996405,  0.58419052,  0.        ]])

回答by fuglede

The largest value representable by a numpyfloat is 1.7976931348623157e+308, whose logarithm is about 709.782, so there is no way to represent np.exp(1234.1).

numpy浮点数可表示的最大值为 1.7976931348623157e+308,其对数约为 709.782,因此无法表示np.exp(1234.1)

In [1]: import numpy as np

In [2]: np.finfo('d').max
Out[2]: 1.7976931348623157e+308

In [3]: np.log(_)
Out[3]: 709.78271289338397

In [4]: np.exp(709)
Out[4]: 8.2184074615549724e+307

In [5]: np.exp(710)
/usr/local/bin/ipython:1: RuntimeWarning: overflow encountered in exp
  #!/usr/local/bin/python3.5
Out[5]: inf

回答by jmd_dk

A possible solution is to use the decimalmodule, which lets you work with arbitrary precision floats. Here is an example where a numpyarray of floats with 100 digits precision is used:

一个可能的解决方案是使用该decimal模块,它可以让您使用任意精度的浮点数。下面是一个示例,其中numpy使用了 100 位精度的浮点数数组:

import numpy as np
import decimal

# Precision to use
decimal.getcontext().prec = 100

# Original array
cc = np.array(
    [0.120,0.34,-1234.1]
)
# Fails
print(1/(1 + np.exp(-cc)))    

# New array with the specified precision
ccd = np.asarray([decimal.Decimal(el) for el in cc], dtype=object)
# Works!
print(1/(1 + np.exp(-ccd)))

回答by user1559897

exp(-1234.1) is too small for 32bit or 64bit floating-point numbers. Since it cannot be represented, numpy produces the correct warning.

exp(-1234.1) 对于 32 位或 64 位浮点数来说太小了。由于无法表示,numpy 会产生正确的警告。

Using IEEE 754 32bit floating-pointnumbers, the smallest positive number it can represent is 2^(-149), which is roughly 1e-45.

使用IEEE 754 32bit floating-point数字,它可以表示的最小正数是2^(-149),大约是 1e-45。

If you use IEEE 754 64 bit floating-pointnumbers, the smallest positive number is 2^(-1074)which is roughy 1e-327.

如果使用IEEE 754 64 bit floating-point数字,则最小的正数2^(-1074)是粗略的 1e-327。

In either case, it cannot represent a number as small as exp(-1234.1) which is about 1e-535.

在任何一种情况下,它都不能表示像 exp(-1234.1) 这样小的数字,大约为 1e-535。

You should be using the expitfunction from scipy to compute the sigmoid function. This would give you better precision.

您应该使用expitscipy 中的函数来计算 sigmoid 函数。这会给你更好的精度。

For practical purposes, exp(-1234.1) is a very small number. If rounding to zero makes sense in your use case, numpy produces benign results by rounding it to zero.

出于实际目的,exp(-1234.1) 是一个非常小的数字。如果在您的用例中舍入为零是有意义的,则 numpy 通过将其舍入为零来产生良性结果。