python - Tratar con el desbordamiento en exp usando numpy
overflow (5)
Usando numpy, tengo esta definición de una función:
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
Esta función se evalúa una gran cantidad de veces en una rutina de optimización. A menudo plantea excepción:
RuntimeWarning: overflow encountered in exp
Entiendo que el operando no se puede almacenar en el espacio asignado para un flotador. Pero, ¿cómo puedo superar el problema?
Dependiendo de sus necesidades específicas, puede ser útil recortar el argumento de entrada para exp()
. Si realmente desea obtener una inf
si se desborda o si desea obtener números absurdamente enormes, entonces otras respuestas serán más apropiadas.
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)))
Resultado:
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
Tenga en cuenta que powellBadlyScaled2
no se powellBadlyScaled2
/ powellBadlyScaled
cuando lo hizo el powellBadlyScaled
original, pero la versión modificada da 1.79769313486e+305
lugar de inf
en una de las pruebas. Me imagino que hay muchas aplicaciones donde 1.79769313486e+305
es prácticamente inf
y esto estaría bien, o incluso sería preferible porque 1.79769313486e+305
es un número real y inf
no lo es.
Prueba scipy''s
scipy.special.expit(x)
.
Puede usar numpy.seterr
para controlar el comportamiento de numpy en esta circunstancia: http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html
También puede usar el módulo de advertencias para controlar cómo se presentan o no las advertencias: http://docs.python.org/library/warnings.html
Puede utilizar el paquete bigfloat. Es compatible con operaciones de punto flotante de precisión arbitraria.
http://packages.python.org/bigfloat/
import bigfloat
bigfloat.exp(5000,bigfloat.precision(100))
# -> BigFloat.exact(''2.9676283840236670689662968052896e+2171'', precision=100)
¿Está utilizando un marco de optimización de funciones? Usualmente implementan límites de valor (usando términos de penalización). Trata eso. ¿Son los valores relevantes realmente tan extremos? En la optimización no es raro minimizar el registro (f). (probabilidad de registro aproximada, etc, etc). ¿Está seguro de que desea optimizar ese valor de exp y no registrar (exp (f)) == f. ?
Eche un vistazo a mi respuesta a esta pregunta: funciones logit e logit inverso para valores extremos
Por cierto, si todo lo que haces es minimizar powellBadlyScaled (x, y), entonces el mínimo está en x -> + inf y y -> + inf, por lo que no hay necesidad de números.
Tal vez usted pueda mejorar su algoritmo al verificar en qué áreas recibe advertencias (probablemente debajo de ciertos valores para X [0], X [1]) y reemplazar el resultado con un número realmente grande. Debe ver cómo se comporta su función, creo que debería verificar, por ejemplo, exp (-x) + exp (-y) + x * y