Multilayer Perceptron
Perceptron đa tầng
Một perceptron đơn lẻ chỉ vẽ được đường thẳng để phân loại. Muốn phân loại hình xoắn ốc (spiral), bạn cần gì?
Hình minh họa
Thay đổi giá trị đầu vào, rồi nhấn Lan truyền để xem tín hiệu đi qua mạng. Rê chuột lên nơ-ron để xem chi tiết.
Năm 1969, Minsky và Papert công bố cuốn sách Perceptrons chỉ ra: một perceptron đơn lẻ không thể giải bài toán XOR. Điều đó đã khiến làn sóng AI đầu tiên nguội lạnh suốt hơn một thập kỷ — cho đến khi MLP + backpropagation xuất hiện. Hãy tự tay chứng kiến:
Hình minh họa
Điểm xanh = lớp 1, điểm đỏ = lớp 0. Perceptron chỉ vẽ được MỘT đường thẳng — không đường nào phân tách được 2 nhóm XOR!
Bạn vừa xây một Multi-Layer Perceptron — mạng nơ-ron nhiều lớp! Mỗi lớp ẩn trích xuất đặc trưng ngày càng trừu tượng, giống như nhà máy phở: lớp 1 sơ chế nguyên liệu, lớp 2 nấu nước dùng, lớp cuối cho ra tô phở hoàn chỉnh. Quan trọng hơn: chiều sâu phá vỡ giới hạn tuyến tính — điều mà perceptron đơn không thể làm được với XOR.
Năm 1989 Cybenko chứng minh: một MLP với 1 lớp ẩn đủ rộng có thể xấp xỉ hầu hết mọi hàm liên tục trên tập compact với độ chính xác tuỳ ý. Dưới đây, ta dùng MLP với số nơ-ron ẩn thay đổi để xấp xỉ .
Hình minh họa
MSE = 0.0017
K = 2
Quá thô
K = 10
Khá tốt
K = 30+
Rất gần
Bạn đã thấy tín hiệu chảy qua mạng. Nhưng nếu bỏ hết hàm kích hoạt (ReLU, sigmoid) thì sao? Nghĩ kĩ trước khi chọn!
Nếu MLP 10 lớp không có hàm kích hoạt phi tuyến, nó tương đương với gì?
Depth vs Width: Bạn có 10.000 tham số để xây mạng cho bài toán ảnh phức tạp. Chọn thế nào?
Giải thích
Multi-Layer Perceptron (MLP) là kiến trúc mạng nơ-ron cơ bản nhất với các lớp kết nối đầy đủ (fully connected). Tại mỗi lớp, phép tính diễn ra theo hai bước:
Trong đó là ma trận trọng số, là bias, và là hàm kích hoạt phi tuyến (ReLU, sigmoid, v.v.). Mạng học bằng lan truyền ngược để tối ưu trọng số.
Ba loại lớp trong MLP:
- Lớp đầu vào: Nhận dữ liệu thô. Số nơ-ron = số đặc trưng (ảnh 28×28 pixel = 784 nơ-ron).
- Lớp ẩn: Trích xuất đặc trưng. Lớp đầu nhận diện nét đơn giản, lớp sau tổ hợp thành đặc trưng phức tạp hơn.
- Lớp đầu ra: Cho kết quả cuối. 1 nơ-ron cho bài toán hồi quy, n nơ-ron cho phân loại n lớp.
import torch
import torch.nn as nn
class MLP(nn.Module):
def __init__(self, in_dim=784, hidden=[128, 64], out_dim=10):
super().__init__()
dims = [in_dim, *hidden, out_dim]
layers = []
for i in range(len(dims) - 1):
layers.append(nn.Linear(dims[i], dims[i + 1]))
if i < len(dims) - 2: # không đặt ReLU sau lớp đầu ra
layers.append(nn.ReLU())
self.net = nn.Sequential(*layers)
def forward(self, x):
return self.net(x)
# Khởi tạo & đếm tham số
model = MLP(784, [128, 64], 10)
n_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Tham số: {n_params:,}") # ~109k
# Forward pass thử
x = torch.randn(32, 784) # batch 32, ảnh flatten
logits = model(x) # (32, 10)
print(logits.shape)import torch
import torch.nn as nn
# Dữ liệu XOR
X = torch.tensor([[0., 0.], [0., 1.], [1., 0.], [1., 1.]])
y = torch.tensor([[0.], [1.], [1.], [0.]])
# MLP nhỏ nhất: 2 đầu vào -> 2 nơ-ron ẩn (tanh) -> 1 đầu ra (sigmoid)
model = nn.Sequential(
nn.Linear(2, 2),
nn.Tanh(),
nn.Linear(2, 1),
nn.Sigmoid(),
)
loss_fn = nn.BCELoss()
opt = torch.optim.Adam(model.parameters(), lr=0.1)
for epoch in range(2000):
pred = model(X)
loss = loss_fn(pred, y)
opt.zero_grad()
loss.backward()
opt.step()
if epoch % 200 == 0:
acc = ((pred > 0.5).float() == y).float().mean().item()
print(f"epoch {epoch:4d} loss={loss.item():.4f} acc={acc:.2f}")
# Kết quả cuối
print("Dự đoán:", model(X).squeeze().detach().tolist())
# ~ [0.02, 0.98, 0.98, 0.02] ← XOR đã học được!Không có công thức vạn năng, nhưng có vài heuristic hữu ích:
- Bắt đầu với 1–2 lớp ẩn, mỗi lớp ~cùng cỡ chiều đầu vào.
- Nếu underfitting (bias cao): tăng chiều rộng hoặc chiều sâu.
- Nếu overfitting (variance cao): giảm mạng, thêm dropout/L2.
- Với dữ liệu có cấu trúc (ảnh, chuỗi): dùng CNN/RNN/Transformer thay vì cố ép MLP.
- Dùng Bayesian/grid search hoặc learning rate finder để tinh chỉnh hyperparameter có hệ thống.
Kiến trúc MLP phụ thuộc vào loại bài toán. Chọn loại dữ liệu bên dưới để xem khuyến nghị:
Hình minh họa
Số lớp
2–3 lớp ẩn
Chiều rộng
64–256 nơ-ron mỗi lớp
Kích hoạt
ReLU hoặc GELU
MLP là lựa chọn chuẩn cho dữ liệu bảng (số, hạng mục mã hoá). Không cần sâu.
Quy tắc ngón tay cái:
- Dữ liệu bảng → MLP 2-3 lớp, gradient boosted trees thường cũng mạnh.
- Ảnh → CNN (ResNet, EfficientNet, ViT).
- Chuỗi → Transformer (GPT, BERT) hoặc RNN (LSTM, GRU).
- Dataset nhỏ → giữ mạng nhỏ + regularization mạnh, hoặc transfer learning.
- MLP gồm lớp đầu vào → lớp ẩn (một hoặc nhiều) → lớp đầu ra, tất cả kết nối đầy đủ.
- Hàm kích hoạt phi tuyến (ReLU, sigmoid) là BẮT BUỘC — không có nó, nhiều lớp vẫn chỉ là một phép tuyến tính.
- Perceptron đơn KHÔNG giải được XOR; MLP với 1 lớp ẩn 2 nơ-ron là đủ — chiều sâu mở khoá các hàm phi tuyến.
- Universal Approximation Theorem: MLP đủ rộng xấp xỉ hầu hết hàm liên tục; nhưng thực tế, SÂU thường hiệu quả hơn RỘNG.
- Số trọng số giữa hai lớp = (nơ-ron lớp trước) × (nơ-ron lớp sau) + bias.
- MLP tốt cho dữ liệu bảng; ảnh/chuỗi nên dùng CNN/Transformer với inductive bias phù hợp hơn.
Kiểm tra hiểu biết
Tại sao MLP cần hàm kích hoạt phi tuyến giữa các lớp?