Como implementar a função Softmax em Python


246

Da classe de aprendizado profundo do Udacity , o softmax de y_i é simplesmente o exponencial dividido pela soma do exponencial de todo o vetor Y:

insira a descrição da imagem aqui

Onde S(y_i)está a função softmax de y_ie eé o exponencial e jé o não. de colunas no vetor de entrada Y.

Eu tentei o seguinte:

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 retorna:

[ 0.8360188   0.11314284  0.05083836]

Mas a solução sugerida foi:

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 produz a mesma saída que a primeira implementação , mesmo que a primeira implementação explique explicitamente a diferença de cada coluna e o máximo e depois divida pela soma.

Alguém pode mostrar matematicamente o porquê? Um está correto e o outro errado?

A implementação é semelhante em termos de código e complexidade de tempo? Qual é mais eficiente?


6
Estou curioso para saber por que você tentou implementá-lo dessa maneira com uma função max. O que fez você pensar dessa maneira?
BBischof

1
Eu não sei, eu pensei que tratar o máximo como 0 e meio que mover o gráfico para a esquerda e cortar 0 ajuda. Então meu alcance diminui de -inf to +infpara -inf to 0. Eu acho que estava pensando demais. hahahaaa
alvas

1
Eu ainda tenho uma sub) perguntas que não parecem respondidas abaixo. Qual é o significado da axis = 0resposta sugerida por Udacity?
Parva Thakkar

3
se você der uma olhada na documentação numpy, ela discute o que soma (x, eixo = 0) - e da mesma forma eixo = 1-- faz. Em resumo, fornece a direção na qual somar uma matriz de matrizes. Nesse caso, ele diz para somar os vetores. Nesse caso, isso corresponde aos denominadores na função softmax.
BBischof

3
É como a cada duas semanas, há uma resposta mais correta até o ponto em que minha matemática não é boa o suficiente para decidir quem está correto =) Qualquer especialista em matemática que não forneceu uma resposta pode ajudar a decidir qual é a correta?
alvas

Respostas:


137

Ambos estão corretos, mas o seu é preferido do ponto de vista da estabilidade numérica.

Você começa com

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

Usando o fato de que a ^ (b - c) = (a ^ b) / (a ​​^ c) temos

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

= e ^ x / sum(e ^ x)

Qual é o que a outra resposta diz. Você poderia substituir max (x) por qualquer variável e ela cancelaria.


4
Reformate sua resposta @TrevorM para obter mais esclarecimentos: e ^ (x - max (x)) / sum (e ^ (x - max (x)) usando a ^ (b - c) = (a ^ b) / (a ​​^ c) temos, = e ^ x / {e ^ max (x) * sum (e ^ x / e ^ max (x))} = e ^ x / soma (e ^ x)
shanky_thebearer

5
@ Trevor Merrifield, não acho que a primeira abordagem tenha tido um "termo desnecessário". De fato, é melhor que a segunda abordagem. Eu adicionei este ponto como uma resposta separada.
Shagun Sodhani

6
@ Shagun Você está correto. Os dois são matematicamente equivalentes, mas eu não havia considerado a estabilidade numérica.
Trevor Merrifield

Espero que você não se importe: editei "termo desnecessário" para o caso de as pessoas não lerem os comentários (ou os comentários desaparecerem). Essa página recebe bastante tráfego dos mecanismos de pesquisa e atualmente é a primeira resposta que as pessoas veem.
Alex Riley

Gostaria de saber por que você subtrai max (x) e não max (abs (x)) (corrija o sinal após determinar o valor). Se todos os seus valores estiverem abaixo de zero e forem muito grandes em seu valor absoluto, e apenas o valor (o máximo) for próximo de zero, subtrair o máximo não mudará nada. Ainda não seria numericamente instável?
Cerno

102

(Bem ... muita confusão aqui, tanto na pergunta quanto nas respostas ...)

Para começar, as duas soluções (ie a sua e a sugerida) não são equivalentes; eles acontecer que seja equivalente apenas para o caso especial de um D-matrizes de pontuação. Você o teria descoberto se tivesse tentado também a matriz de pontuação 2D no exemplo do questionário Udacity.

Em termos de resultados, a única diferença real entre as duas soluções é o axis=0argumento. Para ver que esse é o caso, vamos tentar sua solução ( your_softmax) e uma onde a única diferença é o axisargumento:

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

Como eu disse, para uma matriz de pontuação 1-D, os resultados são realmente idênticos:

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)

No entanto, aqui estão os resultados para a matriz de pontuação 2D fornecida no questionário Udacity como um exemplo de teste:

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

Os resultados são diferentes - o segundo é realmente idêntico ao esperado no questionário Udacity, onde todas as colunas realmente somam 1, o que não é o caso do primeiro resultado (errado).

Então, todo o barulho foi realmente para um detalhe de implementação - o axisargumento. De acordo com a documentação numpy.sum :

O padrão, axis = None, somará todos os elementos da matriz de entrada

enquanto aqui queremos somar em linhas, portanto axis=0. Para uma matriz 1-D, a soma da (apenas) linha e a soma de todos os elementos são idênticas, portanto, seus resultados idênticos nesse caso ...

O axisproblema à parte, sua implementação (ou seja, sua opção de subtrair o máximo primeiro) é realmente melhor que a solução sugerida! De fato, é a maneira recomendada de implementar a função softmax - veja aqui a justificativa (estabilidade numérica, também apontada por algumas outras respostas aqui).


Bem, se você está falando apenas de matriz multidimensional. A primeira solução pode ser facilmente corrigida adicionando axisargumento a ambos maxe sum. No entanto, a primeira implementação ainda é melhor, pois você pode transbordar facilmente ao tomarexp
Louis Yang

@LouisYang Não estou seguindo; qual é a "primeira" solução? Qual deles não usa exp? O que mais foi modificado aqui, além de adicionar um axisargumento?
desertnaut

A primeira solução refere-se à solução do @alvas. A diferença é que a solução sugerida na pergunta de alvas está faltando a parte de subtrair o valor máximo. Isso pode facilmente causar estouro, por exemplo, exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) são os mesmos em matemática, mas o o primeiro transbordará.
Louis Yang

@LouisYang ainda, não sei se entendi a necessidade do seu comentário - tudo isso já foi abordado explicitamente na resposta.
desertnaut

@LouisYang, por favor, não deixe a popularidade (subseqüente) do tópico te enganar e tente imaginar o contexto em que a própria resposta foi oferecida: um OP intrigado (" ambos dão o mesmo resultado ") e uma resposta (ainda!) Aceita alegando que " ambos estão corretos " (bem, eles não estão ). A resposta nunca foi criada para ser " essa é a maneira mais correta e eficiente de calcular o softmax em geral "; apenas pretendia justificar por que , no questionário Udacity específico discutido, as 2 soluções não são equivalentes.
desertnaut

56

Portanto, este é realmente um comentário à resposta do desertnaut, mas ainda não posso comentar devido à minha reputação. Como ele apontou, sua versão só está correta se sua entrada consistir em uma única amostra. Se sua entrada consistir em várias amostras, isso está errado. No entanto, a solução do desertnaut também está errada. O problema é que uma vez que ele recebe uma entrada unidimensional e, em seguida, ele recebe uma entrada bidimensional. Deixe-me mostrar isso para você.

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

Vamos dar o exemplo do desertnauts:

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

Esta é a saída:

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

Você pode ver que a versão desernauts falharia nessa situação. (Não seria se a entrada fosse apenas uma dimensão como np.array ([1, 2, 3, 6]).

Vamos agora usar 3 amostras, já que essa é a razão pela qual usamos uma entrada bidimensional. O x2 a seguir não é o mesmo do exemplo de desernauts.

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

Esta entrada consiste em um lote com 3 amostras. Mas a amostra um e três são essencialmente os mesmos. Agora esperamos 3 linhas de ativações softmax, onde a primeira deve ser igual à terceira e também a mesma que a ativação 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]])

Espero que você possa ver que esse é apenas o caso da minha solução.

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

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

Além disso, aqui estão os resultados da implementação do softmax do 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 o resultado:

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
Isso teria sido um inferno de um comentário ;-)
Michael Benjamin

27
np.exp (z) / np.sum (np.exp (z), eixo = 1, keepdims = True) atinge o mesmo resultado que sua função softmax. os passos com s são desnecessários.
PabTorre

No lugar de` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)também deve funcionar.
Debashish

2
tantas soluções incorretas / ineficientes nesta página. Faça um favor a si mesmo e use o PabTorre's
Miss Palmer

@PabTorre você quis dizer eixo = -1? axis = 1 não funcionará para entrada unidimensional
DiehardTheTryhard

36

Eu diria que, embora ambos estejam corretos matematicamente, em termos de implementação, o primeiro é melhor. Ao calcular o softmax, os valores intermediários podem se tornar muito grandes. A divisão de dois números grandes pode ser numericamente instável. Essas notas (de Stanford) mencionam um truque de normalização que é essencialmente o que você está fazendo.


3
Os efeitos do cancelamento catastrófico não podem ser subestimados.
Cesar

24

O sklearn também oferece a implementação do 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
Como exatamente isso responde à pergunta específica, que é sobre a implementação em si e não sobre a disponibilidade em alguma biblioteca de terceiros?
Desertnaut 16/07/19

8
Eu estava procurando uma implementação de terceiros para verificar os resultados de ambas as abordagens. É assim que esse comentário ajuda.
Eugenio F. Martinez Pacheco

13

Do ponto de vista matemático, ambos os lados são iguais.

E você pode facilmente provar isso. Vamos m=max(x). Agora sua função softmaxretorna um vetor cuja i-ésima coordenada é igual a

insira a descrição da imagem aqui

observe que isso funciona para qualquer um m, porque para todos os números (mesmo complexos)e^m != 0

  • do ponto de vista da complexidade computacional, eles também são equivalentes e correm no O(n)tempo, onde né o tamanho de um vetor.

  • do ponto de vista da estabilidade numérica , a primeira solução é preferida, porque e^xcresce muito rápido e até mesmo para valores muito pequenos xdela transborda. Subtrair o valor máximo permite eliminar esse estouro. Para experimentar praticamente o que eu estava falando, tente alimentar as x = np.array([1000, 5])duas funções. Um retornará a probabilidade correta, o segundo transbordará comnan

  • sua solução funciona apenas para vetores (o questionário Udacity também deseja que você o calcule para matrizes). Para corrigi-lo, você precisa usarsum(axis=0)


1
Quando útil calcular o softmax na matriz e não no vetor? ou seja, quais modelos de matriz de saída? Pode ser ainda mais dimensional?
mrgloom

2
você quer dizer a primeira solução em "do ponto de vista da estabilidade numérica, a segunda solução é a preferida ..."?
Dataman

10

EDIT . A partir da versão 1.2.0, o scipy inclui o softmax como uma função especial:

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

Eu escrevi uma função aplicando o softmax sobre qualquer eixo:

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

Subtrair o máximo, como outros usuários descreveram, é uma boa prática. Eu escrevi um post detalhado sobre isso aqui .


9

Aqui você pode descobrir por que eles usaram - max.

De lá:

"Quando você está escrevendo um código para calcular a função Softmax na prática, os termos intermediários podem ser muito grandes devido aos exponenciais. Dividir números grandes pode ser numericamente instável, por isso é importante usar um truque de normalização".



4

Para oferecer uma solução alternativa, considere os casos em que seus argumentos são extremamente grandes em magnitude, de tal forma que exp(x)estourariam (no caso negativo) ou estourariam (no caso positivo). Aqui, você deseja permanecer no espaço de log o maior tempo possível, exponenciando apenas no final, onde você pode confiar que o resultado será bem-comportado.

import scipy.special as sc
import numpy as np

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

Para torná-lo igual ao código dos pôsteres, você precisa adicionar axis=0como argumento a logsumexp.
Björn Lindqvist

Como alternativa, pode-se descompactar argumentos extras para passar ao logsumexp.
precisa saber é o seguinte

3

Eu precisava de algo compatível com a saída de uma camada densa do Tensorflow .

A solução da @desertnaut não funciona neste caso porque tenho lotes de dados. Portanto, eu vim com outra solução que deve funcionar nos dois casos:

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)

Resultados:

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


Lembre-se de que a resposta se refere a uma configuração muito específica descrita na pergunta; que nunca foi concebido para ser 'como calcular o softmax, em geral, sob quaisquer circunstâncias, ou no formato de dados do seu agrado' ...
desertnaut

Entendi, coloquei isso aqui porque a pergunta se refere à "classe de aprendizado profundo do Udacity" e não funcionaria se você estivesse usando o Tensorflow para construir seu modelo. Sua solução é legal e limpa, mas funciona apenas em um cenário muito específico. Obrigado mesmo assim.
Lucas Casagrande


1

Para manter a estabilidade numérica, o máximo (x) deve ser subtraído. A seguir está o código para a função 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

Já respondeu com muitos detalhes nas respostas acima. maxé subtraído para evitar o estouro. Estou adicionando aqui mais uma implementação em 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

Todo mundo parece postar sua solução, então eu postarei a minha:

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

Eu obtenho exatamente os mesmos resultados que os importados do 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()

Bem-vindo ao SO. Uma explicação de como seu código responde à pergunta é sempre útil.
13743 Nick

1

Com base em todas as respostas e notas do CS231n , permita-me resumir:

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)

Resultado:

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

Gostaria de complementar um pouco mais a compreensão do problema. Aqui está correto subtrair o máximo da matriz. Mas se você executar o código na outra postagem, descobrirá que ele não está fornecendo a resposta correta quando a matriz tem dimensões 2D ou superiores.

Aqui vou dar algumas sugestões:

  1. Para obter o máximo, tente fazê-lo no eixo x, você obterá uma matriz 1D.
  2. Remodele sua matriz máxima para a forma original.
  3. O np.exp obtém um valor exponencial.
  4. Faça np.sum ao longo do eixo.
  5. Obtenha os resultados finais.

Siga o resultado, você obterá a resposta correta fazendo vetorização. Como está relacionado à lição de casa da faculdade, não posso postar o código exato aqui, mas gostaria de dar mais sugestões, se você não entender.


1
Ele não está relacionado com qualquer lição de casa faculdade, unicamente a um questionário prática ungraded em um não-credenciados claro, onde a resposta correta é fornecido na próxima etapa ...
desertnaut

0

O objetivo da função softmax é preservar a proporção dos vetores, em vez de esmagar os pontos finais com um sigmóide conforme os valores saturam (ou seja, tendem a +/- 1 (tanh) ou de 0 a 1 (logísticos)). Isso ocorre porque ela preserva mais informações sobre a taxa de alteração nos pontos finais e, portanto, é mais aplicável às redes neurais com a codificação de saída 1-de-N (ou seja, se esmagássemos os pontos finais, seria mais difícil diferenciar o número 1). -de-N classe de saída porque não podemos dizer qual é a "maior" ou "menor" porque eles foram esmagados.); também soma a saída total a 1, e o vencedor claro estará mais próximo de 1, enquanto outros números próximos um do outro somarão 1 / p, onde p é o número de neurônios de saída com valores semelhantes.

O objetivo de subtrair o valor máximo do vetor é que, quando você faz todos os expoentes, pode obter um valor muito alto que corta a flutuação no valor máximo que leva a um empate, o que não é o caso neste exemplo. Isso se torna um problema GRANDE se você subtrair o valor máximo para formar um número negativo, e terá um expoente negativo que encolhe rapidamente os valores que alteram a proporção, que foi o que ocorreu na pergunta do pôster e gerou a resposta incorreta.

A resposta fornecida pela Udacity é terrivelmente ineficiente. A primeira coisa que precisamos fazer é calcular e ^ y_j para todos os componentes do vetor, MANTENHA OS VALORES, depois some-os e divida. Onde o Udacity estraga tudo, eles calculam e ^ y_j DUAS VEZES !!! Aqui está a resposta correta:

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

O objetivo era alcançar resultados semelhantes usando Numpy e Tensorflow. A única alteração da resposta original é o axisparâmetro para np.sumAPI.

Abordagem inicial : axis=0- No entanto, isso não fornece os resultados pretendidos quando as dimensões são N.

Abordagem modificada : axis=len(e_x.shape)-1- Soma sempre a última dimensão. Isso fornece resultados semelhantes aos da função softmax do 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

Aqui está uma solução generalizada usando numpy e comparação para correção com tensorflow e scipy:

Preparação de dados:

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)

Resultado:

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

Resultado:

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

Resultado:

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

Resultado:

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

A função softmax é uma função de ativação que transforma números em probabilidades que somam um. A função softmax gera um vetor que representa as distribuições de probabilidade de uma lista de resultados. É também um elemento central usado em tarefas de classificação de aprendizado profundo.

A função Softmax é usada quando temos várias classes.

É útil para descobrir a classe que tem o máx. Probabilidade.

A função Softmax é idealmente usada na camada de saída, na qual estamos realmente tentando obter as probabilidades de definir a classe de cada entrada.

Varia de 0 a 1.

A função Softmax transforma logits [2.0, 1.0, 0.1] em probabilidades [0.7, 0.2, 0.1] e as probabilidades somam 1. Logits são as pontuações brutas geradas pela última camada de uma rede neural. Antes da ativação ocorrer. Para entender a função softmax, devemos observar a saída da (n-1) ésima camada.

A função softmax é, de fato, uma função arg max. Isso significa que ele não retorna o maior valor da entrada, mas a posição dos maiores valores.

Por exemplo:

Antes do softmax

X = [13, 31, 5]

Após softmax

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

Código:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.