Comment implémenter la fonction Softmax en Python

247

D'après la classe d'apprentissage en profondeur d'Udacity , le softmax de y_i est simplement l'exponentielle divisée par la somme des exponentielles de l'ensemble du vecteur Y:

entrez la description de l'image ici

S(y_i)est la fonction softmax de y_iet eest l'exponentielle et jest le non. de colonnes dans le vecteur d'entrée Y.

J'ai essayé ce qui suit:

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

qui renvoie:

[ 0.8360188   0.11314284  0.05083836]

Mais la solution suggérée était:

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    return np.exp(x) / np.sum(np.exp(x), axis=0)

ce qui produit la même sortie que la première implémentation , même si la première implémentation prend explicitement la différence de chaque colonne et le max puis divise par la somme.

Quelqu'un peut-il montrer mathématiquement pourquoi? L'un est-il correct et l'autre faux?

L'implémentation est-elle similaire en termes de code et de complexité temporelle? Quel est le plus efficace?

alvas
la source
6
Je suis curieux de savoir pourquoi vous avez tenté de l'implémenter de cette manière avec une fonction max. Qu'est-ce qui vous a fait penser de cette façon?
BBischof
1
Je ne sais pas, je pensais que traiter le maximum à 0 et un peu comme déplacer le graphique vers la gauche et couper à 0 aide. Ensuite, ma gamme se raccourcit de -inf to +infà -inf to 0. Je suppose que je pensais trop. hahahaaa
alvas
1
J'ai encore une sous-question qui ne semble pas avoir de réponse ci-dessous. Quelle est la signification de axis = 0la réponse suggérée par Udacity?
Parva Thakkar
3
si vous jetez un oeil à la documentation numpy, il explique ce que fait somme (x, axe = 0) - et de même axe = 1 -. En bref, il fournit la direction dans laquelle additionner un tableau de tableaux. Dans ce cas, il lui dit de faire la somme le long des vecteurs. Dans ce cas, cela correspond aux dénominateurs de la fonction softmax.
BBischof
3
C'est comme toutes les deux semaines, il y a une réponse plus correcte jusqu'à ce que mes calculs ne soient pas assez bons pour décider qui a raison =) Tout expert en mathématiques qui n'a pas fourni de réponse peut aider à décider lequel est correct?
alvas

Réponses:

137

Ils sont tous les deux corrects, mais le vôtre est préféré du point de vue de la stabilité numérique.

Vous commencez avec

e ^ (x - max(x)) / sum(e^(x - max(x))

En utilisant le fait que a ^ (b - c) = (a ^ b) / (a ​​^ c) nous avons

= e ^ x / (e ^ max(x) * sum(e ^ x / e ^ max(x)))

= e ^ x / sum(e ^ x)

C'est ce que dit l'autre réponse. Vous pourriez remplacer max (x) par n'importe quelle variable et cela annulerait.

Trevor Merrifield
la source
4
Reformater votre réponse @TrevorM pour plus de précisions: e ^ (x - max (x)) / sum (e ^ (x - max (x)) en utilisant a ^ (b - c) = (a ^ b) / (a ​​^ c) nous avons, = e ^ x / {e ^ max (x) * sum (e ^ x / e ^ max (x))} = e ^ x / sum (e ^ x)
shanky_thebearer
5
@Trevor Merrifield, je ne pense pas que la première approche ait obtenu un "terme inutile". En fait, c'est mieux que la deuxième approche. J'ai ajouté ce point comme réponse distincte.
Shagun Sodhani
6
@Shagun Vous avez raison. Les deux sont mathématiquement équivalents mais je n'avais pas considéré la stabilité numérique.
Trevor Merrifield, le
J'espère que cela ne vous dérange pas: j'ai supprimé "terme inutile" au cas où les gens ne liraient pas les commentaires (ou les commentaires disparaissent). Cette page reçoit un peu de trafic des moteurs de recherche et c'est actuellement la première réponse que les gens voient.
Alex Riley
Je me demande pourquoi vous soustrayez max (x) et non max (abs (x)) (fixez le signe après avoir déterminé la valeur). Si toutes vos valeurs sont inférieures à zéro et très grandes dans leur valeur absolue, et que seule la valeur (le maximum) est proche de zéro, la soustraction du maximum ne changera rien. Ne serait-il pas encore numériquement instable?
Cerno
103

(Eh bien ... beaucoup de confusion ici, à la fois dans la question et dans les réponses ...)

Pour commencer, les deux solutions (c'est-à-dire la vôtre et celle suggérée) ne sont pas équivalentes; ils arrivent être équivalents uniquement pour le cas spécial des tableaux de scores 1-D. Vous l'auriez découvert si vous aviez essayé également le tableau de score 2D dans l'exemple de test d'Udacity.

En termes de résultats, la seule différence réelle entre les deux solutions est l' axis=0argument. Pour voir que c'est le cas, essayons votre solution ( your_softmax) et celle où la seule différence est l' axisargument:

import numpy as np

# your solution:
def your_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()

# correct solution:
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(axis=0) # only difference

Comme je l'ai dit, pour un tableau de scores 1D, les résultats sont en effet identiques:

scores = [3.0, 1.0, 0.2]
print(your_softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
print(softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
your_softmax(scores) == softmax(scores)
# array([ True,  True,  True], dtype=bool)

Néanmoins, voici les résultats du tableau de score 2D donnés dans le quiz Udacity comme exemple de test:

scores2D = np.array([[1, 2, 3, 6],
                     [2, 4, 5, 6],
                     [3, 8, 7, 6]])

print(your_softmax(scores2D))
# [[  4.89907947e-04   1.33170787e-03   3.61995731e-03   7.27087861e-02]
#  [  1.33170787e-03   9.84006416e-03   2.67480676e-02   7.27087861e-02]
#  [  3.61995731e-03   5.37249300e-01   1.97642972e-01   7.27087861e-02]]

print(softmax(scores2D))
# [[ 0.09003057  0.00242826  0.01587624  0.33333333]
#  [ 0.24472847  0.01794253  0.11731043  0.33333333]
#  [ 0.66524096  0.97962921  0.86681333  0.33333333]]

Les résultats sont différents - le second est en effet identique à celui attendu dans le quiz Udacity, où toutes les colonnes totalisent en effet 1, ce qui n'est pas le cas avec le premier (mauvais) résultat.

Donc, tout le tapage était en fait pour un détail de mise en œuvre - l' axisargument. Selon la documentation numpy.sum :

La valeur par défaut, axis = None, additionnera tous les éléments du tableau d'entrée

alors qu'ici nous voulons faire la somme des lignes, donc axis=0. Pour un tableau 1-D, la somme de la (seule) ligne et la somme de tous les éléments se trouvent être identiques, d'où vos résultats identiques dans ce cas ...

Le axisproblème mis à part, votre implémentation (c'est-à-dire votre choix de soustraire le maximum en premier) est en fait meilleure que la solution suggérée! En fait, c'est la façon recommandée d'implémenter la fonction softmax - voir ici pour la justification (stabilité numérique, également soulignée par d'autres réponses ici).

desertnaut
la source
Eh bien, si vous parlez simplement d'un tableau multidimensionnel. La première solution peut être facilement corrigée en ajoutant un axisargument aux deux maxet sum. Cependant, la première implémentation est encore meilleure car vous pouvez facilement déborder lors de la priseexp
Louis Yang
@LouisYang je ne suis pas en train de suivre; quelle est la "première" solution? Lequel ne pas utiliser exp? Quoi de plus a été modifié ici que l'ajout d'un axisargument?
desertnaut
La première solution fait référence à la solution de @alvas. La différence est que la solution suggérée dans la question d'Alvas manque la partie de soustraire le max. Cela peut facilement provoquer un débordement par exemple, exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) sont les mêmes en mathématiques mais les le premier débordera.
Louis Yang
@LouisYang toujours, je ne suis pas sûr de comprendre la nécessité de votre commentaire - tout cela a déjà été explicitement abordé dans la réponse.
desertnaut
@LouisYang s'il vous plaît ne laissez pas la popularité (ultérieure) du fil vous tromper et essayez d'imaginer le contexte dans lequel votre propre réponse a été proposée: un OP perplexe ("les deux donnent le même résultat "), et une réponse (toujours!) Acceptée affirmant que "les deux sont corrects " (enfin, ils ne le sont pas ). La réponse n'a jamais été censée être " c'est la façon la plus correcte et la plus efficace de calculer le softmax en général "; il s'agissait simplement de justifier pourquoi , dans le quiz Udacity spécifique discuté, les 2 solutions ne sont pas équivalentes.
desertnaut
56

Donc, c'est vraiment un commentaire à la réponse de desertnaut mais je ne peux pas encore le commenter en raison de ma réputation. Comme il l'a souligné, votre version n'est correcte que si votre entrée consiste en un seul échantillon. Si votre entrée se compose de plusieurs échantillons, c'est faux. Cependant, la solution de desertnaut est également fausse. Le problème est qu'une fois qu'il prend une entrée unidimensionnelle, puis il prend une entrée bidimensionnelle. Permettez-moi de vous le montrer.

import numpy as np

# your solution:
def your_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()

# desertnaut solution (copied from his answer): 
def desertnaut_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(axis=0) # only difference

# my (correct) solution:
def softmax(z):
    assert len(z.shape) == 2
    s = np.max(z, axis=1)
    s = s[:, np.newaxis] # necessary step to do broadcasting
    e_x = np.exp(z - s)
    div = np.sum(e_x, axis=1)
    div = div[:, np.newaxis] # dito
    return e_x / div

Prenons l'exemple des déserteurs:

x1 = np.array([[1, 2, 3, 6]]) # notice that we put the data into 2 dimensions(!)

Voici la sortie:

your_softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

desertnaut_softmax(x1)
array([[ 1.,  1.,  1.,  1.]])

softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

Vous pouvez voir que la version desernauts échouerait dans cette situation. (Ce ne serait pas le cas si l'entrée n'était qu'une dimension comme np.array ([1, 2, 3, 6]).

Permet maintenant d'utiliser 3 échantillons car c'est la raison pour laquelle nous utilisons une entrée bidimensionnelle. Le x2 suivant n'est pas le même que celui de l'exemple desernauts.

x2 = np.array([[1, 2, 3, 6],  # sample 1
               [2, 4, 5, 6],  # sample 2
               [1, 2, 3, 6]]) # sample 1 again(!)

Cette entrée consiste en un lot de 3 échantillons. Mais les échantillons un et trois sont essentiellement les mêmes. Nous attendons maintenant 3 rangées d'activations softmax où la première devrait être la même que la troisième et aussi la même que notre activation de x1!

your_softmax(x2)
array([[ 0.00183535,  0.00498899,  0.01356148,  0.27238963],
       [ 0.00498899,  0.03686393,  0.10020655,  0.27238963],
       [ 0.00183535,  0.00498899,  0.01356148,  0.27238963]])


desertnaut_softmax(x2)
array([[ 0.21194156,  0.10650698,  0.10650698,  0.33333333],
       [ 0.57611688,  0.78698604,  0.78698604,  0.33333333],
       [ 0.21194156,  0.10650698,  0.10650698,  0.33333333]])

softmax(x2)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047],
       [ 0.01203764,  0.08894682,  0.24178252,  0.65723302],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

J'espère que vous pouvez voir que ce n'est que le cas avec ma solution.

softmax(x1) == softmax(x2)[0]
array([[ True,  True,  True,  True]], dtype=bool)

softmax(x1) == softmax(x2)[2]
array([[ True,  True,  True,  True]], dtype=bool)

En outre, voici les résultats de la mise en œuvre de softmax TensorFlows:

import tensorflow as tf
import numpy as np
batch = np.asarray([[1,2,3,6],[2,4,5,6],[1,2,3,6]])
x = tf.placeholder(tf.float32, shape=[None, 4])
y = tf.nn.softmax(x)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(y, feed_dict={x: batch})

Et le résultat:

array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037045],
       [ 0.01203764,  0.08894681,  0.24178252,  0.657233  ],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037045]], dtype=float32)
ChuckFive
la source
6
Cela aurait été un sacré commentaire ;-)
Michael Benjamin
27
np.exp (z) / np.sum (np.exp (z), axis = 1, keepdims = True) atteint le même résultat que votre fonction softmax. les étapes avec s ne sont pas nécessaires.
PabTorre
Au lieu de` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)devrait également fonctionner.
Debashish
2
autant de solutions incorrectes / inefficaces sur cette page. Faites-vous plaisir et utilisez PabTorre
Miss Palmer
@PabTorre vouliez-vous dire axe = -1? axe = 1 ne fonctionnera pas pour une entrée unidimensionnelle
DiehardTheTryhard
36

Je dirais que si les deux sont corrects mathématiquement, en ce qui concerne la mise en œuvre, le premier est meilleur. Lors du calcul de softmax, les valeurs intermédiaires peuvent devenir très grandes. La division de deux grands nombres peut être numériquement instable. Ces notes (de Stanford) mentionnent une astuce de normalisation qui est essentiellement ce que vous faites.

Shagun Sodhani
la source
3
Les effets d'une annulation catastrophique ne peuvent pas être sous-estimés.
Cesar
24

sklearn propose également la mise en œuvre de softmax

from sklearn.utils.extmath import softmax
import numpy as np

x = np.array([[ 0.50839931,  0.49767588,  0.51260159]])
softmax(x)

# output
array([[ 0.3340521 ,  0.33048906,  0.33545884]]) 
Orac romain
la source
3
Comment cela répond-il exactement à la question spécifique, qui concerne l' implémentation elle-même et non la disponibilité dans une bibliothèque tierce?
desertnaut
8
Je cherchais une implémentation tierce pour vérifier les résultats des deux approches. C'est ainsi que ce commentaire aide.
Eugenio F.Martinez Pacheco
13

D'un point de vue mathématique, les deux côtés sont égaux.

Et vous pouvez facilement le prouver. Allons m=max(x). Maintenant, votre fonction softmaxretourne un vecteur dont la i-ème coordonnée est égale à

entrez la description de l'image ici

notez que cela fonctionne pour tout m , car pour tous les nombres (même complexes)e^m != 0

  • du point de vue de la complexité de calcul, ils sont également équivalents et fonctionnent tous les deux dans O(n) temps, où nest la taille d'un vecteur.

  • du point de vue de la stabilité numérique , la première solution est préférée, car elle se e^xdéveloppe très rapidement et même pour de très petites valeurs, xelle débordera. La soustraction de la valeur maximale permet de se débarrasser de ce débordement. Pour expérimenter pratiquement ce dont je parlais, essayez d'alimenter x = np.array([1000, 5])vos deux fonctions. L'un retournera une probabilité correcte, le second débordera denan

  • votre solution ne fonctionne que pour les vecteurs (le quiz Udacity veut que vous le calculiez également pour les matrices). Pour le réparer, vous devez utilisersum(axis=0)

Salvador Dali
la source
1
Quand est-il utile de pouvoir calculer softmax sur matrice plutôt que sur vecteur? c'est à dire quels modèles de matrice de sortie? Peut-il être encore plus dimensionnel?
mrgloom
2
voulez-vous dire la première solution dans "du point de vue de la stabilité numérique, la deuxième solution est préférée ..."?
Dataman
10

MODIFIER . Depuis la version 1.2.0, scipy inclut softmax comme fonction spéciale:

https://scipy.github.io/devdocs/generated/scipy.special.softmax.html

J'ai écrit une fonction appliquant le softmax sur n'importe quel axe:

def softmax(X, theta = 1.0, axis = None):
    """
    Compute the softmax of each element along an axis of X.

    Parameters
    ----------
    X: ND-Array. Probably should be floats. 
    theta (optional): float parameter, used as a multiplier
        prior to exponentiation. Default = 1.0
    axis (optional): axis to compute values along. Default is the 
        first non-singleton axis.

    Returns an array the same size as X. The result will sum to 1
    along the specified axis.
    """

    # make X at least 2d
    y = np.atleast_2d(X)

    # find axis
    if axis is None:
        axis = next(j[0] for j in enumerate(y.shape) if j[1] > 1)

    # multiply y against the theta parameter, 
    y = y * float(theta)

    # subtract the max for numerical stability
    y = y - np.expand_dims(np.max(y, axis = axis), axis)

    # exponentiate y
    y = np.exp(y)

    # take the sum along the specified axis
    ax_sum = np.expand_dims(np.sum(y, axis = axis), axis)

    # finally: divide elementwise
    p = y / ax_sum

    # flatten if X was 1D
    if len(X.shape) == 1: p = p.flatten()

    return p

La soustraction du maximum, comme d'autres utilisateurs l'ont décrit, est une bonne pratique. J'ai écrit un article détaillé à ce sujet ici .

Nolan Conaway
la source
9

Ici, vous pouvez découvrir pourquoi ils ont utilisé - max.

De là:

"Lorsque vous écrivez du code pour calculer la fonction Softmax dans la pratique, les termes intermédiaires peuvent être très importants en raison des exponentielles. La division de grands nombres peut être numériquement instable, il est donc important d'utiliser une astuce de normalisation."

Sadegh Salehi
la source
4

Une version plus concise est:

def softmax(x):
    return np.exp(x) / np.exp(x).sum(axis=0)
Pimin Konstantin Kefaloukos
la source
9
cela peut entraîner un débordement arithmétique
minhle_r7
4

Pour proposer une solution alternative, considérez les cas où vos arguments sont d'une ampleur extrêmement grande, tels que des exp(x)débordements (dans le cas négatif) ou des débordements (dans le cas positif). Ici, vous souhaitez rester dans l'espace journal le plus longtemps possible, en exponentiant uniquement à la fin où vous pouvez avoir confiance que le résultat se comportera bien.

import scipy.special as sc
import numpy as np

def softmax(x: np.ndarray) -> np.ndarray:
    return np.exp(x - sc.logsumexp(x))
PikalaxALT
la source
Pour le rendre égal au code des affiches, vous devez ajouter axis=0comme argument à logsumexp.
Björn Lindqvist
Alternativement, on pourrait décompresser des arguments supplémentaires pour passer à logsumexp.
PikalaxALT
3

J'avais besoin de quelque chose de compatible avec la sortie d'une couche dense de Tensorflow .

La solution de @desertnaut ne fonctionne pas dans ce cas car j'ai des lots de données. Par conséquent, je suis venu avec une autre solution qui devrait fonctionner dans les deux cas:

def softmax(x, axis=-1):
    e_x = np.exp(x - np.max(x)) # same code
    return e_x / e_x.sum(axis=axis, keepdims=True)

Résultats:

logits = np.asarray([
    [-0.0052024,  -0.00770216,  0.01360943, -0.008921], # 1
    [-0.0052024,  -0.00770216,  0.01360943, -0.008921]  # 2
])

print(softmax(logits))

#[[0.2492037  0.24858153 0.25393605 0.24827873]
# [0.2492037  0.24858153 0.25393605 0.24827873]]

Réf: Tensorflow softmax

Lucas Casagrande
la source
N'oubliez pas que la réponse fait référence à un cadre très spécifique décrit dans la question; cela n'a jamais été destiné à être «comment calculer le softmax en général en toutes circonstances, ou dans le format de données de votre
choix
Je vois, je l'ai mis ici parce que la question fait référence à "la classe d'apprentissage en profondeur d'Udacity" et cela ne fonctionnerait pas si vous utilisez Tensorflow pour construire votre modèle. Votre solution est cool et propre mais elle ne fonctionne que dans un scénario très spécifique. Merci quand même.
Lucas Casagrande
1

Afin de maintenir la stabilité numérique, max (x) doit être soustrait. Voici le code de la fonction softmax;

def softmax (x):

if len(x.shape) > 1:
    tmp = np.max(x, axis = 1)
    x -= tmp.reshape((x.shape[0], 1))
    x = np.exp(x)
    tmp = np.sum(x, axis = 1)
    x /= tmp.reshape((x.shape[0], 1))
else:
    tmp = np.max(x)
    x -= tmp
    x = np.exp(x)
    tmp = np.sum(x)
    x /= tmp


return x
Rahul Ahuja
la source
1

Déjà répondu en détail dans les réponses ci-dessus. maxest soustrait pour éviter le débordement. J'ajoute ici une autre implémentation en python3.

import numpy as np
def softmax(x):
    mx = np.amax(x,axis=1,keepdims = True)
    x_exp = np.exp(x - mx)
    x_sum = np.sum(x_exp, axis = 1, keepdims = True)
    res = x_exp / x_sum
    return res

x = np.array([[3,2,4],[4,5,6]])
print(softmax(x))
Debashish
la source
1

Tout le monde semble poster sa solution donc je vais poster la mienne:

def softmax(x):
    e_x = np.exp(x.T - np.max(x, axis = -1))
    return (e_x / e_x.sum(axis=0)).T

J'obtiens exactement les mêmes résultats que ceux importés de sklearn:

from sklearn.utils.extmath import softmax
julien
la source
1
import tensorflow as tf
import numpy as np

def softmax(x):
    return (np.exp(x).T / np.exp(x).sum(axis=-1)).T

logits = np.array([[1, 2, 3], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])

sess = tf.Session()
print(softmax(logits))
print(sess.run(tf.nn.softmax(logits)))
sess.close()
Roi
la source
Bienvenue chez SO. Une explication de la façon dont votre code répond à la question est toujours utile.
Nick
1

Sur la base de toutes les réponses et des notes du CS231n , permettez-moi de résumer:

def softmax(x, axis):
    x -= np.max(x, axis=axis, keepdims=True)
    return np.exp(x) / np.exp(x).sum(axis=axis, keepdims=True)

Usage:

x = np.array([[1, 0, 2,-1],
              [2, 4, 6, 8], 
              [3, 2, 1, 0]])
softmax(x, axis=1).round(2)

Production:

array([[0.24, 0.09, 0.64, 0.03],
       [0.  , 0.02, 0.12, 0.86],
       [0.64, 0.24, 0.09, 0.03]])
remykarem
la source
0

Je voudrais compléter un peu plus la compréhension du problème. Ici, il est correct de soustraire max du tableau. Mais si vous exécutez le code dans l'autre article, vous constaterez qu'il ne vous donne pas la bonne réponse lorsque le tableau est de dimensions 2D ou supérieures.

Ici, je vous donne quelques suggestions:

  1. Pour obtenir le maximum, essayez de le faire le long de l'axe des x, vous obtiendrez un tableau 1D.
  2. Remodelez votre tableau max à sa forme d'origine.
  3. Np.exp obtient-il une valeur exponentielle.
  4. Faites une somme np le long de l'axe.
  5. Obtenez les résultats finaux.

Suivez le résultat, vous obtiendrez la bonne réponse en faisant de la vectorisation. Puisqu'il est lié aux devoirs du collège, je ne peux pas poster le code exact ici, mais je voudrais donner plus de suggestions si vous ne comprenez pas.

Hao Xu
la source
1
Ce n'est pas lié à des devoirs d'université, seulement à un quiz de pratique non évalué dans un cours non accrédité, où la bonne réponse est fournie à l'étape suivante ...
desertnaut
0

Le but de la fonction softmax est de préserver le rapport des vecteurs par opposition à écraser les points finaux avec un sigmoïde car les valeurs saturent (c'est-à-dire ont tendance à +/- 1 (tanh) ou de 0 à 1 (logistique)). En effet, il conserve plus d'informations sur le taux de changement aux points d'extrémité et est donc plus applicable aux réseaux neuronaux avec codage de sortie 1 sur N (c'est-à-dire que si nous écrasons les points d'extrémité, il serait plus difficile de différencier le 1 -of-N classe de sortie parce que nous ne pouvons pas dire laquelle est la "plus grande" ou "la plus petite" parce qu'elles ont été écrasées.); il fait également la somme totale de sortie à 1, et le gagnant clair sera plus proche de 1 tandis que d'autres nombres qui sont proches les uns des autres seront totalisés à 1 / p, où p est le nombre de neurones de sortie avec des valeurs similaires.

Le but de soustraire la valeur maximale du vecteur est que lorsque vous faites des exposants e ^ y, vous pouvez obtenir une valeur très élevée qui coupe le flotteur à la valeur maximale conduisant à une égalité, ce qui n'est pas le cas dans cet exemple. Cela devient un GRAND problème si vous soustrayez la valeur maximale pour obtenir un nombre négatif, puis vous avez un exposant négatif qui réduit rapidement les valeurs modifiant le rapport, ce qui s'est produit dans la question de l'affiche et a donné la réponse incorrecte.

La réponse fournie par Udacity est HORRIBLEMENT inefficace. La première chose que nous devons faire est de calculer e ^ y_j pour toutes les composantes vectorielles, CONSERVER CES VALEURS, puis les additionner et diviser. Où Udacity a gâché, ils calculent e ^ y_j DEUX FOIS !!! Voici la bonne réponse:

def softmax(y):
    e_to_the_y_j = np.exp(y)
    return e_to_the_y_j / np.sum(e_to_the_y_j, axis=0)

la source
0

L'objectif était d'obtenir des résultats similaires en utilisant Numpy et Tensorflow. Le seul changement par rapport à la réponse d'origine est le axisparamètre pour l' np.sumapi.

Approche initiale : axis=0- Cela ne donne cependant pas les résultats escomptés lorsque les dimensions sont N.

Approche modifiée : axis=len(e_x.shape)-1- Somme toujours sur la dernière dimension. Cela donne des résultats similaires à la fonction softmax de tensorflow.

def softmax_fn(input_array):
    """
    | **@author**: Prathyush SP
    |
    | Calculate Softmax for a given array
    :param input_array: Input Array
    :return: Softmax Score
    """
    e_x = np.exp(input_array - np.max(input_array))
    return e_x / e_x.sum(axis=len(e_x.shape)-1)
Kingspp
la source
0

Voici une solution généralisée utilisant numpy et la comparaison pour l'exactitude avec tensorflow et scipy:

Préparation des données:

import numpy as np

np.random.seed(2019)

batch_size = 1
n_items = 3
n_classes = 2
logits_np = np.random.rand(batch_size,n_items,n_classes).astype(np.float32)
print('logits_np.shape', logits_np.shape)
print('logits_np:')
print(logits_np)

Production:

logits_np.shape (1, 3, 2)
logits_np:
[[[0.9034822  0.3930805 ]
  [0.62397    0.6378774 ]
  [0.88049906 0.299172  ]]]

Softmax utilisant tensorflow:

import tensorflow as tf

logits_tf = tf.convert_to_tensor(logits_np, np.float32)
scores_tf = tf.nn.softmax(logits_np, axis=-1)

print('logits_tf.shape', logits_tf.shape)
print('scores_tf.shape', scores_tf.shape)

with tf.Session() as sess:
    scores_np = sess.run(scores_tf)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np,axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Production:

logits_tf.shape (1, 3, 2)
scores_tf.shape (1, 3, 2)
scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.4965232  0.5034768 ]
  [0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

Softmax utilisant scipy:

from scipy.special import softmax

scores_np = softmax(logits_np, axis=-1)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Production:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.4965232  0.5034768 ]
  [0.6413727  0.35862732]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

Softmax utilisant numpy ( https://nolanbconaway.github.io/blog/2017/softmax-numpy ):

def softmax(X, theta = 1.0, axis = None):
    """
    Compute the softmax of each element along an axis of X.

    Parameters
    ----------
    X: ND-Array. Probably should be floats.
    theta (optional): float parameter, used as a multiplier
        prior to exponentiation. Default = 1.0
    axis (optional): axis to compute values along. Default is the
        first non-singleton axis.

    Returns an array the same size as X. The result will sum to 1
    along the specified axis.
    """

    # make X at least 2d
    y = np.atleast_2d(X)

    # find axis
    if axis is None:
        axis = next(j[0] for j in enumerate(y.shape) if j[1] > 1)

    # multiply y against the theta parameter,
    y = y * float(theta)

    # subtract the max for numerical stability
    y = y - np.expand_dims(np.max(y, axis = axis), axis)

    # exponentiate y
    y = np.exp(y)

    # take the sum along the specified axis
    ax_sum = np.expand_dims(np.sum(y, axis = axis), axis)

    # finally: divide elementwise
    p = y / ax_sum

    # flatten if X was 1D
    if len(X.shape) == 1: p = p.flatten()

    return p


scores_np = softmax(logits_np, axis=-1)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Production:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.49652317 0.5034768 ]
  [0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]
mrgloom
la source
0

La fonction softmax est une fonction d'activation qui transforme les nombres en probabilités qui se résument à un. La fonction softmax génère un vecteur qui représente les distributions de probabilité d'une liste de résultats. C'est également un élément central utilisé dans les tâches de classification de l'apprentissage en profondeur.

La fonction Softmax est utilisée lorsque nous avons plusieurs classes.

Il est utile pour trouver la classe qui a le max. Probabilité.

La fonction Softmax est idéalement utilisée dans la couche de sortie, où nous essayons en fait d'atteindre les probabilités de définir la classe de chaque entrée.

Il va de 0 à 1.

La fonction Softmax transforme les logits [2.0, 1.0, 0.1] en probabilités [0.7, 0.2, 0.1] et la somme des probabilités à 1. Les logits sont les scores bruts émis par la dernière couche d'un réseau neuronal. Avant l'activation. Pour comprendre la fonction softmax, nous devons regarder la sortie de la (n-1) ème couche.

La fonction softmax est, en fait, une fonction arg max. Cela signifie qu'il ne renvoie pas la plus grande valeur de l'entrée, mais la position des plus grandes valeurs.

Par exemple:

Avant softmax

X = [13, 31, 5]

Après softmax

array([1.52299795e-08, 9.99999985e-01, 5.10908895e-12]

Code:

import numpy as np

# your solution:

def your_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() 

# correct solution: 

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(axis=0) 

# only difference
krishna veer
la source