Я использую функцию активации Softmax в последнем слое нейронной сети. Но у меня есть проблемы с безопасной реализацией этой функции.
Наивная реализация будет такой:
Vector y = mlp(x); // output of the neural network without softmax activation function
for(int f = 0; f < y.rows(); f++)
y(f) = exp(y(f));
y /= y.sum();
Это не очень хорошо работает для> 100 скрытых узлов, потому что y во многих случаях будет NaN
(если y (f)> 709, exp (y (f)) вернет inf). Я придумал эту версию:
Vector y = mlp(x); // output of the neural network without softmax activation function
for(int f = 0; f < y.rows(); f++)
y(f) = safeExp(y(f), y.rows());
y /= y.sum();
, где safeExp
определяется как
double safeExp(double x, int div)
{
static const double maxX = std::log(std::numeric_limits<double>::max());
const double max = maxX / (double) div;
if(x > max)
x = max;
return std::exp(x);
}
Эта функция ограничивает ввод эксп. В большинстве случаев это работает, но не во всех случаях, и мне не удалось выяснить, в каких случаях это не работает. Когда у меня есть 800 скрытых нейронов в предыдущем слое, он вообще не работает.
Однако, даже если это сработало, я каким-то образом "исказил" результат ANN. Можете ли вы придумать какой-нибудь другой способ рассчитать правильное решение? Существуют ли какие-либо библиотеки или приемы C ++, которые я могу использовать для вычисления точного результата этого ANN?
edit: Решение, предоставленное Itamar Katz:
Vector y = mlp(x); // output of the neural network without softmax activation function
double ymax = maximal component of y
for(int f = 0; f < y.rows(); f++)
y(f) = exp(y(f) - ymax);
y /= y.sum();
И это действительно математически то же самое. Однако на практике некоторые небольшие значения становятся 0 из-за точности с плавающей запятой. Интересно, почему никто никогда не записывает эти детали реализации в учебники.