Overloopfout in de numpy.exp-functie van Python

Ik wil numpy.expals volgt gebruiken:

cc = np.array([
    [0.120,0.34,-1234.1]
])
print 1/(1+np.exp(-cc))

Maar dit geeft me een foutmelding:

/usr/local/lib/python2.7/site-packages/ipykernel/__main__.py:5: RuntimeWarning: overflow encountered in exp

Ik begrijp niet waarom? Hoe kan ik dit oplossen? Het lijkt erop dat het probleem zit in het derde nummer (-1234.1)


Antwoord 1, autoriteit 100%

Zoals Fuglede zegt, is het probleem hier dat np.float64een getal zo groot als exp(1234.1)niet aankan. Probeer in plaats daarvan np.float128te gebruiken:

>>> cc = np.array([[0.120,0.34,-1234.1]], dtype=np.float128)
>>> cc
array([[ 0.12,  0.34, -1234.1]], dtype=float128)
>>> 1 / (1 + np.exp(-cc))
array([[ 0.52996405,  0.58419052,  1.0893812e-536]], dtype=float128)

Houd er echter rekening mee dat er bepaalde eigenaardigheden zijn bij het gebruik van uitgebreide precisie. Het werkt mogelijk niet op Windows; je krijgt niet de volledige 128 bits precisie; en je zou de precisie kunnen verliezen wanneer het nummer door pure python gaat. U kunt hiermeer lezen over de details.

Voor de meeste praktische doeleinden kunt u 1 / (1 + <a large number>)waarschijnlijk op nul schatten. Dat wil zeggen, negeer de waarschuwing en ga verder. Numpy zorgt voor de benadering voor u (bij gebruik van np.float64):

>>> 1 / (1 + np.exp(-cc))
/usr/local/bin/ipython3:1: RuntimeWarning: overflow encountered in exp
  #!/usr/local/bin/python3.4
array([[ 0.52996405,  0.58419052,  0.        ]])

Als je de waarschuwing wilt onderdrukken, kun je scipy.special.expit, zoals voorgesteld door WarrenWeckesser in een reactie op de vraag:

>>> from scipy.special import expit
>>> expit(cc)
array([[ 0.52996405,  0.58419052,  0.        ]])

Antwoord 2, autoriteit 38%

De grootste waarde die kan worden weergegeven door een numpyfloat is 1.7976931348623157e+308, waarvan de logaritme ongeveer 709.782 is, dus er is geen manier om np.exp(1234.1)weer te geven .

In [1]: import numpy as np
In [2]: np.finfo('d').max
Out[2]: 1.7976931348623157e+308
In [3]: np.log(_)
Out[3]: 709.78271289338397
In [4]: np.exp(709)
Out[4]: 8.2184074615549724e+307
In [5]: np.exp(710)
/usr/local/bin/ipython:1: RuntimeWarning: overflow encountered in exp
  #!/usr/local/bin/python3.5
Out[5]: inf

Antwoord 3, autoriteit 9%

Een mogelijke oplossing is om de module decimalte gebruiken, waarmee je met willekeurige precisie-floats kunt werken. Hier is een voorbeeld waarbij een numpyarray van floats met een precisie van 100 cijfers wordt gebruikt:

import numpy as np
import decimal
# Precision to use
decimal.getcontext().prec = 100
# Original array
cc = np.array(
    [0.120,0.34,-1234.1]
)
# Fails
print(1/(1 + np.exp(-cc)))    
# New array with the specified precision
ccd = np.asarray([decimal.Decimal(el) for el in cc], dtype=object)
# Works!
print(1/(1 + np.exp(-ccd)))

Antwoord 4, autoriteit 6%

exp(-1234.1) is te klein voor 32-bits of 64-bits drijvende-kommagetallen. Omdat het niet kan worden weergegeven, geeft numpy de juiste waarschuwing.

Met behulp van IEEE 754 32bit floating-pointgetallen, is het kleinste positieve getal dat het kan vertegenwoordigen 2^(-149), wat ongeveer 1e-45 is.

Als u IEEE 754 64 bit floating-pointgetallen gebruikt, is het kleinste positieve getal 2^(-1074), wat ruwweg 1e-327 is.

In beide gevallen kan het geen getal vertegenwoordigen dat zo klein is als exp(-1234.1) wat ongeveer 1e-535 is.

U zou de functie expitvan scipy moeten gebruiken om de sigmoid-functie te berekenen. Dit zou je een betere precisie geven.

Voor praktische doeleinden is exp(-1234.1) een heel klein getal. Als afronden naar nul zinvol is in uw gebruiksscenario, levert numpy goedaardige resultaten op door het naar nul af te ronden.


Antwoord 5

Als je niet om precisie geeft, kun je numpy.clipgebruiken.

In float64:

cc = np.clip(cc, -709.78, 709.78)

In float32:

cc = np.clip(cc, -88.72, 88.72)

LEAVE A REPLY

Please enter your comment!
Please enter your name here

19 − nine =

Other episodes