En utilisant numpy, j'ai cette définition d'une fonction:
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
Cette fonction est évaluée un très grand nombre de fois dans une routine d'optimisation. Il soulève souvent une exception:
RuntimeWarning: overflow encountered in exp
Je comprends que l’opérande ne peut pas être stocké dans l’espace alloué pour un float. Mais comment puis-je surmonter le problème?
Vous pouvez utiliser le package bigfloat. Il supporte les opérations à virgule flottante de précision arbitraire.
http://packages.python.org/bigfloat/
import bigfloat
bigfloat.exp(5000,bigfloat.precision(100))
# -> BigFloat.exact('2.9676283840236670689662968052896e+2171', precision=100)
Utilisez-vous un cadre d’optimisation des fonctions? Ils implémentent généralement des limites de valeur (en utilisant des termes de pénalité). Essayez ça. Les valeurs pertinentes sont-elles vraiment extrêmes? En optimisation, il n’est pas rare de minimiser le journal (f). (probabilité approximative du journal, etc., etc.). Êtes-vous sûr de vouloir optimiser cette valeur exp et non pas vous connecter (exp (f)) == f. ?
Regardez ma réponse à cette question: fonctions logit et logit inverse pour les valeurs extrêmes
Btw, si tout ce que vous faites est de minimiser powellBadlyScaled (x, y) alors le minimum est à x -> + inf et y -> + inf, donc pas besoin de chiffres.
Essayez Scipy -
scipy.special.expit(x)
.
Vous pouvez utiliser numpy.seterr
pour contrôler le comportement de numpy dans ce cas: http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html
Vous pouvez également utiliser le module warnings pour contrôler le mode d'affichage des avertissements: http://docs.python.org/library/warnings.html
Peut-être pourriez-vous améliorer votre algorithme en vérifiant dans quels domaines vous recevez des avertissements (certaines valeurs pour X [0], X [1] seront probablement sous-jacentes) et en remplaçant le résultat par un très grand nombre. Vous devez voir comment votre fonction se comporte, vous devriez par exemple vérifier, par exemple. exp (-x) + exp (-y) + x * y
En fonction de vos besoins spécifiques, il peut être utile de rogner l'argument d'entrée en exp()
. Si vous voulez réellement obtenir une inf
si elle déborde ou si vous voulez obtenir des nombres absurdement énormes, alors d'autres réponses seront plus appropriées.
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)))
Résultat:
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
Notez que powellBadlyScaled2
n'a pas dépassé/dépassé lorsque powellBadlyScaled
d'origine l'a fait, mais la version modifiée donne 1.79769313486e+305
au lieu de inf
dans l'un des tests. J'imagine qu'il y a beaucoup d'applications où 1.79769313486e+305
est pratiquement inf
et ce serait très bien, voire préférable car 1.79769313486e+305
est un nombre réel et inf
ne l'est pas.