Vai al contenuto principale

Funzione di attivazione Softmax in Python: guida completa

Scopri come la funzione di attivazione softmax trasforma i logits in probabilità per la classificazione multi-classe. Confronta softmax vs sigmoid e implementala in Python con TensorFlow e PyTorch.
· 12 min leggi

Scopri con l'IA

Le funzioni di attivazione sono la spina dorsale delle reti neurali. Sono componenti fondamentali che introducono non linearità e consentono a queste reti di apprendere pattern complessi. La funzione di attivazione softmax è importante, soprattutto quando si affrontano problemi di classificazione multi-classe.

Sebbene alternative come Sigmoid e ReLU abbiano casi d’uso specifici, softmax è più adatta a gestire situazioni in cui gli output devono essere interpretati come probabilità su classi mutuamente esclusive.

La funzione di attivazione softmax trasforma un intero vettore di numeri in una distribuzione di probabilità. Questa caratteristica la rende indispensabile per i compiti in cui bisogna classificare gli input in una tra più possibili categorie.

Dai sistemi di riconoscimento delle immagini che identificano migliaia di categorie di oggetti ai modelli di elaborazione del linguaggio naturale che predicono la parola successiva in una frase, softmax fornisce le basi matematiche per prendere decisioni tra più possibilità.

In questo articolo vedremo cos’è la funzione di attivazione softmax, come funziona matematicamente e quando dovresti usarla nelle tue architetture di reti neurali. Vedremo anche implementazioni pratiche in Python.

Che cos’è la funzione di attivazione Softmax?

La funzione di attivazione Softmax è una funzione matematica che trasforma un vettore di output grezzi del modello, detti logits, in una distribuzione di probabilità. In parole semplici, prende un insieme di numeri e li converte in probabilità che sommano a 1.

A differenza di alcune funzioni di attivazione che operano su singoli valori in modo indipendente, softmax lavora su un intero vettore di valori, trasformandoli collettivamente in una distribuzione di probabilità in cui tutti gli elementi sommano esattamente a 1.

Nel contesto delle reti neurali, softmax viene in genere applicata allo strato finale di una rete progettata per la classificazione multi-classe. Quando abbiamo più possibili categorie e vogliamo che il modello indichi la probabilità di ciascuna categoria, la funzione di attivazione softmax è la scelta standard.

Come funziona la funzione softmax?

Gli output grezzi dello strato finale di una rete neurale sono spesso chiamati "logits". Questi valori possono variare da meno infinito a più infinito e non hanno un’interpretazione probabilistica diretta. La funzione di attivazione softmax trasforma questi logits in una forma più interpretabile:

  1. Calcolando l’esponenziale di ciascun valore in input (che garantisce che tutti i valori siano positivi).
  2. Dividendo ciascun esponenziale per la somma di tutti gli esponenziali (che garantisce che gli output sommino a 1).

Questa trasformazione è cruciale perché ci permette di interpretare l’output della rete come una distribuzione di probabilità. Ad esempio, se una rete neurale classifica immagini in tre categorie (gatto, cane, uccello), l’output softmax potrebbe essere [0,7, 0,2, 0,1], indicando il 70% di probabilità per gatto, 20% per cane e 10% per uccello.

La funzione di attivazione softmax svolge un ruolo fondamentale nel creare distribuzioni di probabilità valide perché:

  • Garantisce che tutti i valori in output siano compresi tra 0 e 1.
  • Garantisce che tutti gli output sommino esattamente a 1.
  • Preserva l’ordinamento dei valori in input (input maggiori producono probabilità maggiori).
  • Accentua le differenze tra i valori più grandi e sopprime le differenze tra quelli più piccoli.

softmax activation function

Funzione di attivazione Softmax

La visualizzazione sopra mostra come la funzione di attivazione softmax trasforma logits grezzi (i valori in input 2,0, 1,0 e 0,5) in una distribuzione di probabilità (0,7, 0,2 e 0,1). La formula all’interno del riquadro softmax rappresenta come ciascuna probabilità in output è calcolata prendendo l’esponenziale di un valore in input e dividendolo per la somma di tutti gli esponenziali. 

Le proprietà chiave evidenziate a destra indicano perché softmax è utile per i problemi di classificazione multi-classe. Nella prossima sezione vedremo la formula matematica e come funziona.

Formula della funzione di attivazione Softmax e come funziona

Ora che sappiamo cos’è la funzione di attivazione softmax, vediamo la formulazione matematica e come trasforma gli input in distribuzioni di probabilità.

La funzione di attivazione softmax può essere espressa matematicamente come:

Dove:

  • ​zi è il valore in input (logit) per la classe i
  • ezi è la funzione esponenziale applicata a zi (anche scritta come exp(zi ​))
  • K è il numero totale di classi
  • Il denominatore somma gli esponenziali di tutti i valori in input, assicurando che i valori in output sommino a 1

La funzione di attivazione softmax segue questi passaggi per trasformare un vettore di input in una distribuzione di probabilità:

  1. Calcolare gli esponenziali: per prima cosa si calcola l’esponenziale (ex) di ciascun valore in input. Questo passaggio garantisce che tutti i valori siano positivi, dato che ex > 0 per ogni numero reale x
  2. Sommare gli esponenziali: si calcola la somma di tutti i valori esponenziali dal passaggio 1.
  3. Normalizzare: si divide ciascun valore esponenziale per la somma calcolata al passaggio 2. Questa normalizzazione garantisce che tutti gli output siano compresi tra 0 e 1 e sommino esattamente a 1.

Applichiamo ora la formula della funzione di attivazione softmax a un semplice esempio per vedere come funziona in pratica.

Supponiamo di avere una rete neurale con tre neuroni di output per un problema di classificazione a tre classi (ad es., identificare se un’immagine contiene un gatto, un cane o un uccello). Dopo il calcolo finale, la rete produce i seguenti logits: z = [2,0, 1,0, 0,5].

Per convertire questi logits in probabilità usando la funzione softmax:

  1. Calcolare gli esponenziali:
    • e^2,0 = 7,389
    • e^1,0 = 2,718
    • e^0,5 = 1,648
  2. Sommare gli esponenziali:
    • 7,389 + 2,718 + 1,648 = 11,755
  3. Normalizzare:
    • P(classe 1) = 7,389 / 11,755 ≈ 0,628 ovvero 62,8%
    • P(classe 2) = 2,718 / 11,755 ≈ 0,231 ovvero 23,1%
    • P(classe 3) = 1,648 / 11,755 ≈ 0,140 ovvero 14,0%

La risultante distribuzione di probabilità [0,628, 0,231, 0,140] somma a 1, con la probabilità più alta assegnata alla classe corrispondente al valore di logit più alto. Questo esempio dimostra come la funzione di attivazione softmax preservi l’ordinamento dei valori in input trasformandoli in una distribuzione di probabilità valida.

Nota come i valori originali in input (2,0, 1,0, 0,5) abbiano mantenuto il loro ordinamento relativo nelle probabilità in output, ma le differenze tra loro siano state accentuate. Questa proprietà rende softmax particolarmente utile nei compiti di classificazione in cui vogliamo identificare la classe più probabile con sicurezza.

Nella prossima sezione vedremo i diversi modi per implementare la funzione di attivazione softmax usando Python.

Implementare la funzione di attivazione Softmax in Python

Ora che abbiamo compreso la teoria dietro la funzione di attivazione softmax, vediamo come implementarla in Python. Partiremo scrivendo una funzione softmax da zero con NumPy, poi vedremo come usarla con framework di deep learning popolari come TensorFlow/Keras e PyTorch.

Scrivere softmax da zero con NumPy

Prima di passare ai framework, è importante capire come implementare la funzione di attivazione softmax da zero. Questo aiuta a costruire intuizione su cosa avviene sotto il cofano.

import numpy as np

def softmax(x):
    """
    Compute softmax values for each set of scores in x.
    
    Args:
        x: Input array of shape (batch_size, num_classes) or (num_classes,)
        
    Returns:
        Softmax probabilities of same shape as input
    """
    # For numerical stability, subtract the maximum value from each input vector
    # This prevents overflow when calculating exp(x)
    shifted_x = x - np.max(x, axis=-1, keepdims=True)
    
    # Calculate exp(x) for each element
    exp_x = np.exp(shifted_x)
    
    # Calculate the sum of exp(x) for normalization
    sum_exp_x = np.sum(exp_x, axis=-1, keepdims=True)
    
    # Normalize to get probabilities
    probabilities = exp_x / sum_exp_x
    
    return probabilities

Questa implementazione segue esattamente la formula della funzione di attivazione softmax, con un’aggiunta importante: sottraiamo il valore massimo da ciascun vettore di input prima dell’esponenziazione. 

Questa operazione di "shift" non cambia il risultato matematico ma aiuta a prevenire overflow numerici, che possono verificarsi quando si calcolano esponenziali di numeri grandi.

Testiamo la nostra implementazione con un esempio semplice:

# Sample logits from a neural network (batch of 2 examples, 3 classes each)
logits = np.array([
    [2.0, 1.0, 0.5],  # First example
    [3.0, 2.0, 1.0]   # Second example
])

probabilities = softmax(logits)
print("Logits:\n", logits)
print("\nSoftmax probabilities:\n", probabilities)
print("\nSum of probabilities (should be 1 for each example):", np.sum(probabilities, axis=1))

Output:

Eseguendo il codice sopra, vedremo che la somma delle probabilità per ciascun esempio è pari a 1, confermando che la nostra implementazione di softmax produce distribuzioni di probabilità valide. Per il primo esempio, la probabilità più alta corrisponde al logit più alto (2,0), e lo stesso vale per il secondo esempio.

Usare softmax in TensorFlow/Keras

TensorFlow e Keras rendono semplice utilizzare la funzione di attivazione softmax nelle tue reti neurali. Costruiamo passo passo un semplice classificatore per il dataset MNIST.

Per prima cosa, importiamo le librerie necessarie e carichiamo il dataset:

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, Softmax
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
import numpy as np

# Load and preprocess the MNIST dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# Normalize pixel values to be between 0 and 1
x_train, x_test = x_train / 255.0, x_test / 255.0

# One-hot encode the labels
y_train_one_hot = tf.keras.utils.to_categorical(y_train, 10)
y_test_one_hot = tf.keras.utils.to_categorical(y_test, 10)

Il dataset MNIST contiene immagini in scala di grigi 28x28 di cifre scritte a mano (0-9). Normalizziamo i valori dei pixel tra 0 e 1 per migliorare la dinamica dell’addestramento e convertiamo le etichette in one-hot encoding, che è il formato preferito per gli output softmax.

Ora creiamo un modello di rete neurale con uno strato di output softmax:

# Method 1: Using softmax as the activation function in the final layer
model1 = Sequential([
    Flatten(input_shape=(28, 28)),  # Convert 28x28 images to 784-length vectors
    Dense(128, activation='relu'),   # Hidden layer with ReLU activation
    Dense(10, activation='softmax')  # Output layer with softmax activation
])

# Method 2: Using a separate Softmax layer
model2 = Sequential([
    Flatten(input_shape=(28, 28)),
    Dense(128, activation='relu'),
    Dense(10),  # Linear output (logits)
    Softmax()   # Separate softmax layer
])

Qui mostriamo due modi equivalenti per incorporare la funzione di attivazione softmax in una rete neurale:

  • Metodo 1: specificare direttamente 'softmax' come funzione di attivazione nello strato Dense finale
  • Metodo 2: aggiungere uno strato Softmax separato dopo lo strato Dense che produce logits grezzi

Entrambi gli approcci producono risultati identici, ma il secondo rende più esplicita la separazione tra logits e probabilità, utile in alcuni scenari.

Successivamente, compiliamo e addestriamo il modello:

# Compile the model
model1.compile(
    optimizer='adam',
    loss='categorical_crossentropy',  # This loss works well with softmax
    metrics=['accuracy']
)

# Print model summary
print("Model with softmax activation:")
model1.summary()

# Train the model
print("\nTraining the model...")
history = model1.fit(
    x_train, y_train_one_hot,
    epochs=5,
    batch_size=128,
    validation_split=0.1,
    verbose=1
)

Output:

Compiliamo il modello usando la funzione di perdita entropia incrociata categoriale, progettata per funzionare con output softmax. Questa loss misura la differenza tra la distribuzione di probabilità predetta e le etichette one-hot vere. Usiamo l’ottimizzatore Adam, che adatta il learning rate durante l’addestramento.

Dopo l’addestramento, possiamo usare il modello per fare previsioni e visualizzare i risultati:

# Let's check predictions on a sample
sample_idx = 42
sample_image = x_test[sample_idx]
true_label = y_test[sample_idx]

# Get model predictions (probabilities across all classes)
predictions = model1.predict(sample_image[np.newaxis, ...])

# Visualize the results
plt.figure(figsize=(10, 4))

# Plot the image
plt.subplot(1, 2, 1)
plt.imshow(sample_image, cmap='gray')
plt.title(f"True label: {true_label}")
plt.axis('off')

# Plot the probability distribution
plt.subplot(1, 2, 2)
plt.bar(range(10), predictions[0])
plt.xticks(range(10))
plt.xlabel('Digit')
plt.ylabel('Probability')
plt.title('Softmax Probabilities')

Questo codice seleziona un’immagine di test, la passa attraverso il modello addestrato e visualizza sia l’immagine sia la distribuzione di probabilità risultante dall’output softmax. La barra più alta nel grafico delle probabilità rappresenta la previsione del modello.

Output:

TensorFlow fornisce anche una funzione integrata per applicare direttamente softmax:

# Demonstrate using a custom softmax function in TensorFlow
def custom_softmax(logits):
    """Custom implementation of softmax in TensorFlow"""
    exp_logits = tf.exp(logits - tf.reduce_max(logits, axis=-1, keepdims=True))
    return exp_logits / tf.reduce_sum(exp_logits, axis=-1, keepdims=True)

# Example usage of custom softmax
logits = tf.constant([[2.0, 1.0, 0.5], [3.0, 2.0, 1.0]])
custom_probs = custom_softmax(logits)
tf_probs = tf.nn.softmax(logits)

print("\nCustom softmax:", custom_probs.numpy())
print("TensorFlow softmax:", tf_probs.numpy())

Output:

Questo esempio confronta un’implementazione personalizzata di softmax con la funzione integrata di TensorFlow tf.nn.softmax(). Entrambe dovrebbero produrre risultati identici. L’implementazione personalizzata include anche l’accorgimento di stabilità numerica di sottrarre il valore massimo prima dell’esponenziazione.

Usare Softmax in PyTorch

Ora implementiamo un modello simile usando PyTorch e il dataset CIFAR-10. Inizieremo importando le librerie e configurando i dati, come mostrato sotto:

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np

# Set the device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# Load and preprocess the CIFAR-10 dataset
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # Normalize RGB channels
])

# Load a small subset of the CIFAR-10 dataset for demonstration
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,
                                         shuffle=False, num_workers=2)

# Define the class names for CIFAR-10
classes = ('plane', 'car', 'bird', 'cat', 'deer',
           'dog', 'frog', 'horse', 'ship', 'truck')

Il codice sopra configura PyTorch per usare l’accelerazione GPU se disponibile, carica il dataset CIFAR-10 (che contiene immagini a colori 32x32 in 10 classi) e prepara i data loader per training e test.

Successivamente, definiamo una semplice rete neurale convoluzionale come mostrato di seguito:

# Define a simple convolutional neural network
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        # Convolutional layers
        self.conv1 = nn.Conv2d(3, 16, 3, padding=1)
        self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
        self.pool = nn.MaxPool2d(2, 2)
        
        # Fully connected layers
        self.fc1 = nn.Linear(32 * 8 * 8, 128)
        self.fc2 = nn.Linear(128, 10)  # 10 classes in CIFAR-10
        
        # Activation functions
        self.relu = nn.ReLU()
        
        # Note: We don't define softmax here as it will be applied with the loss function
    
    def forward(self, x):
        # Convolutional layers with ReLU and pooling
        x = self.pool(self.relu(self.conv1(x)))  # -> 16x16x16
        x = self.pool(self.relu(self.conv2(x)))  # -> 8x8x32
        
        # Flatten the output
        x = x.view(-1, 32 * 8 * 8)
        
        # Fully connected layers
        x = self.relu(self.fc1(x))
        x = self.fc2(x)  # Raw logits output
        
        # Note: No softmax here, as PyTorch's CrossEntropyLoss applies it internally
        return x

Questa CNN elabora le immagini RGB 32x32 attraverso strati convoluzionali, applica l’attivazione ReLU e il pooling e termina con strati fully connected. Notare che il modello non include uno strato softmax nel forward pass. Invece, produce logits grezzi.

Questo è un pattern comune in PyTorch perché la funzione CrossEntropyLoss usata durante l’addestramento applica internamente softmax prima di calcolare la loss, il che è più stabile numericamente. 

Vediamo anche come includere esplicitamente softmax se necessario:

# Applying softmax within the model
class ModelWithSoftmax(nn.Module):
    def __init__(self):
        super(ModelWithSoftmax, self).__init__()
        self.features = SimpleCNN()
        self.softmax = nn.Softmax(dim=1)
    
    def forward(self, x):
        logits = self.features(x)
        probabilities = self.softmax(logits)
        return probabilities

Definiamo due varianti di modello: SimpleCNN restituisce logits grezzi, mentre ModelWithSoftmax applica esplicitamente softmax per produrre probabilità. Per l’addestramento, usiamo SimpleCNN con CrossEntropyLoss, che è l’approccio standard in PyTorch.

Definiamo una funzione di training:

# Create the model and move it to the device 
model = SimpleCNN().to(device) 
# Define loss function and optimizer 
criterion = nn.CrossEntropyLoss()  # Combines LogSoftmax and NLLLoss 
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
# Train the model (only a few epochs for demonstration)
def train_model(epochs=2):
    for epoch in range(epochs):
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data[0].to(device), data[1].to(device)
            
            # Zero the parameter gradients
            optimizer.zero_grad()
            
            # Forward + backward + optimize
            outputs = model(inputs)  # These are logits (pre-softmax)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            
            running_loss += loss.item()
            if i % 100 == 99:
                print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 100:.3f}')
                running_loss = 0.0
    
    print('Finished Training')

Infine, creiamo una funzione per visualizzare le previsioni del modello:

# Function to display predictions with softmax probabilities
def show_prediction_example():
    # Get a batch of test images
    dataiter = iter(testloader)
    images, labels = next(dataiter)
    
    # Select a single image
    img = images[0].to(device)
    label = labels[0]
    
    # Get the model's prediction (logits)
    with torch.no_grad():
        logits = model(img.unsqueeze(0))
    
    # Apply softmax to get probabilities
    probabilities = torch.nn.functional.softmax(logits, dim=1)
    
    # Plot the image and probabilities
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
    
    # Show the image
    img_np = img.cpu().numpy()
    img_np = np.transpose(img_np, (1, 2, 0))
    # Denormalize the image for display
    img_np = img_np * 0.5 + 0.5
    ax1.imshow(img_np)
    ax1.set_title(f"True label: {classes[label]}")
    ax1.axis('off')
    
    # Show the probabilities
    probs = probabilities[0].cpu().numpy()
    ax2.bar(range(10), probs)
    ax2.set_xticks(range(10))
    ax2.set_xticklabels(classes, rotation=45)
    ax2.set_xlabel('Class')
    ax2.set_ylabel('Probability')
    ax2.set_title('Softmax Probabilities')
    
    plt.tight_layout()

Questa funzione mostra come ottenere le probabilità softmax da un modello addestrato in fase di inference. Passa un’immagine attraverso il modello per ottenere i logits, applica manualmente softmax usando torch.nn.functional.softmax() e poi visualizza sia l’immagine sia la distribuzione di probabilità risultante.

Ora addestriamo il modello:

train_model()

Output:

Facciamo una previsione e vediamo come si presentano le probabilità per un’immagine di test:

show_prediction_example()

Output:

Nella prossima sezione, vedremo gli scenari specifici in cui softmax è la scelta ottimale, quando usare la funzione di attivazione softmax e applicazioni reali in vari modelli di deep learning.

Quando usare la funzione di attivazione Softmax?

Capire quando usare la funzione di attivazione softmax è importante per progettare reti neurali efficaci. La funzione di attivazione softmax trova la sua principale applicazione nello strato di output di reti neurali progettate per compiti di classificazione.

Softmax per la classificazione multi-classe

Softmax è la scelta standard quando il modello deve classificare gli input in una tra più categorie mutuamente esclusive. Esempi comuni includono:

  • Classificazione di immagini (identificazione di oggetti nelle foto)
  • Categorizzazione di documenti (assegnazione di argomenti a testi)
  • Named entity recognition (identificazione di nomi di persona, luoghi, ecc.)
  • Riconoscimento vocale (mappatura dell’audio in testo)

Interpretazione probabilistica e punteggi di confidenza

Quando vogliamo che il modello produca probabilità e non solo predizioni di classe, softmax fornisce un’interpretazione probabilistica della confidenza del modello su tutte le possibili classi.

Softmax nel reinforcement learning e nei meccanismi di attenzione

Nel reinforcement learning e nei problemi di decisione sequenziali, softmax può essere usata per convertire i valori delle azioni in una distribuzione di probabilità per la selezione delle azioni.

Le moderne architetture basate su transformer usano softmax per distribuire l’attenzione sulle diverse parti della sequenza di input.

La solida base matematica e l’intuitiva interpretazione probabilistica rendono la funzione di attivazione softmax particolarmente adatta ai problemi di classificazione con classi mutuamente esclusive.

Modelli di deep learning

Diverse architetture di deep learning usano la funzione di attivazione softmax. 

Reti di classificazione di immagini come ResNet, VGG e Inception usano tutte softmax nel loro strato finale per classificare le immagini in migliaia di categorie. Ad esempio, i modelli addestrati su ImageNet hanno tipicamente uno strato softmax da 1000 unità corrispondenti a 1000 categorie di oggetti.

Nel language modeling, i modelli basati su RNN usano softmax per predire la parola successiva in una sequenza da un vocabolario che può contenere decine di migliaia di parole.

Le moderne architetture NLP come BERT, GPT e T5 usano softmax in più componenti:

  • Nei meccanismi di attenzione per determinare quanta attenzione porre su diverse parti dell’input
  • Nello strato di classificazione finale per compiti come analisi del sentiment o classificazione di documenti

I Variational Autoencoder (VAE) e alcune GAN (Generative Adversarial Networks) usano softmax nei loro componenti discriminatori o per la modellazione di variabili latenti categoriali.

Nella prossima sezione, vedremo le differenze tra la funzione di attivazione softmax e la funzione di attivazione sigmoid.

Softmax vs Sigmoid

La funzione sigmoid, definita come σ(x) = 1/(1+e^(-x)), trasforma un singolo numero reale in un valore compreso tra 0 e 1. Al contrario, la funzione di attivazione softmax opera su un vettore di numeri, convertendoli in una distribuzione di probabilità.

Ecco le differenze fondamentali tra queste due funzioni di attivazione:

Dimensioni di input e output

  • Sigmoid: prende un singolo input scalare e produce un singolo output scalare tra 0 e 1.
  • Softmax: prende un vettore di n input e produce un vettore di n output che sommano a 1.

Interpretazione probabilistica

  • Sigmoid: l’output rappresenta la probabilità di un singolo evento binario (ad es., "Questa email è spam?").
  • Softmax: gli output rappresentano probabilità su più classi mutuamente esclusive (ad es., "Quale cifra da 0 a 9 è questa?").

Indipendenza degli output

  • Sigmoid: quando usata su più neuroni, ogni output è indipendente dagli altri. Più output possono essere tutti alti o tutti bassi.
  • Softmax: gli output sono interdipendenti—se una probabilità aumenta, le altre devono diminuire per mantenere la somma a 1.

Relazione matematica

Interessante notare che la funzione sigmoid è in realtà un caso particolare della funzione di attivazione softmax quando ci sono solo due classi. Per questo sigmoid è spesso chiamata "softmax binaria".

Quando usare softmax vs quando usare sigmoid

Scegliere la funzione di attivazione giusta è cruciale per garantire che una rete neurale produca predizioni significative, e la decisione tra softmax e sigmoid dipende dalla natura del compito di classificazione.

Usa sigmoid quando:

  • Risolvi problemi di classificazione binaria (due classi)
  • Ogni output deve essere interpretato in modo indipendente
  • Implementi classificazione multi-etichetta in cui un’istanza può appartenere a più classi contemporaneamente
  • Crei meccanismi di attenzione o gate in reti neurali ricorrenti

Usa softmax quando:

  • Ti occupi di classificazione multi-classe (più di due classi)
  • Le classi sono mutuamente esclusive (un input appartiene esattamente a una classe)
  • Hai bisogno di una vera distribuzione di probabilità su tutti i possibili esiti
  • Implementi lo strato finale della maggior parte delle reti di classificazione di immagini

Per esempio, in una rete neurale che classifica immagini di cifre scritte a mano (0-9), la funzione di attivazione softmax sarebbe appropriata per lo strato di output poiché ogni immagine rappresenta esattamente una cifra. Al contrario, per una rete che rileva più oggetti in un’immagine (ad es., "contiene persona", "contiene auto", "contiene albero"), le attivazioni sigmoid sarebbero più adatte, poiché più oggetti possono essere presenti contemporaneamente.

Ecco una tabella di riferimento rapido che confronta softmax e sigmoid:

Caratteristica

Sigmoid

Softmax

Input

Scalare singolo

Vettore di valori

Intervallo output

Tra 0 e 1

Tra 0 e 1, con somma pari a 1

Caso d’uso

Classificazione binaria

Classificazione multi-classe

Interpretazione output

Probabilità indipendente

Distribuzione di probabilità

Output multipli

Possono essere tutti alti o tutti bassi

Vincolati a sommare a 1

Gradienti

Può soffrire di vanishing gradient

Meno soggetta a problemi di vanishing gradient

Efficienza di training

Si addestra con loss binaria a entropia incrociata

Si addestra con loss categoriale a entropia incrociata

Comprendere la distinzione tra queste funzioni di attivazione è fondamentale per progettare reti neurali efficaci. Sebbene la funzione di attivazione softmax sia la scelta ideale per i problemi di classificazione multi-classe, sigmoid resta preziosa per la classificazione binaria e per i problemi che richiedono probabilità indipendenti.

Nella prossima sezione, vedremo i problemi comuni che sorgono e le considerazioni da fare quando si lavora con le funzioni di attivazione softmax.

Problemi comuni e considerazioni

Quando lavori con la funzione di attivazione softmax nei tuoi modelli di deep learning, diversi problemi possono influire sulle prestazioni e l’affidabilità del modello. Capire questi problemi e sapere come affrontarli ti aiuterà a costruire modelli più robusti.

Sfide di stabilità numerica

La stabilità numerica è una preoccupazione critica quando si usa la funzione di attivazione softmax. L’operazione di esponenziazione nella formula di softmax può portare a overflow o underflow numerici se non gestita correttamente.

Ad esempio, quando si hanno valori di input molto grandi (come 1000 o più), la funzione esponenziale produce numeri estremamente grandi che possono superare il massimo valore rappresentabile in virgola mobile del sistema. Questo porta a errori di overflow, producendo valori "infinity" che rendono l’operazione di divisione finale non definita (NaN - Not a Number).

La soluzione standard, come menzionato nella sezione di implementazione, è sottrarre il valore massimo da tutti gli input prima di applicare la funzione esponenziale. Questo shift non cambia le proporzioni relative dopo la normalizzazione ma mantiene i valori in un intervallo gestibile. 

I moderni framework di deep learning gestiscono internamente questo problema, ma è importante comprenderlo quando si implementano operazioni personalizzate o si fa debug di comportamenti inattesi.

Softmax e iperconfidenza nelle previsioni

Un altro problema comune con la funzione di attivazione softmax è che le reti neurali tendono a diventare eccessivamente fiduciose nelle loro previsioni, anche quando sono sbagliate. Questa iperconfidenza si verifica perché:

  1. La natura esponenziale di softmax amplifica piccole differenze nei logits.
  2. Le moderne reti neurali profonde sono abbastanza potenti da memorizzare perfettamente i dati di training.
  3. La loss a entropia incrociata continua a spingere le probabilità verso 1 per le classi corrette, anche dopo che il modello ha raggiunto una buona accuratezza.

In pratica, questo significa che un modello può assegnare il 99% di probabilità a una previsione in realtà errata. Questo può essere problematico in applicazioni critiche in cui è essenziale una stima affidabile dell’incertezza. Ad esempio, un sistema di diagnosi medica iperconfi-dente in previsioni sbagliate potrebbe portare a decisioni terapeutiche inappropriate.

Il divario tra la confidenza del modello (dalle probabilità softmax) e la sua accuratezza reale è noto come errore di calibrazione. Modelli ben calibrati producono punteggi di confidenza che corrispondono ai loro tassi di accuratezza—se un modello predice eventi con l’80% di confidenza, quegli eventi dovrebbero verificarsi circa l’80% delle volte.

Tecniche di regolarizzazione per migliorare le prestazioni

Fortunatamente, diverse tecniche possono aiutare ad affrontare questi problemi con la funzione di attivazione softmax:

Temperature scaling

Il temperature scaling introduce un parametro T che controlla la "morbidezza" della distribuzione di probabilità. Dividendo i logits per questo parametro di temperatura prima di applicare softmax, puoi regolare quanto la distribuzione risultante sia appuntita o uniforme.

Temperature più alte (T > 1) producono distribuzioni più "morbide" con valori meno estremi, aiutando a ridurre l’iperconfidenza. Temperature più basse (T < 1) rendono la distribuzione più appuntita verso il valore più alto. Il temperature scaling è comunemente usato come tecnica di post-processing dopo l’addestramento per calibrare la confidenza del modello senza influire sul ranking delle classi.

Label smoothing

Il label smoothing sostituisce i vettori target one-hot rigidi con distribuzioni leggermente "smussate". Invece di addestrare il modello a produrre zeri e uno esatti, il label smoothing incoraggia il modello a essere leggermente meno sicuro, puntando a valori come 0,9 per la classe corretta e 0,025 per le classi errate (in un problema a 4 classi).

Addestrando con queste etichette smussate, il modello impara a essere meno sicuro nelle sue previsioni, migliorando la generalizzazione e rendendolo più robusto al rumore nelle etichette. Questa tecnica è diventata pratica standard in molti modelli SOTA di classificazione di immagini.

Dropout e metodi ensemble

Usare il dropout durante l’addestramento e mantenerlo attivo in inference (tecnica chiamata Monte Carlo dropout) consente di campionare più previsioni per lo stesso input e stimare l’incertezza. Se il modello produce previsioni coerenti su più forward pass con pattern di dropout diversi, è probabilmente più certo della sua previsione.

Allo stesso modo, i metodi ensemble combinano le previsioni di più modelli per migliorare le prestazioni e fornire stime di incertezza migliori. Il disaccordo tra i modelli in un ensemble può fungere da misura di incertezza.

Tecniche di calibrazione

Il Platt scaling e altri metodi di calibrazione possono essere applicati dopo l’addestramento per garantire che i punteggi di confidenza da softmax corrispondano a vere probabilità. Questi metodi usano tipicamente un set di validazione per apprendere parametri che mappano gli output originali del modello in probabilità ben calibrate.

Ad esempio, un semplice approccio di temperature scaling (come menzionato sopra) può essere ottimizzato sui dati di validazione per minimizzare l’errore di calibrazione. Approcci più complessi includono la regressione isotonica e il Bayesian binning.

Il collo di bottiglia di softmax

Ricerche recenti hanno identificato una limitazione fondamentale della funzione softmax nota come "softmax bottleneck". Si riferisce al fatto che l’espressività dei modelli linguistici basati su softmax è limitata dal rango della matrice di pesi nello strato finale. In contesti di linguaggio naturale con dipendenze complesse, questo può impedire ai modelli di catturare pienamente le distribuzioni condizionali sottostanti.

Architetture avanzate come Mixture of Softmaxes (MoS) sono state proposte per affrontare questa limitazione usando una combinazione pesata di più distribuzioni softmax.

Essendo consapevole di questi problemi comuni e implementando soluzioni appropriate, puoi migliorare l’affidabilità e le prestazioni dei modelli che usano la funzione di attivazione softmax per i compiti di classificazione.

Conclusione

La funzione di attivazione softmax è un componente essenziale delle reti neurali per i problemi di classificazione multi-classe, trasformando logits grezzi in distribuzioni di probabilità interpretabili. Abbiamo esplorato le sue basi matematiche, l’implementazione in Python, il confronto con sigmoid, i casi d’uso pratici e le tecniche per affrontare sfide comuni come instabilità numerica e iperconfidenza.

Pronto ad approfondire le reti neurali? 

Domande frequenti su Softmax

A cosa serve la funzione di attivazione softmax?

Softmax trasforma gli output di una rete neurale in distribuzioni di probabilità per problemi di classificazione multi-classe con classi mutuamente esclusive.

Qual è la differenza tra le funzioni di attivazione softmax e sigmoid?

Sigmoid produce probabilità indipendenti per esiti binari, mentre softmax crea probabilità interdipendenti che sommano a 1 tra più classi.

Come gestisce la formula di softmax i problemi di stabilità numerica?

L’implementazione stabile di softmax sottrae il valore massimo da tutti gli input prima dell’esponenziazione per evitare overflow senza cambiare il risultato.

Quando dovrei usare softmax invece di altre funzioni di attivazione?

Usa softmax nello strato di output quando classifichi gli input in una tra più categorie mutuamente esclusive, come nella classificazione di immagini o nella categorizzazione di documenti.

Gli output di softmax possono essere interpretati come probabilità?

Sì, gli output di softmax rappresentano probabilità su classi diverse che sommano a 1, con valori più alti che indicano maggiore confidenza in quella classe.

Autore

Rajesh Kumar

Sono una content writer specializzata in data science. Amo creare contenuti su temi di IA/ML/DS. Esploro anche nuovi strumenti di IA e ne scrivo.

Argomenti

Correlato