Função Softmax
Visão geral
A função softmax (softmax function) converte um vetor de valores reais (tipicamente chamado de logits (logits)) em uma distribuição de probabilidade (probability distribution) sobre um conjunto de classes. Ela é a transformação padrão da “última camada” para classificação multiclasse (multiclass classification) em Redes Neurais, e também aparece em outros contextos, como mecanismos de atenção (mecanismos de atenção (attention mechanisms)) na Arquitetura Transformer (Transformer Architecture).
Intuitivamente, a softmax transforma “pontuações” em probabilidades ao exponenciá-las (tornando-as positivas) e normalizá-las para que somem 1.
Definição
Dado um vetor de logits (z \in \mathbb{R}^K) para (K) classes, a saída da softmax (p \in \mathbb{R}^K) é
[ \mathrm{softmax}(z)i = \frac{e^{z_i}}{\sum{j=1}^{K} e^{z_j}}, \quad i=1,\dots,K. ]
Aqui:
- (z_i) é o logit (pontuação não normalizada) para a classe (i)
- (\mathrm{softmax}(z)_i) é a probabilidade prevista da classe (i)
Por que “logits”?
Em muitos modelos, os logits são produzidos por uma camada linear final:
[ z = Wx + b ]
onde (x) é a última representação escondida e (W,b) são parâmetros aprendíveis. Os logits não são probabilidades; eles podem assumir quaisquer valores reais.
Propriedades principais
1) A saída é uma distribuição de probabilidade válida
A softmax produz valores que satisfazem:
- Não negatividade: (\mathrm{softmax}(z)_i > 0) para todo (i)
- Normalização: (\sum_i \mathrm{softmax}(z)_i = 1)
Assim, a saída pode ser interpretada como uma distribuição categórica (categorical distribution) sobre as classes.
2) Preserva a ordem (o argmax não muda)
A softmax é monótona em relação a cada logit:
[ \arg\max_i z_i = \arg\max_i \mathrm{softmax}(z)_i ]
Assim, a softmax não muda qual classe tem a maior pontuação — ela apenas converte pontuações em probabilidades.
3) Invariância a deslocamento (shift invariance) (somar uma constante não importa)
Para qualquer constante (c),
[ \mathrm{softmax}(z)_i = \mathrm{softmax}(z + c\mathbf{1})_i. ]
Esboço de prova:
[ \frac{e^{z_i + c}}{\sum_j e^{z_j + c}} = \frac{e^{c} e^{z_i}}{e^{c}\sum_j e^{z_j}} = \frac{e^{z_i}}{\sum_j e^{z_j}}. ]
Essa propriedade é crucial para estabilidade numérica (numerical stability), porque significa que somos livres para deslocar os logits sem alterar o resultado.
4) Diferenças relativas importam (não a escala absoluta)
A softmax depende de diferenças entre logits. Se um logit for muito maior do que os demais, sua probabilidade se aproxima de 1, enquanto as outras se aproximam de 0. Isso leva a um comportamento de “o vencedor leva quase tudo” quando os logits estão bem separados.
Temperatura: controlando suavidade e confiança
Uma variante comum é a softmax com temperatura (softmax with temperature) (T > 0):
[ \mathrm{softmax}_T(z)_i = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}}. ]
Efeitos:
- Baixa temperatura (T \to 0^+): a distribuição fica muito concentrada (próxima de argmax / one-hot (one-hot)).
- Alta temperatura (T \to \infty): a distribuição fica mais plana, aproximando-se da uniforme.
Usos práticos de temperatura
- Calibração / escalonamento de confiança: O escalonamento de temperatura (temperature scaling) é um método simples post-hoc para calibrar probabilidades previstas (frequentemente aplicado aos logits antes da softmax).
- Destilação de conhecimento (knowledge distillation): Um modelo professor pode usar uma temperatura mais alta para fornecer “alvos suaves” que transmitam similaridades entre classes.
- Controle de amostragem em modelos generativos (generative models): A temperatura ajusta a aleatoriedade ao amostrar de uma distribuição categórica.
Um exemplo numérico concreto
Suponha que os logits sejam:
[ z = [2.0,\ 1.0,\ 0.1]. ]
Calcule as exponenciais:
- (e^{2.0} \approx 7.389)
- (e^{1.0} \approx 2.718)
- (e^{0.1} \approx 1.105)
Soma: (7.389 + 2.718 + 1.105 \approx 11.212)
Probabilidades:
- (p_1 \approx 7.389/11.212 \approx 0.659)
- (p_2 \approx 2.718/11.212 \approx 0.242)
- (p_3 \approx 1.105/11.212 \approx 0.099)
Assim, a softmax converte “a classe 1 tem a maior pontuação” em “a classe 1 tem ~65,9% de probabilidade”.
Estabilidade numérica: estouro (overflow) e o truque log-sum-exp (log-sum-exp trick)
O problema
Exponenciais crescem muito rápido. Se os logits forem grandes (por exemplo, 1000), (e^{z_i}) vai estourar para infinito na aritmética de ponto flutuante (floating-point arithmetic). Mesmo logits moderadamente grandes podem causar instabilidade.
Softmax estável via deslocamento pelo máximo
Usando a invariância a deslocamento, escolha (c = -\max_i z_i). Seja (m = \max_i z_i). Então:
[ \mathrm{softmax}(z)_i = \frac{e^{z_i - m}}{\sum_j e^{z_j - m}}. ]
Agora todos os expoentes são (\le 0), então as exponenciais ficam em ((0, 1]), evitando estouro.
Implementação de referência (NumPy)
import numpy as np
def softmax(z, axis=-1):
z = np.asarray(z)
m = np.max(z, axis=axis, keepdims=True)
exp = np.exp(z - m)
return exp / np.sum(exp, axis=axis, keepdims=True)
Log-softmax (log-softmax) e o truque log-sum-exp
No treinamento, frequentemente precisamos de (\log(\mathrm{softmax}(z))), especialmente para entropia cruzada / log-verossimilhança negativa. Calcular a softmax e depois aplicar log ainda pode ser instável (e desperdiça computação).
Defina:
[ \log \mathrm{softmax}(z)_i = z_i - \log \sum_j e^{z_j}. ]
O termo (\log \sum_j e^{z_j}) é calculado de forma estável usando log-sum-exp:
[ \log \sum_j e^{z_j} = m + \log \sum_j e^{z_j - m}, \quad m = \max_j z_j. ]
Isso evita estouro mantendo a precisão.
Log-softmax estável (NumPy)
def log_softmax(z, axis=-1):
z = np.asarray(z)
m = np.max(z, axis=axis, keepdims=True)
shifted = z - m
return shifted - np.log(np.sum(np.exp(shifted), axis=axis, keepdims=True))
Observação prática: use funções de biblioteca fundidas (fused)
Bibliotecas de deep learning fornecem implementações estáveis e fundidas:
- PyTorch:
torch.nn.functional.cross_entropy(recebe logits diretamente) - TensorFlow:
tf.nn.softmax_cross_entropy_with_logits
Essas funções normalmente calculam um log-softmax estável internamente e evitam materializar probabilidades explicitamente.
Softmax e [Perda de Entropia Cruzada (Cross-Entropy Loss)](/deep-learning/fundamentos/ativacoes-e-perdas/perda-de-entropia-cruzada)
Para classificação multiclasse com um vetor-alvo one-hot (y) e probabilidades previstas (p = \mathrm{softmax}(z)), a perda de entropia cruzada é:
[ \mathcal{L} = -\sum_{i=1}^{K} y_i \log p_i. ]
Se a classe verdadeira for (t) (então (y_t = 1) e as outras são 0), isso se reduz a:
[ \mathcal{L} = -\log p_t. ]
Isso também é a log-verossimilhança negativa (negative log-likelihood) da classe correta sob uma distribuição categórica parametrizada por (p).
Por que logits + entropia cruzada é tão comum
A combinação de:
- logits (z) de uma rede,
- softmax para obter probabilidades (p),
- entropia cruzada para comparar (p) com os rótulos,
forma uma narrativa probabilística e de otimização bem definida:
- A softmax define uma distribuição categórica condicional (p(y \mid x)).
- A entropia cruzada corresponde à estimação por máxima verossimilhança (maximum likelihood estimation).
- Os gradientes são simples e numericamente estáveis quando implementados com log-sum-exp.
Gradientes: por que softmax + entropia cruzada é conveniente
O treinamento usa Descida do Gradiente (Gradient Descent) e Retropropagação (Backpropagation), que exigem derivadas.
O jacobiano (Jacobian) da softmax (derivada geral)
Seja (p = \mathrm{softmax}(z)). A derivada de (p_i) em relação a (z_k) é:
[ \frac{\partial p_i}{\partial z_k} = p_i (\delta_{ik} - p_k) ]
onde (\delta_{ik}) é 1 se (i=k), caso contrário 0.
Em forma matricial, o jacobiano é:
[ J = \mathrm{diag}(p) - pp^\top ]
Isso captura dois comportamentos-chave:
- Aumentar (z_k) aumenta (p_k)
- Aumentar (z_k) diminui todos os outros (p_i) porque as probabilidades precisam somar 1
A simplificação clássica: gradiente da entropia cruzada em relação aos logits
Quando a entropia cruzada é usada com softmax, o gradiente se simplifica drasticamente.
Seja (p = \mathrm{softmax}(z)) e a perda para um exemplo seja:
[ \mathcal{L} = -\sum_i y_i \log p_i ]
Então:
[ \frac{\partial \mathcal{L}}{\partial z_i} = p_i - y_i ]
Este é um dos resultados mais importantes na prática de deep learning:
- O gradiente é simplesmente (probabilidade prevista − probabilidade-alvo).
- Isso é eficiente, estável e fácil de implementar em forma vetorizada (vectorized form).
Intuição
- Se o modelo atribui probabilidade demais a uma classe ((p_i > y_i)), o gradiente empurra (z_i) para baixo.
- Se atribui probabilidade de menos ((p_i < y_i)), o gradiente empurra (z_i) para cima.
- Para a classe correta (t), (y_t=1), então o gradiente é (p_t - 1), incentivando (p_t) a se aproximar de 1.
Softmax vs. sigmoide (e quando usar cada uma)
A softmax é frequentemente contrastada com a Função Sigmoide (Sigmoid Function):
- Sigmoide mapeia um único logit para ((0,1)). Comum para classificação binária (binary classification) ou problemas multirrótulo (multi-label) (rótulos independentes).
- Softmax mapeia um vetor de logits para uma distribuição de probabilidade que soma 1. Comum para problemas multiclasse (rótulo único) (multiclass (single-label)), em que as classes são mutuamente exclusivas.
Exemplos:
- Imagem é gato vs cachorro (binário): sigmoide (ou softmax com 2 classes).
- Imagem é gato, cachorro, cavalo (exatamente um): softmax sobre 3 classes.
- Imagem pode conter gato e cachorro simultaneamente (multirrótulo): sigmoides independentes por rótulo.
Padrões práticos de implementação
1) Treinamento: passe logits para a entropia cruzada (recomendado)
Em vez de:
p = softmax(logits)loss = -sum(y * log(p))
use uma perda de biblioteca que consome logits:
- PyTorch:
F.cross_entropy(logits, targets) - TensorFlow:
tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits)
Isso evita problemas numéricos e geralmente é mais rápido.
2) Inferência (inference): softmax para probabilidades, argmax para classe
No momento da inferência, você pode querer:
- classe prevista:
argmax(logits)(a softmax não é estritamente necessária) - probabilidades previstas:
softmax(logits)(para estimativas de confiança, limiares ou lógica downstream)
3) Probabilidades top-k (top-k)
A softmax é frequentemente usada para calcular as (k) classes mais prováveis:
p = softmax(logits)
topk = np.argsort(p)[::-1][:k]
Para (K) grande, muitos sistemas usam “top-k nos logits” otimizado e calculam softmax apenas sobre os principais candidatos se probabilidades exatas não forem necessárias.
Softmax em atenção (conexão breve)
A softmax também aparece em mecanismos de atenção (não apenas em classificadores). Na atenção por produto escalar escalado (scaled dot-product attention), a softmax normaliza pontuações de similaridade em pesos que somam 1, produzindo uma combinação convexa de valores. As mesmas preocupações de estabilidade numérica se aplicam, então implementações subtraem o máximo por linha antes de exponenciar.
(Veja também: Arquitetura Transformer.)
Armadilhas comuns e considerações
Excesso de confiança e calibração
Redes neurais treinadas com softmax + entropia cruzada podem ficar excessivamente confiantes, especialmente sob mudança de distribuição (distribution shift). O escalonamento de temperatura ((T>1)) é um método comum de calibração aplicado aos logits antes da softmax.
Saturação e gradientes pequenos
Quando um logit domina, as saídas da softmax podem ficar extremamente concentradas, e os sinais de aprendizado para classes não verdadeiras podem ficar muito pequenos. Boa inicialização, regularização (regularization), suavização de rótulos (label smoothing) e otimização bem ajustada podem ajudar na prática.
Não aplique softmax duas vezes
Alguns erros acontecem quando usuários aplicam softmax no modelo e depois passam probabilidades para uma perda que espera logits. Muitas funções de perda de bibliotecas esperam logits; aplicar softmax antes pode degradar a estabilidade numérica e o aprendizado.
Resumo
- Softmax mapeia logits (z) para uma distribuição de probabilidade: (\mathrm{softmax}(z)_i = \frac{e^{z_i}}{\sum_j e^{z_j}}).
- Ela é invariante a deslocamento, permitindo computação numericamente estável ao subtrair (\max(z)).
- A temperatura (T) controla a concentração da distribuição: menor (T) → mais concentrada; maior (T) → mais uniforme.
- Para estabilidade e eficiência, use log-sum-exp e implementações fundidas como “softmax cross-entropy with logits”.
- Com Perda de Entropia Cruzada, o gradiente em relação aos logits se simplifica para: [ \frac{\partial \mathcal{L}}{\partial z} = p - y ] o que é uma razão central para a softmax ser tão amplamente usada em classificação multiclasse.