使用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的已分配空间中。但是我怎么能克服这个问题呢?
答案 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>)
来克服此运行时警告。