Implementación de una función de activación softmax para redes neuronales

Estoy usando una Softmax función de activación en la última capa de una red neuronal. Pero tengo problemas con una implementación segura de esta función.

Una implementación ingenua sería esta:

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();

Esto no funciona muy bien para> 100 nodos ocultos porque la y seráNaN en muchos casos (si y (f)> 709, exp (y (f)) devolverá inf). Se me ocurrió esta versión:

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();

dóndesafeExp Se define com

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);
}

Esta función limita la entrada de exp. En la mayoría de los casos esto funciona, pero no en todos los casos, y realmente no pude averiguar en qué casos no funciona. Cuando tengo 800 neuronas ocultas en la capa anterior, no funciona en absoluto.

Sin embargo, incluso si esto funcionó, de alguna manera "distorsioné" el resultado de la ANN. ¿Se te ocurre alguna otra forma de calcular la solución correcta? ¿Hay alguna biblioteca o truco de C ++ que pueda usar para calcular el resultado exacto de este ANN?

editar La solución provista por Itamar Katz es:

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();

Y realmente es matemáticamente igual. Sin embargo, en la práctica, algunos valores pequeños se convierten en 0 debido a la precisión de coma flotante. Me pregunto por qué nadie escribe estos detalles de implementación en los libros de texto.

Respuestas a la pregunta(4)

Su respuesta a la pregunta