Come implementare la funzione Softmax in Python


247

Dalla classe di apprendimento profondo di Udacity , la softmax di y_i è semplicemente l'esponenziale diviso per la somma dell'esponente dell'intero vettore Y:

inserisci qui la descrizione dell'immagine

Dov'è S(y_i)la funzione softmax di y_ied eè l'esponenziale ed jè il no. di colonne nel vettore di input Y.

Ho provato quanto segue:

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

che ritorna:

[ 0.8360188   0.11314284  0.05083836]

Ma la soluzione suggerita era:

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

che produce lo stesso output della prima implementazione , anche se la prima implementazione prende esplicitamente la differenza di ogni colonna e il massimo e quindi si divide per la somma.

Qualcuno può mostrare matematicamente perché? Uno è corretto e l'altro è sbagliato?

L'implementazione è simile in termini di codice e complessità temporale? Qual è più efficiente?


6
Sono curioso di sapere perché hai tentato di implementarlo in questo modo con una funzione max. Cosa ti ha fatto pensare in quel modo?
— BBischof,

1
Non lo so, ho pensato di trattare il massimo come 0 e in qualche modo spostare il grafico a sinistra e clip a 0 aiuta. Allora la mia gamma sorta di accorciare da -inf to +infa -inf to 0. Immagino stavo pensando troppo. hahahaaa
— alvas

1
Ho ancora una sotto) domande a cui non sembra rispondere di seguito. Qual è il significato di axis = 0nella risposta suggerita da Udacity?
— Parva Thakkar,

3
se dai un'occhiata alla documentazione intorpidita, discute quale somma (x, asse = 0) - e allo stesso modo asse = 1-- fa. In breve, fornisce la direzione in cui sommare una matrice di array. In questo caso, dice di sommare lungo i vettori. In questo caso, ciò corrisponde ai denominatori nella funzione softmax.
— BBischof,

3
È come ogni altra settimana, c'è una risposta più corretta fino al punto in cui la mia matematica non è abbastanza buona per decidere chi è corretto =) Qualunque mago di matematica che non ha fornito una risposta può aiutare a decidere quale è corretta?
— alvas,

Risposte:


137

Sono entrambi corretti, ma il tuo è preferito dal punto di vista della stabilità numerica.

Inizi con

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

Usando il fatto che a ^ (b - c) = (a ^ b) / (a ​​^ c) abbiamo

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

= e ^ x / sum(e ^ x)

Questo è ciò che dice l'altra risposta. È possibile sostituire max (x) con qualsiasi variabile e si annullerebbe.


4
Riformattazione della risposta @TrevorM per ulteriori chiarimenti: e ^ (x - max (x)) / sum (e ^ (x - max (x)) utilizzando a ^ (b - c) = (a ^ b) / (a ​​^ c) abbiamo, = e ^ x / {e ^ max (x) * sum (e ^ x / e ^ max (x))} = e ^ x / sum (e ^ x)
— shanky_thebearer

5
@Trevor Merrifield, non credo che il primo approccio abbia avuto "termini inutili". In effetti è meglio del secondo approccio. Ho aggiunto questo punto come risposta separata.
— Shagun Sodhani,

6
@Shagun Hai ragione. I due sono matematicamente equivalenti ma non avevo considerato la stabilità numerica.
— Trevor Merrifield,

Spero non ti dispiaccia: ho eliminato "termine non necessario" nel caso in cui le persone non leggano i commenti (o i commenti scompaiono). Questa pagina riceve un bel po 'di traffico dai motori di ricerca e questa è attualmente la prima risposta che la gente vede.
— Alex Riley

Mi chiedo perché sottrai max (x) e non max (abs (x)) (correggi il segno dopo aver determinato il valore). Se tutti i tuoi valori sono inferiori a zero e molto grandi nel loro valore assoluto e solo il valore (il massimo) è vicino allo zero, sottraendo il massimo non cambierà nulla. Non sarebbe ancora numericamente instabile?
— Cerno

103

(Beh ... molta confusione qui, sia nella domanda che nelle risposte ...)

Per cominciare, le due soluzioni (cioè la tua e quella suggerita) non sono equivalenti; essi accadono equivalenti soltanto per il caso particolare di array punteggio 1-D. Lo avresti scoperto se avessi provato anche l'array di punteggi 2-D nel quiz Udacity fornito come esempio.

Per quanto riguarda i risultati, l'unica vera differenza tra le due soluzioni è l' axis=0argomento. Per vedere che questo è il caso, proviamo la tua soluzione ( your_softmax) e una in cui l'unica differenza è l' axisargomento:

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

Come ho detto, per un array di punteggi 1-D, i risultati sono effettivamente identici:

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)

Tuttavia, ecco i risultati per la matrice di punteggio 2-D fornita nel quiz Udacity come esempio di 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]]

I risultati sono diversi: il secondo è effettivamente identico a quello previsto nel quiz Udacity, in cui tutte le colonne sommano effettivamente 1, il che non è il caso del primo risultato (sbagliato).

Quindi, tutto il clamore era in realtà per un dettaglio di implementazione - l' axisargomento. Secondo la documentazione numpy.sum :

L'impostazione predefinita, axis = None, sommerà tutti gli elementi dell'array di input

mentre qui vogliamo riassumere per quanto riguarda le righe, quindi axis=0. Per un array 1-D, la somma della (sola) riga e la somma di tutti gli elementi risultano identiche, quindi i risultati identici in quel caso ...

A axisparte il problema, l'implementazione (ovvero la scelta di sottrarre il massimo prima) è in realtà migliore della soluzione suggerita! In realtà, è il modo raccomandato per implementare la funzione softmax - vedi qui per la giustificazione (stabilità numerica, indicata anche da altre risposte qui).


Bene, se stai parlando di array multidimensionali. La prima soluzione può essere facilmente risolta aggiungendo axisargomento a entrambi maxe sum. Tuttavia, la prima implementazione è ancora migliore poiché puoi facilmente traboccare quando prendiexp
— Louis Yang il

@LouisYang non sto seguendo; qual è la "prima" soluzione? Quale non usa exp? Cos'altro è stato modificato qui se non l'aggiunta di un axisargomento?
— Desertnaut il

La prima soluzione si riferisce alla soluzione di @alvas. La differenza è che alla soluzione suggerita nella domanda di alvas manca la parte della sottrazione del limite massimo. Questo può facilmente causare overflow, ad esempio exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) sono gli stessi in matematica ma il il primo traboccerà.
— Louis Yang, il

@LouisYang ancora, non sono sicuro di aver capito la necessità del tuo commento - tutto questo è già stato affrontato esplicitamente nella risposta.
— Desertnaut il

@LouisYang, per favore, non lasciatevi ingannare dalla (successiva) popolarità del thread e provate a immaginare il contesto in cui è stata offerta la propria risposta: un OP perplesso (" entrambi danno lo stesso risultato ") e una (ancora!) Risposta accettata sostenendo che " entrambi sono corrette " (bene, sono non ). La risposta non è mai stata pensata per essere " questo è il modo più corretto ed efficiente per calcolare il softmax in generale "; voleva solo giustificare perché , nello specifico quiz su Udacity discusso, le 2 soluzioni non fossero equivalenti.
— Desertnaut

56

Quindi, questo è davvero un commento alla risposta di desertnaut ma non posso ancora commentarlo a causa della mia reputazione. Come ha sottolineato, la tua versione è corretta solo se il tuo input è costituito da un singolo campione. Se il tuo input è composto da più campioni, è sbagliato. Tuttavia, anche la soluzione di Desertnaut è sbagliata. Il problema è che una volta accetta un input monodimensionale e quindi accetta un input bidimensionale. Lascia che te lo mostri.

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

Facciamo un esempio dei desertnauts:

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

Questo è l'output:

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

Puoi vedere che la versione di Desernauts fallirebbe in questa situazione. (Non sarebbe se l'input fosse solo unidimensionale come np.array ([1, 2, 3, 6]).

Ora usiamo 3 campioni poiché questo è il motivo per cui usiamo un input bidimensionale. Il seguente x2 non è uguale a quello dell'esempio di desernauts.

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

Questo input è costituito da un batch con 3 campioni. Ma il campione uno e tre sono essenzialmente gli stessi. Ora ci aspettiamo 3 file di attivazioni di softmax in cui la prima dovrebbe essere la stessa della terza e anche la stessa della nostra attivazione di 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]])

Spero che tu possa vedere che questo è solo il caso della mia soluzione.

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

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

Inoltre, ecco i risultati dell'implementazione del softmax di 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})

E il risultato:

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)

6
Sarebbe stato un gran bel commento ;-)
— Michael Benjamin,

27
np.exp (z) / np.sum (np.exp (z), axis = 1, keepdims = True) raggiunge lo stesso risultato della funzione softmax. i passaggi con s non sono necessari.
— PabTorre,

Al posto di` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)dovrebbe funzionare anche.
— Debashish,

2
così tante soluzioni errate / inefficienti in questa pagina. Fatevi un favore e usate PabTorre's
— Miss Palmer il

@PabTorre intendevi asse = -1? axis = 1 non funziona con input monodimensionali
— DiehardThe Tryhard

36

Direi che mentre entrambi sono corretti matematicamente, per quanto riguarda l'implementazione, il primo è migliore. Quando si calcola il softmax, i valori intermedi possono diventare molto grandi. Dividere due grandi numeri può essere numericamente instabile. Queste note (da Stanford) menzionano un trucco di normalizzazione che è essenzialmente quello che stai facendo.


3
Gli effetti dell'annullamento catastrofico non possono essere sottovalutati.
— Cesar,

24

sklearn offre anche l'implementazione di 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]]) 

3
Come risponde esattamente alla domanda specifica, che riguarda l' implementazione stessa e non la disponibilità in alcune librerie di terze parti?
— Desertnaut,

8
Stavo cercando un'implementazione di terze parti per verificare i risultati di entrambi gli approcci. Questo è il modo in cui questo commento aiuta.
— Eugenio F. Martinez Pacheco,

13

Dal punto di vista matematico entrambi i lati sono uguali.

E puoi dimostrarlo facilmente. Let's m=max(x). Ora la tua funzione softmaxrestituisce un vettore, la cui i-esima coordinata è uguale a

inserisci qui la descrizione dell'immagine

si noti che questo funziona per qualsiasi m, perché per tutti i numeri (anche complessi)e^m != 0

  • dal punto di vista della complessità computazionale sono anche equivalenti ed entrambi corrono nel O(n)tempo, dov'è nla dimensione di un vettore.

  • a partire dal punto di vista della stabilità numerica , la prima soluzione è preferita, perché e^xcresce molto velocemente e anche per valori piuttosto piccoli xtraboccerà. Sottraendo il valore massimo è possibile eliminare questo overflow. Per sperimentare praticamente le cose di cui stavo parlando, prova ad alimentare x = np.array([1000, 5])entrambe le tue funzioni. Uno restituirà la probabilità corretta, il secondo traboccerànan

  • la tua soluzione funziona solo per i vettori (il quiz Udacity vuole che tu lo calcoli anche per le matrici). Per risolverlo devi usaresum(axis=0)


1
Quando è utile poter calcolare il softmax sulla matrice piuttosto che sul vettore? cioè quali modelli di matrice di output? Può essere ancora più dimensionale?
— MrGloom il

2
intendi la prima soluzione in "dal punto di vista della stabilità numerica, la seconda soluzione è preferita ..."?
— Dataman

10

MODIFICARE . A partire dalla versione 1.2.0, scipy include softmax come funzione speciale:

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

Ho scritto una funzione applicando il softmax su qualsiasi asse:

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

Sottrarre il massimo, come descritto da altri utenti, è una buona pratica. Ho scritto un post dettagliato al riguardo qui .


9

Qui puoi scoprire perché hanno usato - max.

Da li:

"Quando si scrive codice per calcolare la funzione Softmax in pratica, i termini intermedi possono essere molto grandi a causa degli esponenziali. Dividere grandi numeri può essere numericamente instabile, quindi è importante usare un trucco di normalizzazione."



4

Per offrire una soluzione alternativa, prendi in considerazione i casi in cui i tuoi argomenti sono estremamente grandi in modo tale che exp(x)verrebbero meno o meno (nel caso negativo) o troppo pieno (nel caso positivo). Qui vuoi rimanere nello spazio di registro il più a lungo possibile, esponendo solo alla fine, dove puoi fidarti che il risultato sarà ben educato.

import scipy.special as sc
import numpy as np

def softmax(x: np.ndarray) -> np.ndarray:
    return np.exp(x - sc.logsumexp(x))

Per renderlo uguale al codice dei poster, è necessario aggiungere axis=0come argomento a logsumexp.
— Björn Lindqvist,

In alternativa, è possibile decomprimere argomenti aggiuntivi da passare a logsumexp.
— PikalaxALT,

3

Avevo bisogno di qualcosa di compatibile con l'output di uno strato denso di Tensorflow .

La soluzione di @desertnaut non funziona in questo caso perché ho lotti di dati. Pertanto, sono arrivato con un'altra soluzione che dovrebbe funzionare in entrambi i casi:

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)

risultati:

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

Rif: Tensorflow softmax


Basta tenere presente che la risposta si riferisce a un'impostazione molto specifica descritta nella domanda; non è mai stato pensato per essere "come calcolare il softmax in generale in nessuna circostanza o nel formato dei dati di tuo gradimento" ...
— desertnaut

Vedo, l'ho messo qui perché la domanda si riferisce alla "classe di apprendimento profondo di Udacity" e non funzionerebbe se stai usando Tensorflow per costruire il tuo modello. La tua soluzione è bella e pulita ma funziona solo in uno scenario molto specifico. Grazie comunque.
— Lucas Casagrande,


1

Per mantenere la stabilità numerica, sottrarre max (x). Di seguito è riportato il codice per la funzione 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

1

Ho già risposto in modo molto dettagliato nelle risposte precedenti. maxviene sottratto per evitare il trabocco. Sto aggiungendo qui un'altra implementazione in 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))

1

Tutti sembrano pubblicare la loro soluzione, quindi posterò la mia:

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

Ottengo esattamente gli stessi risultati importati da sklearn:

from sklearn.utils.extmath import softmax

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

Benvenuti in SO. Una spiegazione di come il tuo codice risponde alla domanda è sempre utile.
— Nick,

1

Sulla base di tutte le risposte e delle note CS231n , consentitemi di riassumere:

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

Uso:

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

Produzione:

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

0

Vorrei integrare un po 'più di comprensione del problema. Qui è corretto sottrarre il massimo dell'array. Ma se esegui il codice nell'altro post, scopriresti che non ti dà la risposta giusta quando l'array ha dimensioni 2D o superiori.

Qui ti do alcuni suggerimenti:

  1. Per ottenere il massimo, prova a farlo lungo l'asse x, otterrai un array 1D.
  2. Rimodella l'array massimo alla forma originale.
  3. Np.exp ottiene valore esponenziale.
  4. Esegui np.sum lungo l'asse.
  5. Ottieni i risultati finali.

Segui il risultato otterrai la risposta corretta eseguendo la vettorializzazione. Dal momento che è legato ai compiti del college, non posso pubblicare qui il codice esatto, ma vorrei dare ulteriori suggerimenti se non capisci.


1
Non è legato ad alcun lavoro all'università, solo per un quiz non classificate pratica in maniera non accreditata corso, in cui la risposta corretta è fornita nella fase successiva ...
— desertnaut

0

Lo scopo della funzione softmax è di preservare il rapporto tra i vettori invece di schiacciare i punti finali con un sigmoide poiché i valori sono saturi (cioè tendono a +/- 1 (tanh) o da 0 a 1 (logistica)). Questo perché conserva maggiori informazioni sulla velocità di variazione negli end-point ed è quindi più applicabile alle reti neurali con codifica output 1-of-N (cioè se abbiamo schiacciato gli end-point sarebbe più difficile differenziare il 1 -of-N classe di output perché non possiamo dire quale sia il "più grande" o il "più piccolo" perché sono stati schiacciati.); inoltre fa la somma totale dell'output a 1, e il vincitore chiaro sarà più vicino a 1 mentre gli altri numeri vicini l'uno all'altro si sommeranno a 1 / p, dove p è il numero di neuroni di output con valori simili.

Lo scopo di sottrarre il valore massimo dal vettore è che quando si eseguono esponenti e ^ y si può ottenere un valore molto elevato che aggancia il galleggiante al valore massimo che porta a un pareggio, cosa che non è il caso in questo esempio. Questo diventa un GRANDE problema se si sottrae il valore massimo per creare un numero negativo, quindi si ha un esponente negativo che riduce rapidamente i valori alterando il rapporto, che è ciò che è accaduto nella domanda del poster e ha dato la risposta errata.

La risposta fornita da Udacity è ORRIBILMENTE inefficiente. La prima cosa che dobbiamo fare è calcolare e ^ y_j per tutti i componenti vettoriali, MANTENERE QUESTI VALORI, quindi sommarli e dividerli. Dove Udacity ha sbagliato è che calcolano e ^ y_j DUE VOLTE !!! Ecco la risposta corretta:

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)

0

L'obiettivo era ottenere risultati simili usando Numpy e Tensorflow. L'unica modifica rispetto alla risposta originale è il axisparametro per np.sumapi.

Approccio iniziale : axis=0- Ciò tuttavia non fornisce i risultati previsti quando le dimensioni sono N.

Approccio modificato : axis=len(e_x.shape)-1- Somma sempre l'ultima dimensione. Ciò fornisce risultati simili alla funzione softmax di 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)

0

Ecco una soluzione generalizzata che utilizza intorpidimento e confronto per correttezza con tensorflow e scipy:

Preparazione dei dati:

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)

Produzione:

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

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

Produzione:

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

Produzione:

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

Produzione:

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

0

La funzione softmax è una funzione di attivazione che trasforma i numeri in probabilità che si sommano a una. La funzione softmax genera un vettore che rappresenta le distribuzioni di probabilità di un elenco di risultati. È anche un elemento chiave utilizzato nelle attività di classificazione di apprendimento profondo.

La funzione Softmax viene utilizzata quando abbiamo più classi.

È utile per scoprire la classe che ha il massimo. Probabilità.

La funzione Softmax è idealmente utilizzata nel livello di output, dove stiamo effettivamente cercando di raggiungere le probabilità di definire la classe di ciascun input.

Va da 0 a 1.

La funzione Softmax trasforma i logit [2.0, 1.0, 0.1] in probabilità [0.7, 0.2, 0.1] e le probabilità si sommano a 1. I log sono i punteggi grezzi emessi dall'ultimo strato di una rete neurale. Prima dell'attivazione. Per comprendere la funzione softmax, dobbiamo guardare all'output del (n-1) th layer.

La funzione softmax è, infatti, una funzione arg max. Ciò significa che non restituisce il valore più grande dall'input, ma la posizione dei valori più grandi.

Per esempio:

Prima del softmax

X = [13, 31, 5]

Dopo softmax

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

Codice:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.