Подтвердить что ты не робот

Сделка с переполнением в exp с использованием numpy

Используя 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

Я понимаю, что операнд не может быть сохранен в выделенном пространстве для float. Но как я могу решить эту проблему?

4b9b3361

Ответ 1

Вы можете использовать пакет bigfloat, поддерживающий операции с плавающей запятой произвольной точности.

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

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

Используете ли вы инфраструктуру оптимизации функций? Обычно они используют границы ценности (используя штрафные условия). Попробуй это. Действительно ли релевантные значения действительно экстремальны? В оптимизации это не редкость для минимизации log (f). (приблизительный лог-правдоподобие и т.д.). Вы уверены, что хотите оптимизировать это значение exp, а не log (exp (f)) == f.

Взгляните на мой ответ на этот вопрос: логит и обратные функции логита для экстремальных значений

Btw, если все, что вы делаете, сводит к минимуму powellBadlyScaled (x, y), то минимум находится в x → + inf и y → + inf, поэтому нет необходимости в численных вычислениях.

Ответ 3

Возможно, вы можете улучшить свой алгоритм, проверив, в каких областях вы получите предупреждения (это, вероятно, вызовет определенные значения для X [0], X [1]) и заменит результат на действительно большое число. Вам нужно посмотреть, как ведет себя ваша функция, я должен проверить, например. exp (-x) + exp (-y) + x * y

Ответ 4

В зависимости от ваших конкретных потребностей может оказаться полезным обрезать входной аргумент 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

Обратите внимание, что powellBadlyScaled2 не выполнял/переполнения, если оригинальный powellBadlyScaled сделал, но измененная версия дает 1.79769313486e+305 вместо inf в одном из тестов. Я полагаю, что существует множество приложений, где 1.79769313486e+305 практически inf, и это было бы хорошо или даже предпочтительнее, потому что 1.79769313486e+305 - это реальное число, а inf - нет.