python numpy overflow exp

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 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