De la clase de aprendizaje profundo de Udacity , el softmax de y_i es simplemente el exponencial dividido por la suma del exponencial de todo el vector Y:
¿Dónde S(y_i)
está la función softmax de y_i
y e
es la exponencial y j
es el no. de columnas en el vector de entrada Y.
He intentado lo siguiente:
import numpy as np
def softmax(x):
"""Compute softmax values for each sets of scores in x."""
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()
scores = [3.0, 1.0, 0.2]
print(softmax(scores))
que devuelve:
[ 0.8360188 0.11314284 0.05083836]
Pero la solución sugerida fue:
def softmax(x):
"""Compute softmax values for each sets of scores in x."""
return np.exp(x) / np.sum(np.exp(x), axis=0)
que produce el mismo resultado que la primera implementación , aunque la primera implementación explícitamente toma la diferencia de cada columna y el máximo y luego se divide por la suma.
¿Alguien puede mostrar matemáticamente por qué? ¿Es uno correcto y el otro incorrecto?
¿La implementación es similar en términos de código y complejidad de tiempo? ¿Cuál es más eficiente?
-inf to +inf
a-inf to 0
. Supongo que estaba pensando demasiado. jajajaaaaxis = 0
en la respuesta sugerida por Udacity?Respuestas:
Ambas son correctas, pero la suya es la preferida desde el punto de vista de la estabilidad numérica.
Empiezas con
Al usar el hecho de que a ^ (b - c) = (a ^ b) / (a ^ c) tenemos
Que es lo que dice la otra respuesta. Puede reemplazar max (x) con cualquier variable y se cancelaría.
fuente
(Bueno ... mucha confusión aquí, tanto en la pregunta como en las respuestas ...)
Para empezar, las dos soluciones (es decir, la suya y la sugerida) no son equivalentes; que pasan a ser equivalente sólo para el caso especial de las matrices de puntuación 1-D. Lo habrías descubierto si hubieras probado también la matriz de puntuación en 2-D en el ejemplo proporcionado por Udacity quiz.
En cuanto a los resultados, la única diferencia real entre las dos soluciones es el
axis=0
argumento. Para ver que este es el caso, intentemos su solución (your_softmax
) y una donde la única diferencia sea elaxis
argumento:Como dije, para una matriz de puntaje 1-D, los resultados son de hecho idénticos:
Sin embargo, aquí están los resultados para la matriz de puntaje 2-D dada en el cuestionario Udacity como ejemplo de prueba:
Los resultados son diferentes: el segundo es idéntico al esperado en el cuestionario Udacity, donde todas las columnas suman 1, que no es el caso con el primer resultado (incorrecto).
Entonces, todo el alboroto era en realidad un detalle de implementación: el
axis
argumento. De acuerdo con la documentación de numpy.sum :mientras que aquí queremos sumar en fila, por lo tanto
axis=0
. Para una matriz 1-D, la suma de la (única) fila y la suma de todos los elementos resultan ser idénticos, por lo tanto, sus resultados idénticos en ese caso ...El
axis
tema de lado, su aplicación (es decir, su elección para restar el primer max) es en realidad mejor que la solución sugerida! De hecho, es la forma recomendada de implementar la función softmax: vea aquí la justificación (estabilidad numérica, también señalada por algunas otras respuestas aquí).fuente
axis
argumentos a ambosmax
ysum
. Sin embargo, la primera implementación es aún mejor ya que puede desbordarse fácilmente al tomarexp
exp
? ¿Qué más se ha modificado aquí aparte de agregar unaxis
argumento?Entonces, este es realmente un comentario a la respuesta de desertnaut, pero todavía no puedo comentarlo debido a mi reputación. Como señaló, su versión solo es correcta si su entrada consiste en una sola muestra. Si su entrada consta de varias muestras, está mal. Sin embargo, la solución de desertnaut también está mal. El problema es que una vez que toma una entrada unidimensional y luego toma una entrada bidimensional. Déjame mostrarte esto.
Tomemos un ejemplo de desertnauts:
Esta es la salida:
Puedes ver que la versión de desernauts fallaría en esta situación. (No lo haría si la entrada fuera solo unidimensional como np.array ([1, 2, 3, 6]).
Ahora usemos 3 muestras ya que esa es la razón por la que usamos una entrada bidimensional. El siguiente x2 no es el mismo que el del ejemplo de desernauts.
Esta entrada consiste en un lote con 3 muestras. Pero la muestra uno y tres son esencialmente lo mismo. ¡Ahora esperamos 3 filas de activaciones de softmax donde la primera debería ser la misma que la tercera y también la misma que nuestra activación de x1!
Espero que puedan ver que este es solo el caso con mi solución.
Además, aquí están los resultados de la implementación de TensorFlows softmax:
Y el resultado:
fuente
s = s[:, np.newaxis]
,s = s.reshape(z.shape[0],1)
también debería funcionar.Diría que si bien ambos son matemáticamente correctos, en cuanto a la implementación, el primero es mejor. Al calcular softmax, los valores intermedios pueden llegar a ser muy grandes. Dividir dos números grandes puede ser numéricamente inestable. Estas notas (de Stanford) mencionan un truco de normalización que es esencialmente lo que estás haciendo.
fuente
sklearn también ofrece implementación de softmax
fuente
Desde el punto de vista matemático, ambos lados son iguales.
Y puedes probar esto fácilmente. Vamos
m=max(x)
. Ahora su funciónsoftmax
devuelve un vector, cuya i-ésima coordenada es igual atenga en cuenta que esto funciona para cualquiera
m
, porque para todos los números (incluso complejos)e^m != 0
desde el punto de vista de la complejidad computacional, también son equivalentes y ambos se ejecutan en el
O(n)
tiempo, donden
es el tamaño de un vector.desde el punto de vista de la estabilidad numérica , se prefiere la primera solución, porque
e^x
crece muy rápido e inclusox
se desbordarán valores muy pequeños . Restar el valor máximo permite deshacerse de este desbordamiento. Para experimentar prácticamente las cosas de las que estaba hablando, intente alimentarx = np.array([1000, 5])
sus dos funciones. Uno devolverá la probabilidad correcta, el segundo se desbordará connan
su solución solo funciona para vectores (el cuestionario Udacity quiere que también lo calcule para matrices). Para arreglarlo necesitas usar
sum(axis=0)
fuente
EDITAR . A partir de la versión 1.2.0, scipy incluye softmax como una función especial:
https://scipy.github.io/devdocs/generated/scipy.special.softmax.html
Escribí una función aplicando el softmax sobre cualquier eje:
Restar el máximo, como lo describieron otros usuarios, es una buena práctica. Escribí una publicación detallada al respecto aquí .
fuente
Aquí puedes averiguar por qué lo usaron
- max
.Desde allí:
fuente
Una versión más concisa es:
fuente
Para ofrecer una solución alternativa, considere los casos en que sus argumentos son de una magnitud extremadamente grande, de modo que
exp(x)
se desbordaría (en el caso negativo) o se desbordaría (en el caso positivo). Aquí desea permanecer en el espacio logarítmico el mayor tiempo posible, exponiendo solo al final donde puede confiar en que el resultado se comportará bien.fuente
axis=0
como argumento alogsumexp
.Necesitaba algo compatible con la salida de una capa densa de Tensorflow .
La solución de @desertnaut no funciona en este caso porque tengo lotes de datos. Por lo tanto, vine con otra solución que debería funcionar en ambos casos:
Resultados:
Ref: Tensorflow softmax
fuente
Sugeriría esto:
Funcionará tanto para el estocástico como para el lote.
Para más detalles, consulte: https://medium.com/@ravish1729/analysis-of-softmax-function-ad058d6a564d
fuente
Para mantener la estabilidad numérica, se debe restar max (x). El siguiente es el código para la función softmax;
def softmax (x):
fuente
Ya respondí con mucho detalle en las respuestas anteriores.
max
se resta para evitar el desbordamiento. Estoy agregando aquí una implementación más en python3.fuente
Todos parecen publicar su solución, así que yo publicaré la mía:
Obtengo exactamente los mismos resultados que los importados de sklearn:
fuente
fuente
Basado en todas las respuestas y las notas de CS231n , permítanme resumir:
Uso:
Salida:
fuente
Me gustaría complementar un poco más de comprensión del problema. Aquí es correcto restar max de la matriz. Pero si ejecuta el código en la otra publicación, descubrirá que no le da la respuesta correcta cuando la matriz tiene dimensiones 2D o superiores.
Aquí te doy algunas sugerencias:
Siga el resultado y obtendrá la respuesta correcta haciendo la vectorización. Como está relacionado con la tarea de la universidad, no puedo publicar el código exacto aquí, pero me gustaría darle más sugerencias si no lo comprende.
fuente
El propósito de la función softmax es preservar la relación de los vectores en lugar de aplastar los puntos finales con un sigmoide a medida que los valores se saturan (es decir, tienden a +/- 1 (tanh) o de 0 a 1 (logístico)). Esto se debe a que conserva más información sobre la tasa de cambio en los puntos finales y, por lo tanto, es más aplicable a las redes neuronales con codificación de salida 1-de-N (es decir, si aplastamos los puntos finales sería más difícil diferenciar el 1 -of-N clase de salida porque no podemos decir cuál es el "más grande" o el "más pequeño" porque fueron aplastados); también hace que la producción total sume a 1, y el ganador claro estará más cerca de 1, mientras que otros números que están cerca uno del otro sumarán 1 / p, donde p es el número de neuronas de salida con valores similares.
El propósito de restar el valor máximo del vector es que cuando haces e ^ y exponentes puedes obtener un valor muy alto que recorta el flotador en el valor máximo que conduce a un empate, lo cual no es el caso en este ejemplo. Esto se convierte en un GRAN problema si resta el valor máximo para hacer un número negativo, entonces tiene un exponente negativo que reduce rápidamente los valores que alteran la relación, que es lo que ocurrió en la pregunta del póster y arrojó la respuesta incorrecta.
La respuesta proporcionada por Udacity es HORRIBLEMENTE ineficiente. Lo primero que debemos hacer es calcular e ^ y_j para todos los componentes del vector, MANTENER ESOS VALORES, luego sumarlos y dividirlos. Donde Udacity está en mal estado, calculan e ^ y_j ¡DOS VECES! Aquí está la respuesta correcta:
fuente
El objetivo era lograr resultados similares usando Numpy y Tensorflow. El único cambio de la respuesta original es el
axis
parámetro paranp.sum
api.Enfoque inicial :
axis=0
sin embargo, esto no proporciona los resultados previstos cuando las dimensiones son N.Enfoque modificado :
axis=len(e_x.shape)-1
- Suma siempre en la última dimensión. Esto proporciona resultados similares a la función softmax de tensorflow.fuente
Aquí hay una solución generalizada que utiliza numpy y comparación para la corrección con tensorflow y scipy:
Preparación de datos:
Salida:
Softmax usando tensorflow:
Salida:
Softmax usando scipy:
Salida:
Softmax usando numpy ( https://nolanbconaway.github.io/blog/2017/softmax-numpy ):
Salida:
fuente
La función softmax es una función de activación que convierte los números en probabilidades que suman uno. La función softmax genera un vector que representa las distribuciones de probabilidad de una lista de resultados. También es un elemento central utilizado en las tareas de clasificación de aprendizaje profundo.
La función Softmax se usa cuando tenemos múltiples clases.
Es útil para descubrir la clase que tiene el máximo. Probabilidad.
La función Softmax se usa idealmente en la capa de salida, donde en realidad estamos tratando de alcanzar las probabilidades para definir la clase de cada entrada.
Varía de 0 a 1.
La función Softmax convierte los logits [2.0, 1.0, 0.1] en probabilidades [0.7, 0.2, 0.1], y las probabilidades suman 1. Los logits son los puntajes brutos producidos por la última capa de una red neuronal. Antes de que tenga lugar la activación. Para comprender la función softmax, debemos mirar la salida de la capa (n-1) th.
La función softmax es, de hecho, una función arg max. Eso significa que no devuelve el valor más grande de la entrada, sino la posición de los valores más grandes.
Por ejemplo:
Antes de softmax
Después de softmax
Código:
fuente