in scipy.special.expit
, logistic function is implemented like the following:
if x < 0
a = exp(x)
a / (1 + a)
else
1 / (1 + exp(-x))
However, I have seen implementations in other languages/frameworks that simply do
1 / (1 + exp(-x))
I am wondering how much benefit the scipy version actually brings.
For very small x
, the result approaches to 0. It works even if exp(-x)
overflows to Inf
.
It's really just for stability - putting in values that are very large in magnitude might return unexpected results otherwise.
If
expit
was implemented just as1 / (1 + exp(-x))
then putting a value of-710
into the function would returnnan
, whereas-709
would give a value close to zero as expected. This is becauseexp(710)
is too big to be a double.The branching in the code just means that this scenario is avoided.
See also this question and answer on Stack Overflow.
Another way to do it would be
python np.where(x > 0, 1. / (1. + np.exp(-x)), np.exp(x) / (np.exp(x) + np.exp(0)))
Since
np.exp(x) / (np.exp(x) + np.exp(0))
is equivalent to1. / (1. + np.exp(-x))
but more stable for negative valuesSeems it would be more efficient to use:
unless you need number with 10^-309 precision (see below) which seems overkill!