So implementieren Sie die Softmax-Funktion in Python

245

Aus der Deep-Learning-Klasse der Udacity ist der Softmax von y_i einfach das Exponential geteilt durch die Summe der Exponentiale des gesamten Y-Vektors:

Geben Sie hier die Bildbeschreibung ein

Wo S(y_i)ist die Softmax-Funktion von y_iund eist die Exponentialfunktion und jist die Nr. von Spalten im Eingabevektor Y.

Ich habe folgendes versucht:

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

was zurückgibt:

[ 0.8360188   0.11314284  0.05083836]

Die vorgeschlagene Lösung war jedoch:

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

Dies erzeugt die gleiche Ausgabe wie die erste Implementierung , obwohl die erste Implementierung explizit die Differenz jeder Spalte und das Maximum verwendet und dann durch die Summe dividiert.

Kann jemand mathematisch zeigen warum? Ist einer richtig und der andere falsch?

Ist die Implementierung in Bezug auf Code und Zeitkomplexität ähnlich? Welches ist effizienter?

Alvas
quelle
6
Ich bin gespannt, warum Sie versucht haben, es auf diese Weise mit einer Max-Funktion zu implementieren. Warum hast du so darüber nachgedacht?
BBischof
1
Ich weiß nicht, ich dachte, das Maximum als 0 zu behandeln und das Diagramm nach links zu verschieben und bei 0 zu schneiden, hilft. Dann verkürzt sich meine Reichweite von -inf to +infbis -inf to 0. Ich glaube, ich habe überlegt. hahahaaa
alvas
1
Ich habe noch eine Unterfrage, die unten nicht beantwortet zu sein scheint. Welche Bedeutung hat axis = 0die vorgeschlagene Antwort von Udacity?
Parva Thakkar
3
Wenn Sie sich die Numpy-Dokumentation ansehen, wird erläutert, was die Summe (x, Achse = 0) - und in ähnlicher Weise Achse = 1 - bewirkt. Kurz gesagt, es gibt die Richtung an, in der ein Array von Arrays summiert werden soll. In diesem Fall wird angegeben, dass entlang der Vektoren summiert werden soll. In diesem Fall entspricht dies den Nennern in der Softmax-Funktion.
BBischof
3
Es ist wie in jeder zweiten Woche, es gibt eine korrektere Antwort bis zu dem Punkt, an dem meine Mathematik nicht gut genug ist, um zu entscheiden, wer richtig ist =) Jeder Mathematiker, der keine Antwort gegeben hat, kann helfen, zu entscheiden, welche richtig ist?
Alvas

Antworten:

137

Sie sind beide korrekt, aber Ihre wird unter dem Gesichtspunkt der numerischen Stabilität bevorzugt.

Sie beginnen mit

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

Indem wir die Tatsache verwenden, dass a ^ (b - c) = (a ^ b) / (a ​​^ c) ist, haben wir

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

= e ^ x / sum(e ^ x)

Welches ist, was die andere Antwort sagt. Sie könnten max (x) durch eine beliebige Variable ersetzen und es würde sich aufheben.

Trevor Merrifield
quelle
4
Formatieren Sie Ihre Antwort @TrevorM zur weiteren Verdeutlichung neu: e ^ (x - max (x)) / Summe (e ^ (x - max (x)) mit a ^ (b - c) = (a ^ b) / (a ​​^ c) wir haben, = e ^ x / {e ^ max (x) * Summe (e ^ x / e ^ max (x))} = e ^ x / Summe (e ^ x)
shanky_thebearer
5
@ Trevor Merrifield, ich glaube nicht, dass der erste Ansatz einen "unnötigen Begriff" hatte. In der Tat ist es besser als der zweite Ansatz. Ich habe diesen Punkt als separate Antwort hinzugefügt.
Shagun Sodhani
6
@ Shagun Du bist richtig. Die beiden sind mathematisch äquivalent, aber ich hatte die numerische Stabilität nicht berücksichtigt.
Trevor Merrifield
Ich hoffe, es macht Ihnen nichts aus: Ich habe "unnötigen Begriff" herausgeschnitten, falls die Leute die Kommentare nicht lesen (oder die Kommentare verschwinden). Diese Seite erhält ziemlich viel Verkehr von Suchmaschinen und dies ist derzeit die erste Antwort, die die Leute sehen.
Alex Riley
Ich frage mich, warum Sie max (x) und nicht max (abs (x)) subtrahieren (korrigieren Sie das Vorzeichen, nachdem Sie den Wert ermittelt haben). Wenn alle Ihre Werte unter Null liegen und in ihrem absoluten Wert sehr groß sind und nur der Wert (das Maximum) nahe Null liegt, ändert das Subtrahieren des Maximums nichts. Wäre es nicht immer noch numerisch instabil?
Cerno
101

(Nun ... viel Verwirrung hier, sowohl in der Frage als auch in den Antworten ...)

Zunächst sind die beiden Lösungen (dh Ihre und die vorgeschlagene) nicht gleichwertig. sie passieren nur für den speziellen Fall von 1-D - Score - Arrays äquivalent. Sie hätten es entdeckt, wenn Sie auch das 2-D-Score-Array im Beispiel des Udacity-Quiz ausprobiert hätten.

In Bezug auf die Ergebnisse ist der einzige tatsächliche Unterschied zwischen den beiden Lösungen das axis=0Argument. Um zu sehen, dass dies der Fall ist, versuchen wir Ihre Lösung ( your_softmax) und eine, bei der der einzige Unterschied das axisArgument ist:

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

Wie gesagt, für ein 1-D-Score-Array sind die Ergebnisse tatsächlich identisch:

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)

Hier sind jedoch die Ergebnisse für das 2-D-Score-Array, die im Udacity-Quiz als Testbeispiel angegeben wurden:

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

Die Ergebnisse sind unterschiedlich - das zweite ist tatsächlich identisch mit dem im Udacity-Quiz erwarteten, bei dem alle Spalten tatsächlich 1 ergeben, was beim ersten (falschen) Ergebnis nicht der Fall ist.

Die ganze Aufregung galt also tatsächlich einem Implementierungsdetail - dem axisArgument. Laut der numpy.sum-Dokumentation :

Der Standardwert Achse = Keine summiert alle Elemente des Eingabearrays

während wir hier zeilenweise summieren wollen, daher axis=0. Bei einem 1-D-Array sind die Summe der (einzigen) Zeile und die Summe aller Elemente identisch, daher sind Ihre identischen Ergebnisse in diesem Fall ...

Die axisFrage beiseite, Ihre Implementierung (dh Ihre Wahl , um den max ersten zu subtrahieren) ist eigentlich besser als die vorgeschlagene Lösung! Tatsächlich ist dies die empfohlene Methode zur Implementierung der Softmax-Funktion - siehe hier zur Begründung (numerische Stabilität, auf die auch einige andere Antworten hier hinweisen).

desertnaut
quelle
Nun, wenn Sie nur über mehrdimensionale Arrays sprechen. Die erste Lösung kann einfach durch Hinzufügen von axisArgumenten zu maxund behoben werden sum. Die erste Implementierung ist jedoch immer noch besser, da Sie bei der Einnahme leicht überlaufen könnenexp
Louis Yang vor
@ LouisYang Ich folge nicht; Welches ist die "erste" Lösung? Welches ist nicht verwenden exp? Was wurde hier mehr geändert, als ein axisArgument hinzuzufügen ?
desertnaut vor
Die erste Lösung bezieht sich auf die Lösung von @alvas. Der Unterschied besteht darin, dass der vorgeschlagenen Lösung in Alvas 'Frage der Teil des Subtrahierens der max. Dies kann leicht zu einem Überlauf führen, zum Beispiel sind exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) in der Mathematik gleich, aber die Der erste wird überlaufen.
Louis Yang
@ LouisYang immer noch nicht sicher, ob ich die Notwendigkeit Ihres Kommentars verstehe - all dies wurde bereits in der Antwort explizit angesprochen.
Wüstennaut
@LouisYang Bitte lassen Sie sich nicht von der (nachfolgenden) Popularität des Threads täuschen und versuchen Sie sich den Kontext vorzustellen, in dem die eigene Antwort angeboten wurde: ein verwirrtes OP (" beide geben das gleiche Ergebnis ") und eine (noch!) Akzeptierte Antwort behaupten, dass " beide richtig sind " (nun, sie sind nicht ). Die Antwort sollte niemals lauten: " Das ist die korrekteste und effizienteste Methode, um Softmax im Allgemeinen zu berechnen. " Es sollte nur begründen, warum in dem besprochenen spezifischen Udacity-Quiz die beiden Lösungen nicht gleichwertig sind.
Wüstennaut
56

Dies ist also wirklich ein Kommentar zu Desertnauts Antwort, aber ich kann ihn aufgrund meines Rufs noch nicht kommentieren. Wie er betonte, ist Ihre Version nur dann korrekt, wenn Ihre Eingabe aus einem einzelnen Beispiel besteht. Wenn Ihre Eingabe aus mehreren Samples besteht, ist dies falsch. Die Lösung von desertnaut ist jedoch auch falsch. Das Problem ist, dass er einmal eine eindimensionale Eingabe und dann eine zweidimensionale Eingabe macht. Lass mich dir das zeigen.

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

Nehmen wir als Beispiel Wüstennaut:

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

Dies ist die Ausgabe:

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

Sie können sehen, dass die Desernauts-Version in dieser Situation fehlschlagen würde. (Es wäre nicht so, wenn die Eingabe nur eindimensional wäre wie np.array ([1, 2, 3, 6]).

Verwenden wir jetzt 3 Samples, da dies der Grund ist, warum wir eine zweidimensionale Eingabe verwenden. Das folgende x2 ist nicht dasselbe wie das aus dem Beispiel eines Desernauts.

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

Diese Eingabe besteht aus einer Charge mit 3 Proben. Aber Probe eins und drei sind im Wesentlichen gleich. Wir erwarten jetzt 3 Reihen von Softmax-Aktivierungen, wobei die erste mit der dritten und auch mit unserer Aktivierung von x1 identisch sein sollte!

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

Ich hoffe, Sie können sehen, dass dies nur bei meiner Lösung der Fall ist.

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

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

Darüber hinaus sind hier die Ergebnisse der TensorFlows-Softmax-Implementierung aufgeführt:

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

Und das Ergebnis:

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
quelle
6
Das wäre ein verdammt
Michael Benjamin
27
np.exp (z) / np.sum (np.exp (z), Achse = 1, keepdims = True) erreicht das gleiche Ergebnis wie Ihre Softmax-Funktion. Die Schritte mit s sind nicht erforderlich.
PabTorre
Anstelle von` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)sollte auch Arbeit.
Debashish
2
so viele falsche / ineffiziente Lösungen auf dieser Seite. Tun Sie sich selbst einen Gefallen und verwenden Sie PabTorre's
Miss Palmer
@PabTorre meintest du Achse = -1? Achse = 1 funktioniert nicht für eindimensionale Eingaben
DiehardTheTryhard
36

Ich würde sagen, dass beide zwar mathematisch korrekt und implementierungsmäßig korrekt sind, der erste jedoch besser ist. Bei der Berechnung von Softmax können die Zwischenwerte sehr groß werden. Das Teilen von zwei großen Zahlen kann numerisch instabil sein. Diese Notizen (von Stanford) erwähnen einen Normalisierungstrick, der im Wesentlichen das ist, was Sie tun.

Shagun Sodhani
quelle
3
Die Auswirkungen einer katastrophalen Stornierung sind nicht zu unterschätzen.
Cesar
24

sklearn bietet auch die Implementierung von Softmax an

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]]) 
Roman Orac
quelle
3
Wie genau beantwortet dies die spezifische Frage, die sich auf die Implementierung selbst und nicht auf die Verfügbarkeit in einer Bibliothek eines Drittanbieters bezieht?
Desertnaut
8
Ich suchte nach einer Implementierung durch Dritte, um die Ergebnisse beider Ansätze zu überprüfen. So hilft dieser Kommentar.
Eugenio F. Martinez Pacheco
13

Aus mathematischer Sicht sind beide Seiten gleich.

Und das können Sie leicht beweisen. Lass uns m=max(x). Jetzt gibt Ihre Funktion softmaxeinen Vektor zurück, dessen i-te Koordinate gleich ist

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass dies mfür alle funktioniert , da für alle (auch komplexen) Zahlene^m != 0

  • Unter dem Gesichtspunkt der rechnerischen Komplexität sind sie ebenfalls äquivalent und laufen beide O(n)zeitlich, wobei ndie Größe eines Vektors ist.

  • Unter dem Gesichtspunkt der numerischen Stabilität wird die erste Lösung bevorzugt, da sie e^xsehr schnell wächst und selbst bei ziemlich kleinen Werten xüberläuft. Durch Subtrahieren des Maximalwerts kann dieser Überlauf beseitigt werden. Um die Dinge, über die ich gesprochen habe, praktisch zu erleben, versuchen Sie, x = np.array([1000, 5])beide Funktionen zu nutzen. Einer gibt die korrekte Wahrscheinlichkeit zurück, der zweite läuft mitnan

  • Ihre Lösung funktioniert nur für Vektoren (das Udacity-Quiz möchte, dass Sie sie auch für Matrizen berechnen). Um es zu beheben, müssen Sie verwendensum(axis=0)

Salvador Dali
quelle
1
Wann ist es sinnvoll, Softmax eher auf Matrix als auf Vektor berechnen zu können? dh welche Modelle geben die Matrix aus? Kann es noch dimensionaler sein?
Mrgloom
2
Meinen Sie die erste Lösung in "Aus Sicht der numerischen Stabilität wird die zweite Lösung bevorzugt ..."?
Dataman
10

BEARBEITEN . Ab Version 1.2.0 enthält scipy als Sonderfunktion softmax:

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

Ich habe eine Funktion geschrieben, die den Softmax auf eine beliebige Achse anwendet:

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

Das Subtrahieren des Maximums ist, wie von anderen Benutzern beschrieben, eine gute Praxis. Ich schrieb einen ausführlichen Beitrag über sie hier .

Nolan Conaway
quelle
9

Hier erfahren Sie, warum sie verwendet wurden - max.

Von dort:

"Wenn Sie in der Praxis Code für die Berechnung der Softmax-Funktion schreiben, können die Zwischenbegriffe aufgrund der Exponentiale sehr groß sein. Das Teilen großer Zahlen kann numerisch instabil sein. Daher ist es wichtig, einen Normalisierungstrick zu verwenden."

Sadegh Salehi
quelle
4

Eine präzisere Version ist:

def softmax(x):
    return np.exp(x) / np.exp(x).sum(axis=0)
Pimin Konstantin Kefaloukos
quelle
9
Dies kann zu einem arithmetischen Überlauf führen
minhle_r7
4

Um eine alternative Lösung anzubieten, betrachten Sie die Fälle, in denen Ihre Argumente extrem groß sind, so dass exp(x)ein Unterlauf (im negativen Fall) oder ein Überlauf (im positiven Fall) auftreten würde. Hier möchten Sie so lange wie möglich im Protokollbereich bleiben und nur am Ende potenzieren, wo Sie darauf vertrauen können, dass sich das Ergebnis gut verhält.

import scipy.special as sc
import numpy as np

def softmax(x: np.ndarray) -> np.ndarray:
    return np.exp(x - sc.logsumexp(x))
PikalaxALT
quelle
Um es dem Postercode gleichzusetzen, müssen Sie es axis=0als Argument hinzufügen logsumexp.
Björn Lindqvist
Alternativ könnte man zusätzliche Argumente entpacken, um sie an logsumexp zu übergeben.
PikalaxALT
3

Ich brauchte etwas, das mit der Ausgabe einer dichten Schicht von Tensorflow kompatibel ist .

Die Lösung von @desertnaut funktioniert in diesem Fall nicht, da ich Datenstapel habe. Daher habe ich eine andere Lösung gefunden, die in beiden Fällen funktionieren sollte:

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)

Ergebnisse:

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

Ref: Tensorflow Softmax

Lucas Casagrande
quelle
Denken Sie daran, dass sich die Antwort auf eine ganz bestimmte Einstellung bezieht, die in der Frage beschrieben wird. Es sollte nie sein, wie man den Softmax im Allgemeinen unter keinen Umständen oder in dem Datenformat berechnet, das man mag. ...
desertnaut
Ich verstehe, ich habe dies hier eingefügt, weil sich die Frage auf "Udacitys Deep-Learning-Klasse" bezieht und es nicht funktionieren würde, wenn Sie Tensorflow zum Erstellen Ihres Modells verwenden. Ihre Lösung ist cool und sauber, funktioniert aber nur in einem ganz bestimmten Szenario. Danke trotzdem.
Lucas Casagrande
2

Ich würde dies vorschlagen:

def softmax(z):
    z_norm=np.exp(z-np.max(z,axis=0,keepdims=True))
    return(np.divide(z_norm,np.sum(z_norm,axis=0,keepdims=True)))

Es funktioniert sowohl für stochastische als auch für die Charge.
Weitere Informationen finden Sie unter: https://medium.com/@ravish1729/analysis-of-softmax-function-ad058d6a564d

Ravish Kumar Sharma
quelle
1

Um die numerische Stabilität zu gewährleisten, sollte max (x) subtrahiert werden. Das Folgende ist der Code für die Softmax-Funktion;

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
quelle
1

Bereits ausführlich in den obigen Antworten beantwortet. maxwird abgezogen, um einen Überlauf zu vermeiden. Ich füge hier eine weitere Implementierung in Python3 hinzu.

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
quelle
1

Jeder scheint seine Lösung zu veröffentlichen, also werde ich meine veröffentlichen:

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

Ich erhalte genau die gleichen Ergebnisse wie die von sklearn importierten:

from sklearn.utils.extmath import softmax
julianisch
quelle
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()
König
quelle
Willkommen bei SO. Eine Erklärung, wie Ihr Code die Frage beantwortet, ist immer hilfreich.
Nick
1

Lassen Sie mich anhand aller Antworten und CS231n-Notizen Folgendes zusammenfassen:

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

Verwendung:

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

Ausgabe:

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
quelle
0

Ich möchte das Problem etwas besser verstehen. Hier ist es richtig, das Maximum des Arrays zu subtrahieren. Wenn Sie den Code jedoch in einem anderen Beitrag ausführen, werden Sie feststellen, dass er Ihnen keine richtige Antwort gibt, wenn das Array 2D- oder höhere Dimensionen aufweist.

Hier gebe ich Ihnen einige Vorschläge:

  1. Um das Maximum zu erreichen, versuchen Sie es entlang der x-Achse. Sie erhalten ein 1D-Array.
  2. Formen Sie Ihr maximales Array in die ursprüngliche Form um.
  3. Erhält np.exp einen Exponentialwert?
  4. Machen Sie np.sum entlang der Achse.
  5. Holen Sie sich die endgültigen Ergebnisse.

Folgen Sie dem Ergebnis, um die richtige Antwort zu erhalten, indem Sie eine Vektorisierung durchführen. Da es sich um die Hausaufgaben des Colleges handelt, kann ich den genauen Code hier nicht veröffentlichen, aber ich würde gerne weitere Vorschläge machen, wenn Sie nicht verstehen.

Hao Xu
quelle
1
Es bezieht sich nicht auf Hausaufgaben am College, sondern nur auf ein
unbenotetes Übungsquiz
0

Der Zweck der Softmax-Funktion besteht darin, das Verhältnis der Vektoren beizubehalten, anstatt die Endpunkte mit einem Sigmoid zu quetschen, wenn die Werte gesättigt sind (dh zu +/- 1 (tanh) oder von 0 zu 1 (logistisch) tendieren). Dies liegt daran, dass mehr Informationen über die Änderungsrate an den Endpunkten erhalten bleiben und daher besser auf neuronale Netze mit 1-aus-N-Ausgangskodierung anwendbar sind (dh wenn wir die Endpunkte zerquetschen, ist es schwieriger, die 1 zu unterscheiden -of-N Ausgabeklasse, weil wir nicht sagen können, welche die "größte" oder "kleinste" ist, weil sie gequetscht wurden.); Außerdem wird die Gesamtausgangssumme auf 1 gesetzt, und der eindeutige Gewinner wird näher an 1 sein, während andere Zahlen, die nahe beieinander liegen, 1 / p ergeben, wobei p die Anzahl der Ausgangsneuronen mit ähnlichen Werten ist.

Der Zweck des Subtrahierens des Maximalwerts vom Vektor besteht darin, dass Sie beim Ausführen von Exponenten möglicherweise einen sehr hohen Wert erhalten, der den Gleitkommawert auf den Maximalwert begrenzt, der zu einem Gleichstand führt, was in diesem Beispiel nicht der Fall ist. Dies wird zu einem GROSSEN Problem, wenn Sie den Maximalwert subtrahieren, um eine negative Zahl zu erhalten. Dann haben Sie einen negativen Exponenten, der die Werte schnell verkleinert und das Verhältnis ändert. Dies ist in der Frage des Posters der Fall und hat die falsche Antwort ergeben.

Die Antwort von Udacity ist schrecklich ineffizient. Das erste, was wir tun müssen, ist, e ^ y_j für alle Vektorkomponenten zu berechnen, DIESE WERTE ZU BEHALTEN, sie dann zusammenzufassen und zu teilen. Wo Udacity durcheinander ist, berechnen sie e ^ y_j ZWEIMAL !!! Hier ist die richtige Antwort:

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)

quelle
0

Ziel war es, mit Numpy und Tensorflow ähnliche Ergebnisse zu erzielen. Die einzige Änderung gegenüber der ursprünglichen Antwort ist der axisParameter für die np.sumAPI.

Erster Ansatz : axis=0- Dies liefert jedoch nicht die beabsichtigten Ergebnisse, wenn die Abmessungen N sind.

Modifizierter Ansatz : axis=len(e_x.shape)-1- Summieren Sie immer die letzte Dimension. Dies liefert ähnliche Ergebnisse wie die Softmax-Funktion von 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
quelle
0

Hier ist eine verallgemeinerte Lösung unter Verwendung von Numpy und Vergleich auf Korrektheit mit Tensorflow und Scipy:

Datenaufbereitung:

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)

Ausgabe:

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

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

Ausgabe:

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

Ausgabe:

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

Ausgabe:

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
quelle
0

Die Softmax-Funktion ist eine Aktivierungsfunktion, die Zahlen in Wahrscheinlichkeiten umwandelt, die sich zu eins summieren. Die Softmax-Funktion gibt einen Vektor aus, der die Wahrscheinlichkeitsverteilungen einer Ergebnisliste darstellt. Es ist auch ein Kernelement, das bei Klassifizierungsaufgaben für tiefes Lernen verwendet wird.

Die Softmax-Funktion wird verwendet, wenn wir mehrere Klassen haben.

Es ist nützlich, um herauszufinden, welche Klasse die max. Wahrscheinlichkeit.

Die Softmax-Funktion wird idealerweise in der Ausgabeschicht verwendet, wo wir tatsächlich versuchen, die Wahrscheinlichkeiten zu erreichen, um die Klasse jeder Eingabe zu definieren.

Es reicht von 0 bis 1.

Die Softmax-Funktion wandelt Logits [2.0, 1.0, 0.1] in Wahrscheinlichkeiten [0.7, 0.2, 0.1] um, und die Wahrscheinlichkeiten summieren sich zu 1. Logits sind die Rohwerte, die von der letzten Schicht eines neuronalen Netzwerks ausgegeben werden. Bevor die Aktivierung erfolgt. Um die Softmax-Funktion zu verstehen, müssen wir uns die Ausgabe der (n-1) -ten Schicht ansehen.

Die Softmax-Funktion ist in der Tat eine Arg-Max-Funktion. Dies bedeutet, dass nicht der größte Wert von der Eingabe zurückgegeben wird, sondern die Position der größten Werte.

Beispielsweise:

Vor softmax

X = [13, 31, 5]

Nach 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
quelle