it-swarm.com.de

Behandeln Sie den Überlauf in exp mithilfe von numpy

Mit numpy habe ich die Definition einer Funktion: 

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

Diese Funktion wird in einer Optimierungsroutine sehr oft ausgewertet. Es gibt oft eine Ausnahme:

RuntimeWarning: overflow encountered in exp

Ich verstehe, dass der Operand nicht im zugewiesenen Speicherplatz für einen Float gespeichert werden kann. Aber wie kann ich das Problem überwinden?

21
octoback

Sie können das Bigfloat-Paket verwenden. Es unterstützt Gleitkommaoperationen mit beliebiger Genauigkeit.

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

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

Verwenden Sie ein Funktionsoptimierungs-Framework? Sie implementieren normalerweise Wertgrenzen (unter Verwendung von Vertragsstrafen). Versuch das. Sind die relevanten Werte wirklich so extrem? Bei der Optimierung ist es nicht ungewöhnlich, log (f) zu minimieren. (ungefähre logarithmische Wahrscheinlichkeit usw.). Möchten Sie den Exp-Wert wirklich optimieren und nicht protokollieren (exp (f)) == f. ?

Sehen Sie sich meine Antwort auf diese Frage an: logit und inverse logit-Funktionen für Extremwerte

Übrigens, wenn Sie nur powellBadlyScaled (x, y) minimieren, liegt das Minimum bei x -> + inf und y -> + inf.

18
Johan Lundberg

Versuchen Sie scipy's -

scipy.special.expit(x).

3
markroxor

Mit numpy.seterr können Sie steuern, wie sich numpy in diesem Fall verhält: http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html

Sie können das Warnungsmodul auch verwenden, um zu steuern, wie Warnungen angezeigt werden oder nicht: http://docs.python.org/library/warnings.html

2
Mike McKerns

Vielleicht können Sie Ihren Algorithmus verbessern, indem Sie prüfen, in welchen Bereichen Sie Warnungen erhalten (es wird wahrscheinlich bestimmte Werte für X [0], X [1] enthalten) und das Ergebnis durch eine wirklich große Zahl ersetzt. Sie müssen sehen, wie sich Ihre Funktion verhält. exp (-x) + exp (-y) + x * y

1
ntg

Abhängig von Ihren spezifischen Anforderungen kann es hilfreich sein, das Eingabeargument auf exp() zu beschneiden. Wenn Sie tatsächlich eine inf herausbekommen möchten, wenn sie überläuft oder Sie absurd riesige Zahlen erhalten möchten, sind andere Antworten angemessener.

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

Ergebnis:

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

Beachten Sie, dass powellBadlyScaled2 nicht über- bzw. unterschritten wurde, als die ursprüngliche powellBadlyScaled das tat, aber die modifizierte Version gibt 1.79769313486e+305 anstelle von inf in einem der Tests an. Ich kann mir vorstellen, dass es viele Anwendungen gibt, bei denen 1.79769313486e+305 praktisch inf ist und dies wäre in Ordnung oder sogar bevorzugt, da 1.79769313486e+305 eine reelle Zahl ist und inf nicht.

0
EL_DON