No desenvolvimento de modelos de deep learning, frequentemente focamos na arquitetura da rede ou na escolha da função de perda, negligencinado parâmetros sutis que controlam a distribuição das saídas. O parâmetro de Temperatura (T) no Softmax é um desses componentes críticos. Ele atua como um regulador da "confiança" do modelo, impactando diretamente áreas como destilação de conhecimento, calibração de incerteza e robustez adversarial.
1. Fundamentos Matemáticos e Intuição
A função Softmax tradicional converte um vetor de pontuações brutas (logits) em uma distribuição de probabilidade. A inclusão da temperatura modifica a fórmula da seguinte forma:
softmax(z_i, T) = exp(z_i / T) / Σ exp(z_j / T)
O impacto de T na distribuição é determinante:
- T < 1 (Baixa temperatura): Aumenta o contraste entre as probabilidades. A maior pontuação torna-se muito próxima de 1, resultando em uma distribuição "aguda" (similar ao argmax).
- T = 1: Softmax padrão.
- T > 1 (Alta temperatura): Suaviza a distribuição. As probabilidades tornam-se mais uniformes, permitindo que o modelo "enxergue" melhor as relações entre classes secundárias.
Viusalização Prática com PyTorch 2.3
O código abaixo demonstra como diferentes valores de T alteram a percepção do modelo sobre os mesmos logits:
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
def analisar_temperaturas(logits_entrada, lista_t):
resultados = {}
for t in lista_t:
probabilidades = F.softmax(logits_entrada / t, dim=-1)
resultados[t] = probabilidades
return resultados
# Exemplo com 3 classes
logits = torch.tensor([1.5, 3.2, 4.8])
temps = [0.2, 1.0, 5.0]
distribuicoes = analisar_temperaturas(logits, temps)
for t, prob in distribuicoes.items():
print(f"Temperatura {t}: {prob.numpy()}")
2. Aplicação em Destilação de Conhecimento (Knowledge Distillation)
Na destilação de conhecimento, o objetivo é transferir o aprendizado de um modelo complexo (professor) para um modelo leve (estudante). Usar uma temperatura elevada (geralmente T entre 2 e 8) é essencial para revelar as "probabilidades suaves" que contêm informações sobre a similaridade entre classes.
def loss_destilacao(saida_estudante, saida_professor, alvos_reais, temp, alpha=0.3):
# Perda suave (KL Divergence)
p_suave_professor = F.softmax(saida_professor / temp, dim=-1)
log_p_suave_estudante = F.log_softmax(saida_estudante / temp, dim=-1)
perda_kd = F.kl_div(log_p_suave_estudante, p_suave_professor, reduction='batchmean') * (temp ** 2)
# Perda padrão (Cross Entropy)
perda_ce = F.cross_entropy(saida_estudante, alvos_reais)
return alpha * perda_kd + (1 - alpha) * perda_ce
3. Calibração de Modelos via Temperature Scaling
Redes neurais modernas tendem a ser "superconfiantes", atribuindo probabilidades altas mesmo a predições incorretas. O Temperature Scaling é uma técnica de pós-processamento que ajusta T em um conjunto de validação para alinhar a confiança do modelo com a precisão real (reduzindo o Expected Calibration Error - ECE).
Implementação de um Wrapper de Calibração
class ModeloCalibrado(torch.nn.Module):
def __init__(self, modelo_base):
super().__init__()
self.modelo = modelo_base
# O parâmetro de temperatura é treinado separadamente
self.temperatura = torch.nn.Parameter(torch.ones(1) * 1.3)
def forward(self, x):
logits = self.modelo(x)
return self.ajustar_logits(logits)
def ajustar_logits(self, logits):
# Garante que a temperatura seja sempre positiva
temp_ajustada = self.temperatura.clamp(min=1e-4)
return logits / temp_ajustada
def otimizar_temperatura(modelo, val_loader):
# Otimização apenas do parâmetro 'temperatura' usando LBFGS
param_temp = [modelo.temperatura]
otimizador = torch.optim.LBFGS(param_temp, lr=0.01, max_iter=50)
def closure():
otimizador.zero_grad()
perda_total = 0
for imagens, rotulos in val_loader:
previsoes = modelo(imagens)
perda = F.cross_entropy(previsoes, rotulos)
perda.backward()
perda_total += perda
return perda_total
otimizador.step(closure)
4. Robustez em Treinamento Adversarial
No contexto de ataques adversariais, a temperatura pode ser usada para suavizar as superfícies de decisão. Ao gerar exemplos adversariais (como via PGD - Projected Gradient Descent), o ajuste de T pode tornar o processo de otimização mais estável, dificultando que o ataque encontre gradientes exploráveis.
def pgd_com_temperatura(modelo, dados, alvo, epsilon=0.03, alpha=0.01, passos=15, temp=1.5):
dados_adv = dados.clone().detach().requires_grad_(True)
for _ in range(passos):
saida = modelo(dados_adv)
# Aplicar temperatura durante a geração do ataque
perda = F.cross_entropy(saida / temp, alvo)
perda.backward()
with torch.no_grad():
gradiente = dados_adv.grad.sign()
dados_adv = dados_adv + alpha * gradiente
eta = torch.clamp(dados_adv - dados, min=-epsilon, max=epsilon)
dados_adv = torch.clamp(dados + eta, min=0, max=1).detach_()
dados_adv.requires_grad_(True)
return dados_adv
Estratégias de Ajuste
Para obter os melhores resultados, considere os seguintes pontos na escolha de T:
- Incerteza de Dados: Em datasets com muito ruído, temperaturas mais altas (T > 1.5) costumam prevenir o overfitting às etiquetas ruidosas.
- Complexidade da Classe: Se as classes forem muito parecidas visualmente, aumente a temperatura na destilação para capturar as nuances compartilhadas.
- Estágio do Treinamento: É possível utilizar um scheduler de temperatura, começando com T alto para exploração e reduzindo para T=1 no final para refinamento.