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
オペランドをフロート用に割り当てられたスペースに格納できないことを理解しています。しかし、どうすれば問題を克服できますか?
Bigfloatパッケージを使用できます。任意精度の浮動小数点演算をサポートしています。
http://packages.python.org/bigfloat/
import bigfloat
bigfloat.exp(5000,bigfloat.precision(100))
# -> BigFloat.exact('2.9676283840236670689662968052896e+2171', precision=100)
関数最適化フレームワークを使用していますか?通常、それらは値の境界を実装します(ペナルティ条件を使用)。やってみて関連する値は本当に極端ですか?最適化では、log(f)を最小化することは珍しくありません。 (おおよその対数尤度など)。 log(exp(f))== fではなく、そのexp値で最適化してもよろしいですか? ?
この質問に対する私の答えを見てください: 極値のロジットおよび逆ロジット関数
ところで、powellBadlyScaled(x、y)を最小化するだけであれば、最小値はx-> + infおよびy-> + infであるため、数値は不要です。
Scipyをお試しください-
scipy.special.expit(x)
。
numpy.seterr
を使用して、この状況でのnumpyの動作を制御できます。 http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html
警告モジュールを使用して、警告の表示方法または表示方法を制御することもできます。 http://docs.python.org/library/warnings.html
警告を受け取る領域を確認して(おそらくX [0]、X [1]の特定の値を確認する)、結果を非常に大きな数値に置き換えることで、アルゴリズムを改善できます。あなたはあなたの関数がどのように振る舞うかを見る必要があります。 exp(-x)+ exp(-y)+ x * y
特定のニーズに応じて、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
元のpowellBadlyScaled
がしたときにpowellBadlyScaled2
がオーバーフロー/アンダーフローしなかったことに注意してください。ただし、修正版では、テストの1つでinf
の代わりに1.79769313486e+305
を返します。 1.79769313486e+305
が実質的にinf
であり、1.79769313486e+305
が実数でinf
がそうではないため、これで問題ない、または好まれるアプリケーションがたくさんあると思います。