使用numpy处理exp中的溢出

时间:2012-03-04 22:18:11

标签: python numpy overflow exp

使用numpy,我有一个函数的定义:

def powellBadlyScaled(X):
    f1 = 10**4 * X[0] * X[1] - 1
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001
    return f1 + f2

在优化例程中对此函数进行了大量计算。它经常引发例外:

RuntimeWarning: overflow encountered in exp

我知道操作数不能存储在float的已分配空间中。但是我怎么能克服这个问题呢?

6 个答案:

答案 0 :(得分:18)

您可以使用bigfloat包。它支持任意精度浮点运算。

http://packages.python.org/bigfloat/

import bigfloat
bigfloat.exp(5000,bigfloat.precision(100))
# -> BigFloat.exact('2.9676283840236670689662968052896e+2171', precision=100)

您使用的是功能优化框架吗?它们通常实现价值边界(使用惩罚条款)。试试吧。相关价值真的那么极端吗?在优化中,最小化log(f)并不罕见。 (近似对数似然等)。您确定要优化该exp值而不是log(exp(f))== f。 ?

看看我对这个问题的回答:logit and inverse logit functions for extreme values

顺便说一句,如果你所做的只是最小化powellBadlyScaled(x,y)那么最小值是x - >; + inf和y - > + inf,所以不需要数字。

答案 1 :(得分:2)

您可以使用numpy.seterr来控制numpy在这种情况下的行为:http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html

您还可以使用警告模块来控制警告的显示方式:http://docs.python.org/library/warnings.html

答案 2 :(得分:2)

尝试scipy' s -

scipy.special.expit(x)

答案 3 :(得分:1)

也许你可以通过检查哪些区域得到警告来改进你的算法(它可能会忽略X [0],X [1]的某些值),并用非常大的数字替换结果。你需要看看你的函数是如何表现的,我应该检查一下,例如exp(-x)+exp(-y)+x*y

答案 4 :(得分:1)

根据您的具体需求,将输入参数裁剪为exp()可能很有用。如果你真的希望得到一个inf,如果它溢出或你想获得荒谬的巨大数字,那么其他答案将更合适。

def powellBadlyScaled(X):
    f1 = 10**4 * X[0] * X[1] - 1
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001
    return f1 + f2


def powellBadlyScaled2(X):
    f1 = 10**4 * X[0] * X[1] - 1
    arg1 = -numpy.float(X[0])
    arg2 = -numpy.float(X[1])
    too_big = log(sys.float_info.max / 1000.0)  # The 1000.0 puts a margin in to avoid overflow later
    too_small = log(sys.float_info.min * 1000.0)
    arg1 = max([min([arg1, too_big]), too_small])
    arg2 = max([min([arg2, too_big]), too_small])
    # print('    too_small = {}, too_big = {}'.format(too_small, too_big))  # Uncomment if you're curious
    f2 = numpy.exp(arg1) + numpy.exp(arg2) - 1.0001
    return f1 + f2

print('\nTest against overflow: ------------')
x = [-1e5, 0]
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x)))
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x)))

print('\nTest against underflow: ------------')
x = [0, 1e20]
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x)))
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x)))

结果:

Test against overflow: ------------
*** overflow encountered in exp 
powellBadlyScaled([-100000.0, 0]) = inf
powellBadlyScaled2([-100000.0, 0]) = 1.79769313486e+305

Test against underflow: ------------
*** underflow encountered in exp    
powellBadlyScaled([0, 1e+20]) = -1.0001
powellBadlyScaled2([0, 1e+20]) = -1.0001

请注意powellBadlyScaled2在原始powellBadlyScaled完成时没有上/下溢,但修改后的版本在其中一个测试中提供了1.79769313486e+305而不是inf 。我想有很多应用程序1.79769313486e+305实际上是inf,这样会很好,甚至是首选,因为1.79769313486e+305是实数而inf不是。

答案 5 :(得分:0)

我有同样的问题。如果可以在某种程度上忽略精度,请使用np.round(my_float_array, decimals=<a smaller number>)来克服此运行时警告。