>>> x = np.array([1, -10, 1000])
>>> np.exp(x) / np.exp(x).sum()
RuntimeWarning: overflow encountered in exp
RuntimeWarning: invalid value encountered in true_divide
Out[4]: array([ 0., 0., nan])
Существует 2 способа избежать числовой ошибки при вычислении softmax:
def exp_normalize(x):
b = x.max()
y = np.exp(x - b)
return y / y.sum()
>>> exp_normalize(x)
array([0., 0., 1.])
def log_softmax(x):
c = x.max()
logsumexp = np.log(np.exp(x - c).sum())
return x - c - logsumexp
Обратите внимание, что разумным выбором для обоих b, c в приведенной выше формуле является max (x). При таком выборе переполнение из-за exp невозможно. Наибольшее число, возведенное в степень после сдвига, равно 0.