Разобраться с переполнением в exp, используя numpy - PullRequest
21 голосов
/ 05 марта 2012

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

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

Ответы [ 5 ]

18 голосов
/ 05 марта 2012

Вы можете использовать пакет 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.

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

Между прочим, если все, что вы делаете, это минимизируете powellBadlyScaled (x, y), тогда минимум находится в x -> + inf и y -> + inf, поэтому нет нужды в цифрах.

2 голосов
/ 15 мая 2018

Попробуйте scipy's -

scipy.special.expit(x).

2 голосов
/ 16 июля 2014

Вы можете использовать numpy.seterr, чтобы контролировать поведение numpy в этих условиях: http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html

Вы также можете использовать модуль предупреждений для управления тем, как предупреждения отображаются или не отображаются: http://docs.python.org/library/warnings.html

1 голос
/ 12 января 2018

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

1 голос
/ 18 июня 2014

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

...