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:
Onde S(y_i)
está a função softmax de y_i
e 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?
-inf to +inf
para-inf to 0
. Eu acho que estava pensando demais. hahahaaaaxis = 0
resposta sugerida por Udacity?Respostas:
Ambos estão corretos, mas o seu é preferido do ponto de vista da estabilidade numérica.
Você começa com
Usando o fato de que a ^ (b - c) = (a ^ b) / (a ^ c) temos
Qual é o que a outra resposta diz. Você poderia substituir max (x) por qualquer variável e ela cancelaria.
fonte
(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=0
argumento. Para ver que esse é o caso, vamos tentar sua solução (your_softmax
) e uma onde a única diferença é oaxis
argumento:Como eu disse, para uma matriz de pontuação 1-D, os resultados são realmente idênticos:
No entanto, aqui estão os resultados para a matriz de pontuação 2D fornecida no questionário Udacity como um exemplo de teste:
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
axis
argumento. De acordo com a documentação numpy.sum :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
axis
problema à 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).fonte
axis
argumento a ambosmax
esum
. No entanto, a primeira implementação ainda é melhor, pois você pode transbordar facilmente ao tomarexp
exp
? O que mais foi modificado aqui, além de adicionar umaxis
argumento?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ê.
Vamos dar o exemplo do desertnauts:
Esta é a saída:
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.
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!
Espero que você possa ver que esse é apenas o caso da minha solução.
Além disso, aqui estão os resultados da implementação do softmax do TensorFlows:
E o resultado:
fonte
s = s[:, np.newaxis]
,s = s.reshape(z.shape[0],1)
também deve funcionar.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.
fonte
O sklearn também oferece a implementação do softmax
fonte
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çãosoftmax
retorna um vetor cuja i-ésima coordenada é igual aobserve 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, onden
é o tamanho de um vetor.do ponto de vista da estabilidade numérica , a primeira solução é preferida, porque
e^x
cresce muito rápido e até mesmo para valores muito pequenosx
dela transborda. Subtrair o valor máximo permite eliminar esse estouro. Para experimentar praticamente o que eu estava falando, tente alimentar asx = 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 usar
sum(axis=0)
fonte
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:
Subtrair o máximo, como outros usuários descreveram, é uma boa prática. Eu escrevi um post detalhado sobre isso aqui .
fonte
Aqui você pode descobrir por que eles usaram
- max
.De lá:
fonte
Uma versão mais concisa é:
fonte
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.fonte
axis=0
como argumento alogsumexp
.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:
Resultados:
Ref: Tensorflow softmax
fonte
Eu sugeriria isso:
Ele funcionará tanto para o estocástico quanto para o lote.
Para obter mais detalhes, consulte: https://medium.com/@ravish1729/analysis-of-softmax-function-ad058d6a564d
fonte
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):
fonte
Já respondeu com muitos detalhes nas respostas acima.
max
é subtraído para evitar o estouro. Estou adicionando aqui mais uma implementação em python3.fonte
Todo mundo parece postar sua solução, então eu postarei a minha:
Eu obtenho exatamente os mesmos resultados que os importados do sklearn:
fonte
fonte
Com base em todas as respostas e notas do CS231n , permita-me resumir:
Uso:
Resultado:
fonte
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:
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.
fonte
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:
fonte
O objetivo era alcançar resultados semelhantes usando Numpy e Tensorflow. A única alteração da resposta original é o
axis
parâmetro paranp.sum
API.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.fonte
Aqui está uma solução generalizada usando numpy e comparação para correção com tensorflow e scipy:
Preparação de dados:
Resultado:
Softmax usando tensorflow:
Resultado:
Softmax usando scipy:
Resultado:
Softmax usando numpy ( https://nolanbconaway.github.io/blog/2017/softmax-numpy ):
Resultado:
fonte
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
Após softmax
Código:
fonte