Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Softmax và Cross Entropy trong PyTorch Beginner
Trong lĩnh vực học sâu, đặc biệt là các bài toán phân loại, hai thành phần cốt lõi thường được sử dụng là Hàm Softmax và Hàm mất mát Cross Entropy. Hàm Softmax giúp chuyển đổi đầu ra của mô hình thành xác suất, từ đó dễ dàng xác định lớp dự đoán. Trong khi đó, hàm mất mát Cross Entropy được dùng để đánh giá mức độ chính xác của các dự đoán, giúp mô hình học tập hiệu quả hơn. Trong bài viết này, chúng ta sẽ cùng tìm hiểu chi tiết về cách hoạt động của hai hàm này, mối quan hệ giữa chúng, cũng như cách ứng dụng thực tế trong PyTorch.
Hàm Softmax và Cross Entropy (Với Numpy và PyTorch)
Hàm Softmax
import numpy as np import torch # Định nghĩa hàm Softmax sử dụng Numpy def softmax(x): return np.exp(x) / np.sum(np.exp(x), axis=0) x = np.array([2.0, 1.0, 0.1]) outputs = softmax(x) print('Softmax (numpy):', outputs) # Hàm Softmax sử dụng PyTorch x = torch.tensor([2.0, 1.0, 0.1]) outputs = torch.softmax(x, dim=0) print('Softmax (torch):', outputs)
Giải thích:
Hàm Softmax:
- Tính e^x cho từng phần tử.
- Chia mỗi giá trị cho tổng tất cả các giá trị đã nâng lũy thừa .
- Đảm bảo kết quả đầu ra nằm trong khoảng [0, 1] và tổng bằng 1.
Hàm Cross Entropy
# Hàm tính Cross Entropy (Numpy) def cross_entropy(actual, predicted): EPS = 1e-15 # Tránh log(0) predicted = np.clip(predicted, EPS, 1 - EPS) loss = -np.sum(actual * np.log(predicted)) return loss # Ví dụ với dữ liệu Y = np.array([1, 0, 0]) # Nhãn thực tế (one-hot) Y_pred_good = np.array([0.7, 0.2, 0.1]) # Dự đoán tốt Y_pred_bad = np.array([0.1, 0.3, 0.6]) # Dự đoán tệ l1 = cross_entropy(Y, Y_pred_good) l2 = cross_entropy(Y, Y_pred_bad) print(f'Loss tốt (numpy): {l1:.4f}') print(f'Loss tệ (numpy): {l2:.4f}')
Giải thích:
- Cross Entropy đánh giá độ khác biệt giữa nhãn thực tế và nhãn dự đoán .
- Nếu dự đoán đúng (xác suất cao ở nhãn chính xác), loss sẽ nhỏ.
Sử dụng Cross Entropy trong PyTorch
PyTorch cung cấp hàm mất mát tích hợp CrossEntropyLoss
, bao gồm cả Softmax.
import torch.nn as nn # Khởi tạo loss function loss = nn.CrossEntropyLoss() # Ví dụ 1: Phân loại 3 lớp Y = torch.tensor([0]) # Nhãn thực tế (lớp 0) Y_pred_good = torch.tensor([[2.0, 1.0, 0.1]]) # Logits với dự đoán tốt Y_pred_bad = torch.tensor([[0.5, 2.0, 0.3]]) # Logits với dự đoán tệ l1 = loss(Y_pred_good, Y) l2 = loss(Y_pred_bad, Y) print(f'Loss tốt (PyTorch): {l1.item():.4f}') print(f'Loss tệ (PyTorch): {l2.item():.4f}')
Lưu ý:
Bài viết này được đăng tại [free tuts .net]
- Logits: Đầu ra chưa chuẩn hóa (không cần áp dụng Softmax trước).
- Hàm
CrossEntropyLoss
tự động xử lý chuẩn hóa bằng LogSoftmax.
Loss trên batch và dự đoán
# Ví dụ với nhiều mẫu (batch) Y = torch.tensor([2, 0, 1]) # Nhãn thực tế cho batch Y_pred_good = torch.tensor([ [0.1, 0.2, 3.9], # Dự đoán đúng: lớp 2 [1.2, 0.1, 0.3], # Dự đoán đúng: lớp 0 [0.3, 2.2, 0.2] # Dự đoán đúng: lớp 1 ]) Y_pred_bad = torch.tensor([ [0.9, 0.2, 0.1], # Sai [0.1, 0.3, 1.5], # Sai [1.2, 0.2, 0.5] # Sai ]) l1 = loss(Y_pred_good, Y) l2 = loss(Y_pred_bad, Y) print(f'Batch Loss tốt: {l1.item():.4f}') print(f'Batch Loss tệ: {l2.item():.4f}') # Dự đoán lớp từ logits _, predictions1 = torch.max(Y_pred_good, 1) _, predictions2 = torch.max(Y_pred_bad, 1) print(f'Lớp thực tế: {Y}') print(f'Dự đoán tốt: {predictions1}') print(f'Dự đoán tệ: {predictions2}')
Phân biệt Phân loại nhị phân và Đa lớp trong PyTorch
Phân loại nhị phân
- Sử dụng hàm Sigmoid để chuẩn hóa đầu ra (xác suất cho một lớp).
- Hàm mất mát:
BCELoss()
.
class NeuralNetBinary(nn.Module): def __init__(self, input_size, hidden_size): super(NeuralNetBinary, self).__init__() self.linear1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.linear2 = nn.Linear(hidden_size, 1) def forward(self, x): out = self.linear1(x) out = self.relu(out) out = self.linear2(out) return torch.sigmoid(out)
Phân loại đa lớp
- Không sử dụng Softmax trong mô hình (PyTorch tự xử lý trong
CrossEntropyLoss
). - Hàm mất mát:
CrossEntropyLoss()
.
class NeuralNetMulticlass(nn.Module): def __init__(self, input_size, hidden_size, num_classes): super(NeuralNetMulticlass, self).__init__() self.linear1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.linear2 = nn.Linear(hidden_size, num_classes) def forward(self, x): out = self.linear1(x) out = self.relu(out) return self.linear2(out) # Không Softmax