Chuyển đến nội dung chính

Hàm kích hoạt Softmax trong Python: Hướng dẫn đầy đủ

Tìm hiểu cách hàm kích hoạt softmax chuyển logits thành xác suất cho phân loại đa lớp. So sánh softmax với sigmoid và triển khai trong Python với TensorFlow và PyTorch.
· 12 phút đọc

Khám phá cùng AI

Các hàm kích hoạt là xương sống của mạng nơ-ron. Chúng là những thành phần quan trọng đưa tính phi tuyến vào mô hình và giúp mạng học được các mẫu phức tạp. Hàm kích hoạt softmax đặc biệt quan trọng khi xử lý các bài toán phân loại đa lớp.

Mặc dù các lựa chọn thay thế như Sigmoid và ReLU có những trường hợp sử dụng riêng, softmax phù hợp hơn trong tình huống đầu ra cần được hiểu là xác suất trên các lớp loại trừ lẫn nhau.

Hàm kích hoạt softmax biến đổi toàn bộ một vector số thành một phân phối xác suất. Đặc tính này khiến nó không thể thiếu cho các tác vụ cần phân loại đầu vào vào một trong nhiều hạng mục có thể.

Từ hệ thống nhận dạng hình ảnh phân loại hàng nghìn danh mục đối tượng đến các mô hình xử lý ngôn ngữ tự nhiên dự đoán từ tiếp theo trong câu, softmax cung cấp nền tảng toán học để ra quyết định giữa nhiều khả năng.

Trong bài viết này, chúng ta sẽ tìm hiểu softmax là gì, hoạt động như thế nào về mặt toán học và khi nào bạn nên dùng nó trong kiến trúc mạng nơ-ron của mình. Chúng ta cũng sẽ xem các cách triển khai thực tế bằng Python.

Hàm kích hoạt Softmax là gì?

Hàm kích hoạt Softmax là một hàm toán học biến đổi một vector đầu ra thô của mô hình, còn gọi là logits, thành một phân phối xác suất. Nói đơn giản, nó nhận một tập số và chuyển chúng thành các xác suất có tổng bằng 1.

Không giống một số hàm kích hoạt hoạt động độc lập trên từng giá trị, softmax xử lý toàn bộ vector giá trị, biến đổi chúng đồng thời thành một phân phối xác suất mà tổng các phần tử chính xác bằng 1.

Trong bối cảnh mạng nơ-ron, softmax thường được áp dụng ở tầng cuối của mạng dùng cho phân loại đa lớp. Khi có nhiều hạng mục có thể và chúng ta cần mô hình đưa ra xác suất cho từng hạng mục, softmax là lựa chọn tiêu chuẩn.

Hàm softmax hoạt động như thế nào?

Các đầu ra thô từ tầng cuối của mạng nơ-ron thường được gọi là "logits." Những giá trị này có thể nằm từ âm vô cùng đến dương vô cùng và không mang ý nghĩa xác suất trực tiếp. Hàm kích hoạt softmax biến đổi các logits này thành dạng dễ diễn giải hơn bằng cách:

  1. Lấy hàm mũ của từng giá trị đầu vào (đảm bảo tất cả giá trị dương).
  2. Chia mỗi giá trị mũ cho tổng tất cả các giá trị mũ (đảm bảo đầu ra có tổng bằng 1).

Biến đổi này rất quan trọng vì nó cho phép diễn giải đầu ra của mạng như một phân phối xác suất. Ví dụ, nếu một mạng nơ-ron phân loại ảnh vào ba hạng mục (mèo, chó, chim), đầu ra softmax có thể là [0.7, 0.2, 0.1], biểu thị xác suất 70% cho mèo, 20% cho chó và 10% cho chim.

Hàm kích hoạt softmax đóng vai trò then chốt trong việc tạo ra các phân phối xác suất hợp lệ vì:

  • Nó đảm bảo mọi giá trị đầu ra nằm trong khoảng 0 đến 1.
  • Nó đảm bảo tổng các đầu ra chính xác bằng 1.
  • Nó bảo toàn thứ hạng của các giá trị đầu vào (đầu vào lớn hơn cho xác suất lớn hơn).
  • Nó nhấn mạnh khác biệt giữa các giá trị lớn, đồng thời làm giảm khác biệt giữa các giá trị nhỏ.

softmax activation function

Hàm kích hoạt Softmax

Hình minh họa trên cho thấy cách hàm kích hoạt softmax biến đổi logits thô (các giá trị đầu vào 2.0, 1.0 và 0.5) thành phân phối xác suất (0.7, 0.2 và 0.1). Công thức trong khung softmax biểu diễn cách mỗi xác suất đầu ra được tính bằng cách lấy hàm mũ của một giá trị đầu vào và chia cho tổng tất cả các giá trị mũ. 

Các thuộc tính chính được nêu ở bên phải cho thấy vì sao softmax hữu ích cho các bài toán phân loại đa lớp. Ở phần tiếp theo, chúng ta sẽ xem công thức toán học và cách nó hoạt động.

Công thức hàm kích hoạt Softmax và cách hoạt động

Giờ đây ta đã hiểu softmax là gì, hãy xem biểu thức toán học và cách nó biến đổi đầu vào thành phân phối xác suất.

Công thức hàm kích hoạt softmax có thể được biểu diễn như sau:

Trong đó:

  • ​zi là giá trị đầu vào (logit) cho lớp i
  • ezi là hàm mũ áp dụng cho zi (cũng được viết là exp(zi ​))
  • K là tổng số lớp
  • Mẫu số là tổng các giá trị mũ của toàn bộ đầu vào, đảm bảo tổng các đầu ra bằng 1

Hàm kích hoạt softmax thực hiện các bước sau để biến đổi một vector đầu vào thành phân phối xác suất:

  1. Tính giá trị mũ: Đầu tiên, ta tính hàm mũ (ex) của từng giá trị đầu vào. Bước này đảm bảo mọi giá trị đều dương, vì ex > 0 với mọi số thực x
  2. Cộng các giá trị mũ: Tính tổng tất cả các giá trị mũ từ bước 1.
  3. Chuẩn hóa: Chia mỗi giá trị mũ cho tổng tính ở bước 2. Việc chuẩn hóa này đảm bảo các đầu ra nằm trong khoảng 0–1 và tổng chính xác bằng 1.

Hãy áp dụng công thức softmax cho một ví dụ đơn giản để xem nó hoạt động thế nào trong thực tế.

Giả sử ta có một mạng nơ-ron với ba nơ-ron đầu ra cho bài toán phân loại ba lớp (ví dụ: nhận biết ảnh có mèo, chó hay chim). Sau tính toán cuối cùng, mạng cho ra các logits: z = [2.0, 1.0, 0.5].

Để chuyển các logits này thành xác suất bằng hàm softmax:

  1. Tính giá trị mũ:
    • e^2.0 = 7.389
    • e^1.0 = 2.718
    • e^0.5 = 1.648
  2. Cộng các giá trị mũ:
    • 7.389 + 2.718 + 1.648 = 11.755
  3. Chuẩn hóa:
    • P(lớp 1) = 7.389 / 11.755 ≈ 0.628 hay 62.8%
    • P(lớp 2) = 2.718 / 11.755 ≈ 0.231 hay 23.1%
    • P(lớp 3) = 1.648 / 11.755 ≈ 0.140 hay 14.0%

Phân phối xác suất thu được [0.628, 0.231, 0.140] có tổng bằng 1, với xác suất cao nhất gán cho lớp tương ứng với logit cao nhất. Ví dụ này cho thấy softmax bảo toàn thứ hạng của các giá trị đầu vào trong khi biến chúng thành một phân phối xác suất hợp lệ.

Lưu ý cách các giá trị đầu vào ban đầu (2.0, 1.0, 0.5) giữ nguyên thứ hạng tương đối trong xác suất đầu ra, nhưng khác biệt giữa chúng được nhấn mạnh. Thuộc tính này khiến softmax đặc biệt hữu ích trong các tác vụ phân loại khi ta muốn xác định lớp có khả năng cao nhất với độ tin cậy.

Ở phần tiếp theo, chúng ta sẽ xem các cách triển khai hàm kích hoạt softmax bằng Python.

Triển khai hàm kích hoạt Softmax trong Python

Sau khi nắm lý thuyết đằng sau softmax, hãy xem cách triển khai nó trong Python. Chúng ta sẽ bắt đầu viết softmax từ đầu bằng NumPy, rồi xem cách dùng với các framework học sâu phổ biến như TensorFlow/Keras và PyTorch.

Viết softmax từ đầu bằng NumPy

Trước khi đi vào framework, điều quan trọng là hiểu cách tự triển khai hàm kích hoạt softmax. Điều này giúp xây dựng trực giác về những gì xảy ra bên dưới.

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

Cách triển khai này bám sát công thức softmax, với một bổ sung quan trọng: chúng ta trừ giá trị lớn nhất khỏi mỗi vector đầu vào trước khi lấy hàm mũ. 

Phép “dịch” này không thay đổi kết quả toán học nhưng giúp ngăn tràn số, vốn có thể xảy ra khi tính hàm mũ của các số lớn.

Hãy kiểm thử triển khai của chúng ta với một ví dụ đơn giản:

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

Kết quả:

Khi chạy đoạn mã trên, bạn sẽ thấy tổng xác suất cho mỗi mẫu bằng 1, xác nhận rằng triển khai softmax của chúng ta tạo ra phân phối xác suất hợp lệ. Với ví dụ đầu, xác suất lớn nhất tương ứng với logit lớn nhất (2.0), và tương tự cho ví dụ thứ hai.

Sử dụng softmax trong TensorFlow/Keras

TensorFlow và Keras giúp bạn dùng hàm kích hoạt softmax trong mạng nơ-ron một cách dễ dàng. Hãy xây dựng từng bước một bộ phân loại đơn giản cho tập MNIST.

Trước tiên, nhập các thư viện cần thiết và tải dữ liệu:

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)

Tập MNIST chứa ảnh xám 28x28 pixel của các chữ số viết tay (0-9). Chúng ta chuẩn hóa giá trị pixel về khoảng 0 đến 1 để giúp quá trình huấn luyện tốt hơn, và chuyển nhãn lớp sang dạng one-hot, là định dạng ưa dùng cho đầu ra softmax.

Bây giờ, hãy tạo một mô hình mạng nơ-ron với tầng đầu ra 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
])

Ở đây, chúng ta minh họa hai cách tương đương để đưa softmax vào mạng nơ-ron:

  • Phương pháp 1: Chỉ định trực tiếp 'softmax' làm hàm kích hoạt ở tầng Dense cuối
  • Phương pháp 2: Thêm một tầng Softmax riêng sau tầng Dense xuất logits thô

Cả hai cách cho kết quả giống nhau, nhưng cách thứ hai phân tách rõ ràng giữa logits và xác suất, hữu ích trong một số tình huống nhất định.

Tiếp theo, hãy biên dịch và huấn luyện mô hình:

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

Kết quả:

Chúng ta biên dịch mô hình với hàm mất mát cross-entropy đa lớp, được thiết kế để hoạt động với đầu ra softmax. Hàm mất mát này đo lường khác biệt giữa phân phối xác suất dự đoán và nhãn one-hot thực. Chúng ta dùng bộ tối ưu Adam, tự điều chỉnh tốc độ học trong quá trình huấn luyện.

Sau khi huấn luyện, chúng ta có thể dùng mô hình để dự đoán và trực quan hóa kết quả:

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

Đoạn mã này chọn một ảnh kiểm thử, đưa qua mô hình đã huấn luyện và trực quan hóa cả ảnh lẫn phân phối xác suất từ đầu ra softmax. Cột cao nhất trên biểu đồ xác suất thể hiện dự đoán của mô hình.

Kết quả:

TensorFlow cũng cung cấp hàm tích hợp để áp dụng softmax trực tiếp:

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

Kết quả:

Ví dụ này so sánh một triển khai softmax tùy chỉnh với hàm tích hợp tf.nn.softmax() của TensorFlow. Cả hai phải cho kết quả giống hệt nhau. Triển khai tùy chỉnh cũng bao gồm mẹo ổn định số là trừ giá trị lớn nhất trước khi lấy hàm mũ.

Sử dụng Softmax trong PyTorch

Bây giờ, hãy triển khai một mô hình tương tự bằng PyTorch với tập dữ liệu CIFAR-10. Chúng ta sẽ bắt đầu bằng việc nhập thư viện và thiết lập dữ liệu như dưới đây:

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

Đoạn mã trên thiết lập PyTorch để dùng tăng tốc GPU nếu khả dụng, tải tập CIFAR-10 (chứa ảnh màu 32x32 thuộc 10 lớp), và chuẩn bị các data loader cho huấn luyện và kiểm thử.

Tiếp theo, hãy định nghĩa một mạng nơ-ron tích chập đơn giản như sau:

# 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

Mạng CNN này xử lý ảnh RGB 32x32 qua các tầng tích chập, áp dụng ReLU và pooling, và kết thúc bằng các tầng kết nối đầy đủ. Đáng chú ý, mô hình không có tầng softmax trong đường truyền xuôi. Thay vào đó, nó xuất logits thô.

Đây là cách làm phổ biến trong PyTorch vì hàm CrossEntropyLoss dùng trong huấn luyện sẽ áp dụng softmax nội bộ trước khi tính loss, điều này ổn định số tốt hơn. 

Chúng ta cũng xem cách đưa softmax vào một cách tường minh khi cần:

# 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

Chúng ta định nghĩa hai biến thể mô hình: SimpleCNN xuất logits thô, trong khi ModelWithSoftmax áp dụng softmax tường minh để tạo xác suất. Khi huấn luyện, chúng ta dùng SimpleCNN cùng với CrossEntropyLoss, vốn là cách tiêu chuẩn trong PyTorch.

Hãy định nghĩa hàm huấn luyện:

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

Cuối cùng, hãy tạo một hàm để trực quan hóa dự đoán của mô hình:

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

Hàm này minh họa cách lấy xác suất softmax từ một mô hình đã huấn luyện trong giai đoạn suy luận. Nó đưa ảnh qua mô hình để lấy logits, áp dụng softmax thủ công bằng torch.nn.functional.softmax(), rồi trực quan hóa cả ảnh và phân phối xác suất thu được.

Giờ hãy huấn luyện mô hình:

train_model()

Kết quả:

Hãy dự đoán và xem xác suất hiển thị thế nào cho một ảnh kiểm thử:

show_prediction_example()

Kết quả:

Ở phần tiếp theo, chúng ta sẽ xem các kịch bản cụ thể nơi softmax là lựa chọn tối ưu, xác định khi nào nên dùng hàm kích hoạt softmax, và thảo luận ứng dụng thực tế trong nhiều mô hình học sâu.

Khi nào nên dùng hàm kích hoạt Softmax?

Hiểu khi nào dùng softmax rất quan trọng để thiết kế mạng nơ-ron hiệu quả. Softmax chủ yếu được áp dụng ở tầng đầu ra của các mạng dùng cho bài toán phân loại.

Softmax cho phân loại đa lớp

Softmax là lựa chọn tiêu chuẩn khi mô hình cần phân loại đầu vào vào một trong nhiều hạng mục loại trừ lẫn nhau. Các ví dụ phổ biến gồm:

  • Phân loại hình ảnh (nhận diện đối tượng trong ảnh)
  • Phân loại tài liệu (gán chủ đề cho văn bản)
  • Nhận dạng thực thể có tên (xác định tên người, địa điểm, v.v.)
  • Nhận dạng giọng nói (chuyển âm thanh thành văn bản)

Diễn giải xác suất và điểm tin cậy

Khi cần mô hình xuất ra xác suất thay vì chỉ nhãn lớp, softmax cung cấp cách diễn giải xác suất về mức độ tin cậy của mô hình trên tất cả các lớp có thể.

Softmax trong học tăng cường và cơ chế chú ý

Trong học tăng cường và các bài toán quyết định tuần tự, softmax có thể dùng để chuyển giá trị hành động thành phân phối xác suất chọn hành động.

Các kiến trúc dựa trên transformer hiện đại dùng softmax để phân bổ sự chú ý trên các phần khác nhau của chuỗi đầu vào.

Nền tảng toán học vững chắc và cách diễn giải xác suất trực quan khiến softmax đặc biệt phù hợp với các bài toán phân loại có các lớp loại trừ lẫn nhau.

Các mô hình học sâu

Nhiều kiến trúc học sâu sử dụng hàm kích hoạt softmax. 

Các mạng phân loại ảnh như ResNet, VGG và Inception đều dùng softmax ở tầng cuối để phân loại ảnh vào hàng nghìn danh mục. Ví dụ, các mô hình huấn luyện trên ImageNet thường có tầng softmax 1000 nút tương ứng với 1000 hạng mục đối tượng.

Trong mô hình ngôn ngữ, các mô hình dựa trên RNN dùng softmax để dự đoán từ tiếp theo trong chuỗi từ một vốn từ có thể lên đến hàng chục nghìn từ.

Các kiến trúc NLP hiện đại như BERT, GPT và T5 dùng softmax ở nhiều thành phần:

  • Trong cơ chế chú ý để xác định mức độ tập trung vào các phần khác nhau của đầu vào
  • Ở tầng phân loại cuối cho các tác vụ như phân tích cảm xúc hoặc phân loại tài liệu

Biến đổi Tự mã hóa Biến thể (VAE) và một số Mạng đối sinh (GAN) dùng softmax trong thành phần bộ phân biệt hoặc để mô hình hóa biến ẩn dạng phân loại.

Ở phần tiếp theo, chúng ta sẽ xem sự khác nhau giữa softmax và sigmoid.

Softmax so với hàm kích hoạt Sigmoid

Hàm sigmoid, được định nghĩa là σ(x) = 1/(1+e^(-x)), biến đổi một số thực thành giá trị trong khoảng 0 đến 1. Ngược lại, hàm kích hoạt softmax hoạt động trên một vector số, chuyển chúng thành một phân phối xác suất.

Dưới đây là những khác biệt cơ bản giữa hai hàm kích hoạt này:

Kích thước đầu vào và đầu ra

  • Sigmoid: Nhận một đầu vào vô hướng và cho một đầu ra vô hướng trong khoảng 0 đến 1.
  • Softmax: Nhận một vector n phần tử và cho ra một vector n phần tử có tổng bằng 1.

Diễn giải xác suất

  • Sigmoid: Đầu ra biểu diễn xác suất của một biến cố nhị phân (ví dụ: "Email này có phải spam không?").
  • Softmax: Đầu ra biểu diễn các xác suất trên nhiều lớp loại trừ lẫn nhau (ví dụ: "Đây là chữ số nào từ 0-9?").

Tính độc lập của đầu ra

  • Sigmoid: Khi dùng trên nhiều nơ-ron, mỗi đầu ra độc lập với nhau. Nhiều đầu ra có thể đồng thời cao hoặc đồng thời thấp.
  • Softmax: Các đầu ra phụ thuộc lẫn nhau — nếu một xác suất tăng, các xác suất khác phải giảm để tổng bằng 1.

Mối quan hệ toán học

Thú vị là hàm sigmoid thực ra là trường hợp đặc biệt của softmax khi chỉ có hai lớp. Vì vậy sigmoid thường được gọi là "softmax nhị phân."

Khi nào dùng softmax và khi nào dùng sigmoid

Chọn đúng hàm kích hoạt rất quan trọng để mạng nơ-ron đưa ra dự đoán có ý nghĩa, và quyết định giữa softmax và sigmoid phụ thuộc vào bản chất bài toán phân loại.

Dùng sigmoid khi:

  • Giải quyết bài toán phân loại nhị phân (hai lớp)
  • Mỗi đầu ra cần được diễn giải độc lập
  • Triển khai phân loại đa nhãn, nơi một mẫu có thể thuộc nhiều lớp đồng thời
  • Tạo cơ chế chú ý hoặc cổng trong mạng nơ-ron hồi tiếp

Dùng softmax khi:

  • Xử lý các bài toán phân loại đa lớp (hơn hai lớp)
  • Các lớp loại trừ lẫn nhau (một đầu vào thuộc đúng một lớp)
  • Bạn cần một phân phối xác suất đúng nghĩa trên mọi khả năng
  • Triển khai tầng cuối của hầu hết các mạng phân loại ảnh

Ví dụ, trong mạng phân loại ảnh chữ số viết tay (0-9), softmax phù hợp cho tầng đầu ra vì mỗi ảnh biểu diễn đúng một chữ số. Ngược lại, với mạng phát hiện nhiều đối tượng trong ảnh (ví dụ: "có người", "có ô tô", "có cây"), các kích hoạt sigmoid sẽ phù hợp hơn vì có thể có nhiều đối tượng xuất hiện đồng thời.

Dưới đây là bảng tham chiếu nhanh so sánh softmax và sigmoid:

Tính năng

Sigmoid

Softmax

Đầu vào

Vô hướng

Vector giá trị

Miền giá trị đầu ra

Trong khoảng 0 đến 1

Trong khoảng 0 đến 1, có tổng bằng 1

Trường hợp sử dụng

Phân loại nhị phân

Phân loại đa lớp

Diễn giải đầu ra

Xác suất độc lập

Phân phối xác suất

Nhiều đầu ra

Có thể đồng thời cao hoặc đồng thời thấp

Bị ràng buộc có tổng bằng 1

Gradient

Có thể gặp vấn đề tiêu biến gradient

Ít dễ gặp vấn đề tiêu biến gradient hơn

Hiệu quả huấn luyện

Có thể huấn luyện với hàm mất mát binary cross-entropy

Huấn luyện với hàm mất mát categorical cross-entropy

Hiểu sự khác biệt giữa các hàm kích hoạt này là rất quan trọng để thiết kế mạng nơ-ron hiệu quả. Trong khi softmax là lựa chọn hàng đầu cho phân loại đa lớp, sigmoid vẫn rất hữu ích cho phân loại nhị phân và các bài toán cần xác suất độc lập.

Ở phần tiếp theo, chúng ta sẽ xem các vấn đề thường gặp và những lưu ý khi làm việc với hàm kích hoạt softmax.

Các vấn đề thường gặp và lưu ý

Khi làm việc với softmax trong các mô hình học sâu, có một số thách thức có thể ảnh hưởng đến hiệu năng và độ tin cậy. Hiểu các vấn đề này và cách khắc phục sẽ giúp bạn xây dựng mô hình vững vàng hơn.

Thách thức về ổn định số

Ổn định số là mối quan tâm quan trọng khi dùng softmax. Phép mũ trong công thức softmax có thể dẫn đến tràn hoặc hụt số nếu không xử lý đúng cách.

Chẳng hạn, với các giá trị đầu vào rất lớn (như 1000 trở lên), hàm mũ tạo ra các số cực lớn có thể vượt quá giá trị dấu phẩy động tối đa trên hệ thống của bạn. Điều này dẫn đến lỗi tràn, tạo ra giá trị "vô cực" khiến phép chia cuối cùng cho kết quả không xác định (NaN - Not a Number).

Giải pháp tiêu chuẩn, như đã đề cập ở phần triển khai, là trừ giá trị lớn nhất khỏi tất cả đầu vào trước khi áp dụng hàm mũ. Phép dịch này không thay đổi tỷ lệ tương đối sau khi chuẩn hóa nhưng giữ các giá trị trong phạm vi có thể xử lý. 

Các framework học sâu hiện đại xử lý vấn đề này bên trong, nhưng điều quan trọng là bạn phải hiểu vấn đề khi tự triển khai hoặc gỡ lỗi hành vi bất thường.

Softmax và sự tự tin quá mức trong dự đoán

Một vấn đề thường gặp khác với softmax là mạng nơ-ron có xu hướng quá tự tin vào dự đoán của mình, ngay cả khi chúng sai. Sự tự tin quá mức này xảy ra vì:

  1. Bản chất hàm mũ của softmax khuếch đại các khác biệt nhỏ trong logits.
  2. Các mạng nơ-ron sâu hiện đại đủ mạnh để ghi nhớ hoàn hảo dữ liệu huấn luyện.
  3. Hàm mất mát cross-entropy tiếp tục đẩy xác suất về 1 cho lớp đúng, ngay cả sau khi mô hình đạt độ chính xác tốt.

Trong thực tế, điều này có nghĩa là mô hình có thể gán xác suất 99% cho một dự đoán thực ra sai. Điều này có thể gây vấn đề trong các ứng dụng quan trọng cần ước lượng độ bất định đáng tin cậy. Ví dụ, hệ thống chẩn đoán y khoa quá tự tin với dự đoán sai có thể dẫn đến quyết định điều trị không phù hợp.

Khoảng cách giữa độ tự tin của mô hình (từ xác suất softmax) và độ chính xác thực tế được gọi là lỗi hiệu chuẩn. Mô hình được hiệu chuẩn tốt sẽ cho điểm tin cậy khớp với tỷ lệ chính xác — nếu mô hình dự đoán các sự kiện với độ tin cậy 80%, thì các sự kiện đó nên xảy ra xấp xỉ 80% thời gian.

Kỹ thuật regularization để cải thiện hiệu năng

May mắn thay, có nhiều kỹ thuật giúp khắc phục các vấn đề với softmax:

Temperature scaling

Temperature scaling đưa vào một tham số T điều khiển mức “mềm” của phân phối xác suất. Bằng cách chia logits cho tham số nhiệt độ này trước khi áp dụng softmax, bạn có thể điều chỉnh phân phối kết quả nhọn hơn hay phẳng hơn.

Nhiệt độ cao (T > 1) tạo ra phân phối “mềm” hơn với các giá trị ít cực đoan hơn, giúp giảm tự tin quá mức. Nhiệt độ thấp (T < 1) làm phân phối nhọn hơn về phía giá trị cao nhất. Temperature scaling thường dùng như kỹ thuật hậu xử lý sau huấn luyện để hiệu chuẩn độ tin cậy mà không ảnh hưởng đến thứ hạng các lớp.

Label smoothing

Label smoothing thay thế vector mục tiêu one-hot “cứng” bằng các phân phối được làm mượt nhẹ. Thay vì huấn luyện mô hình để xuất ra chính xác 0 và 1, label smoothing khuyến khích mô hình bớt tự tin, ví dụ đặt mục tiêu 0.9 cho lớp đúng và 0.025 cho lớp sai (trong bài toán 4 lớp).

Bằng cách huấn luyện với nhãn được làm mượt, mô hình học cách bớt tự tin, từ đó cải thiện khả năng tổng quát hóa và tăng độ bền vững trước nhiễu nhãn. Kỹ thuật này đã trở thành thực hành tiêu chuẩn trong nhiều mô hình phân loại ảnh hiện đại.

Dropout và phương pháp tổ hợp (ensemble)

Sử dụng dropout trong huấn luyện và giữ bật nó khi suy luận (kỹ thuật gọi là Monte Carlo dropout) cho phép bạn lấy nhiều dự đoán cho cùng một đầu vào và ước lượng bất định. Nếu mô hình cho dự đoán nhất quán qua nhiều lần chạy với các mẫu dropout khác nhau, có khả năng mô hình tin tưởng hơn vào dự đoán đó.

Tương tự, phương pháp ensemble kết hợp dự đoán từ nhiều mô hình để cải thiện hiệu năng và cung cấp ước lượng bất định tốt hơn. Mức độ bất đồng giữa các mô hình trong tổ hợp có thể đóng vai trò thước đo bất định.

Kỹ thuật hiệu chuẩn

Platt scaling và các phương pháp hiệu chuẩn khác có thể áp dụng sau huấn luyện để đảm bảo điểm tin cậy từ softmax thực sự tương ứng với xác suất đúng. Các phương pháp này thường dùng tập validation để học các tham số ánh xạ đầu ra gốc của mô hình thành các xác suất được hiệu chuẩn tốt.

Ví dụ, một cách tiếp cận temperature scaling đơn giản (như đã đề cập) có thể được tối ưu trên dữ liệu validation để giảm lỗi hiệu chuẩn. Các cách phức tạp hơn gồm hồi quy đẳng đơn (isotonic regression) và Bayesian binning.

Nút thắt cổ chai của softmax

Nghiên cứu gần đây chỉ ra một hạn chế cơ bản của softmax gọi là “softmax bottleneck.” Điều này đề cập đến việc khả năng biểu diễn của các mô hình ngôn ngữ dựa trên softmax bị giới hạn bởi hạng của ma trận trọng số ở tầng cuối. Trong ngữ cảnh ngôn ngữ tự nhiên với phụ thuộc phức tạp, điều này có thể ngăn mô hình nắm bắt đầy đủ các phân phối điều kiện cơ bản.

Các kiến trúc nâng cao như Mixture of Softmaxes (MoS) đã được đề xuất để khắc phục hạn chế này bằng cách dùng tổ hợp có trọng số của nhiều phân phối softmax.

Bằng cách nhận diện các vấn đề thường gặp này và áp dụng giải pháp phù hợp, bạn có thể cải thiện độ tin cậy và hiệu năng của các mô hình dùng softmax cho tác vụ phân loại.

Kết luận

Hàm kích hoạt softmax là thành phần thiết yếu của các mạng nơ-ron cho bài toán phân loại đa lớp, chuyển đổi logits thô thành các phân phối xác suất dễ diễn giải. Chúng ta đã tìm hiểu nền tảng toán học, cách triển khai trong Python, so sánh với sigmoid, các trường hợp sử dụng thực tế, và các kỹ thuật xử lý những thách thức thường gặp như bất ổn số và tự tin quá mức.

Sẵn sàng đào sâu hơn về mạng nơ-ron?

Câu hỏi thường gặp về hàm kích hoạt Softmax

Hàm kích hoạt softmax dùng để làm gì?

Softmax biến đổi đầu ra của mạng nơ-ron thành các phân phối xác suất cho bài toán phân loại đa lớp với các lớp loại trừ lẫn nhau.

Sự khác nhau giữa hàm kích hoạt softmax và sigmoid là gì?

Sigmoid tạo ra các xác suất độc lập cho kết quả nhị phân, trong khi softmax tạo ra các xác suất phụ thuộc lẫn nhau có tổng bằng 1 trên nhiều lớp.

Công thức softmax xử lý vấn đề ổn định số như thế nào?

Triển khai softmax ổn định sẽ trừ giá trị lớn nhất khỏi tất cả đầu vào trước khi lấy hàm mũ để tránh tràn số mà không thay đổi kết quả.

Khi nào tôi nên dùng softmax thay vì các hàm kích hoạt khác?

Hãy dùng softmax ở tầng đầu ra khi phân loại đầu vào vào một trong nhiều hạng mục loại trừ lẫn nhau, như phân loại ảnh hoặc phân loại tài liệu.

Có thể diễn giải đầu ra softmax là xác suất không?

Có. Đầu ra softmax biểu diễn các xác suất trên các lớp khác nhau có tổng bằng 1, giá trị cao hơn cho thấy mức độ tin cậy cao hơn ở lớp đó.

Tác giả

Rajesh Kumar

Tôi là một biên tập viên nội dung về khoa học dữ liệu. Tôi yêu thích sáng tạo nội dung xoay quanh các chủ đề AI/ML/DS. Tôi cũng khám phá các công cụ AI mới và viết về chúng.

Chủ đề

Liên quan