LeNet, AlexNet, VGG
Các kiến trúc CNN quan trọng: LeNet, AlexNet, VGG
Mạng nơ-ron tích chập (Convolutional Neural Networks - CNN) đã cách mạng hóa lĩnh vực thị giác máy tính và đóng vai trò quan trọng trong sự phát triển của trí tuệ nhân tạo hiện đại. Các kiến trúc CNN tiên phong như LeNet, AlexNet và VGG không chỉ là những cột mốc quan trọng trong lịch sử AI mà còn thiết lập nền tảng cho các kiến trúc hiện đại hơn ngày nay. Bài viết này sẽ khám phá chi tiết ba kiến trúc CNN quan trọng này, so sánh các đặc điểm nổi bật và tác động của chúng đến lĩnh vực học sâu.
LeNet-5 (1998)
Tổng quan
LeNet-5 là một trong những mạng CNN đầu tiên, được phát triển bởi Yann LeCun và cộng sự vào năm 1998. Kiến trúc này được thiết kế chủ yếu để nhận dạng chữ số viết tay và đã đạt được thành công đáng kể trong việc tự động xử lý séc ngân hàng.
Kiến trúc
LeNet-5 bao gồm 7 lớp với các thành phần chính:
Lớp đầu vào: Hình ảnh 32×32 pixel
C1: Lớp tích chập với 6 bộ lọc kích thước 5×5, tạo ra 6 feature maps kích thước 28×28
S2: Lớp subsampling (pooling) giảm kích thước xuống 14×14
C3: Lớp tích chập với 16 bộ lọc, tạo ra 16 feature maps kích thước 10×10
S4: Lớp subsampling giảm kích thước xuống 5×5
C5: Lớp tích chập với 120 feature maps kích thước 1×1
F6: Lớp fully connected với 84 đơn vị
Lớp đầu ra: 10 đơn vị (tương ứng với các chữ số 0-9)
Đặc điểm nổi bật
Tổng số tham số: khoảng 60,000
Sử dụng các khối tích chập-pooling lặp lại
Hàm kích hoạt: tanh (hyperbolic tangent)
Không có lớp batch normalization hay dropout
Được thiết kế để chạy trên phần cứng hạn chế
Tầm ảnh hưởng
LeNet-5 đặt nền móng cho kiến trúc CNN hiện đại với các nguyên tắc cơ bản vẫn được sử dụng đến ngày nay:
Tính chất địa phương (local connectivity)
Chia sẻ tham số (parameter sharing)
Sử dụng các lớp tích chập theo sau là subsampling/pooling
AlexNet (2012)
Tổng quan
AlexNet, được phát triển bởi Alex Krizhevsky, Ilya Sutskever và Geoffrey Hinton, đã tạo nên một bước ngoặt trong lĩnh vực thị giác máy tính khi giành chiến thắng tại cuộc thi ImageNet Large Scale Visual Recognition Challenge (ILSVRC) năm 2012 với tỷ lệ lỗi top-5 chỉ 15.3%, vượt xa đội xếp thứ hai (26.2%).
Kiến trúc
AlexNet có 8 lớp (5 lớp tích chập và 3 lớp fully connected):
Lớp đầu vào: Hình ảnh RGB 227×227×3
Conv1: 96 bộ lọc kích thước 11×11, stride 4, không padding
MaxPool1: Kích thước 3×3, stride 2
Conv2: 256 bộ lọc kích thước 5×5, padding 2
MaxPool2: Kích thước 3×3, stride 2
Conv3: 384 bộ lọc kích thước 3×3, padding 1
Conv4: 384 bộ lọc kích thước 3×3, padding 1
Conv5: 256 bộ lọc kích thước 3×3, padding 1
MaxPool3: Kích thước 3×3, stride 2
FC6: 4096 đơn vị
FC7: 4096 đơn vị
FC8: 1000 đơn vị (số lớp trong ImageNet)
Đặc điểm nổi bật
Tổng số tham số: khoảng 60 triệu
Sử dụng hàm kích hoạt ReLU thay vì tanh/sigmoid
Áp dụng kỹ thuật Local Response Normalization (LRN)
Sử dụng Dropout với tỷ lệ 0.5 để giảm overfitting
Sử dụng Data Augmentation (cắt ngẫu nhiên, phản chiếu, thay đổi màu sắc)
Huấn luyện trên 2 GPU (kiến trúc song song)
Tầm ảnh hưởng
AlexNet được coi là cột mốc quan trọng đánh dấu sự bắt đầu của kỷ nguyên học sâu hiện đại:
Chứng minh tính hiệu quả của CNN trên bộ dữ liệu lớn
Phổ biến hóa ReLU và Dropout
Làm nổi bật vai trò của GPU trong huấn luyện mạng học sâu
Thiết lập xu hướng mạng CNN sâu hơn và lớn hơn
VGG (2014)
Tổng quan
VGG (Visual Geometry Group) được phát triển bởi Karen Simonyan và Andrew Zisserman từ Đại học Oxford, đã đạt vị trí thứ hai trong ILSVRC 2014. Mặc dù không giành chiến thắng (xếp sau GoogLeNet), VGG nhanh chóng trở nên phổ biến nhờ kiến trúc đơn giản, rõ ràng và dễ hiểu.
Kiến trúc
VGG có nhiều biến thể, nhưng phổ biến nhất là VGG-16 và VGG-19. VGG-16 bao gồm:
Lớp đầu vào: Hình ảnh RGB 224×224×3
Block 1: 2 lớp tích chập 3×3, 64 kênh + MaxPool 2×2
Block 2: 2 lớp tích chập 3×3, 128 kênh + MaxPool 2×2
Block 3: 3 lớp tích chập 3×3, 256 kênh + MaxPool 2×2
Block 4: 3 lớp tích chập 3×3, 512 kênh + MaxPool 2×2
Block 5: 3 lớp tích chập 3×3, 512 kênh + MaxPool 2×2
FC6: 4096 đơn vị
FC7: 4096 đơn vị
FC8: 1000 đơn vị (số lớp trong ImageNet)
Đặc điểm nổi bật
Tổng số tham số: khoảng 138 triệu (VGG-16)
Thiết kế cực kỳ đồng nhất, chỉ sử dụng các lớp tích chập 3×3 với stride 1 và padding 1
Sử dụng MaxPooling 2×2 với stride 2 để giảm kích thước không gian
Sử dụng ReLU sau mỗi lớp tích chập
Tăng dần số lượng kênh theo độ sâu (64 → 128 → 256 → 512)
Tầm ảnh hưởng
VGG đã đặt ra một số nguyên tắc thiết kế quan trọng cho CNN:
Đơn giản hóa kiến trúc bằng cách sử dụng các khối đồng nhất
Chứng minh hiệu quả của việc sử dụng nhiều lớp tích chập nhỏ (3×3) thay vì ít lớp lớn hơn
Trở thành kiến trúc cơ sở phổ biến cho nhiều ứng dụng chuyển giao học tập
So sánh các kiến trúc
Năm phát hành
1998
2012
2014
Số lớp
7
8
16
Số tham số
~60K
~60M
~138M
Kích thước đầu vào
32×32×1
227×227×3
224×224×3
Bộ dữ liệu
MNIST
ImageNet
ImageNet
Hàm kích hoạt
tanh
ReLU
ReLU
Regularization
Không
Dropout, LRN
Dropout
Bộ lọc
5×5
11×11, 5×5, 3×3
3×3
GPU
Không
2x NVIDIA GTX 580
4x NVIDIA Titan Black
Quá trình phát triển và tiến hóa
Quá trình tiến hóa từ LeNet đến VGG thể hiện một số xu hướng quan trọng trong sự phát triển của CNN:
Tăng độ sâu: Từ 7 lớp (LeNet) lên 8 lớp (AlexNet) và 16-19 lớp (VGG)
Tăng số tham số: Từ 60K lên 60M và 138M, phản ánh sự phức tạp ngày càng tăng
Đơn giản hóa thiết kế: Xu hướng đi từ các bộ lọc đa dạng sang các bộ lọc đồng nhất 3×3 ở VGG
Tinh chỉnh kỹ thuật regularization: Từ không có đến việc sử dụng Dropout, LRN và data augmentation
Thay đổi hàm kích hoạt: Từ tanh/sigmoid sang ReLU
Tăng cường sức mạnh tính toán: Từ CPU sang nhiều GPU mạnh hơn
Bài học kiến trúc từ ba mạng huyền thoại
1. Vai trò của các lớp tích chập
LeNet: Sử dụng các lớp tích chập với khả năng tận dụng tính chất không gian của dữ liệu
AlexNet: Các bộ lọc lớn (11×11) ở lớp đầu giúp bắt được các đặc trưng tổng thể
VGG: Nhiều lớp tích chập 3×3 liên tiếp tạo hiệu ứng trường nhận thức lớn hơn với ít tham số hơn
2. Chiến lược pooling
LeNet: Sử dụng Average Pooling (gọi là Subsampling)
AlexNet: Chuyển sang Max Pooling với cửa sổ 3×3
VGG: Sử dụng Max Pooling 2×2 đơn giản, đều đặn sau mỗi khối tích chập
3. Regularization và chống overfitting
LeNet: Ít tham số nên ít gặp vấn đề overfitting trên bộ dữ liệu nhỏ
AlexNet: Áp dụng Dropout (0.5) ở lớp fully connected và data augmentation
VGG: Tiếp tục sử dụng Dropout, kết hợp với pre-training và fine-tuning
4. Thiết kế mạng
LeNet: Thiết kế thủ công, dựa trên hiểu biết về thị giác sinh học
AlexNet: Thiết kế phức tạp hơn, kết hợp nhiều cải tiến kỹ thuật
VGG: Đơn giản hóa thiết kế, theo dõi từng khối, tăng dần số kênh theo độ sâu
Ứng dụng thực tế
LeNet-5
Nhận dạng chữ số viết tay (MNIST)
Xử lý séc ngân hàng tự động
OCR (Optical Character Recognition) đơn giản
Nhận dạng chữ cái và ký tự đặc biệt
AlexNet
Phân loại hình ảnh đa lớp
Phát hiện đối tượng
Cơ sở cho các mô hình transfer learning đầu tiên
Ứng dụng trong máy thị giác công nghiệp
VGG
Transfer learning cho nhiều ứng dụng thị giác khác nhau
Trích xuất đặc trưng hình ảnh (VGG feature extractor)
Phân đoạn ngữ nghĩa (Semantic segmentation)
Nhận dạng khuôn mặt và xác thực sinh trắc học
Phát hiện đối tượng chi tiết
Style transfer và tạo nội dung
Hiệu suất và chi phí tính toán
LeNet-5
N/A (98.9% trên MNIST)
Vài giờ (CPU)
~0.5MB
~0.4M
AlexNet
15.3%
5-6 ngày (2 GPU)
~240MB
~1.5G
VGG-16
7.3%
2-3 tuần (4 GPU)
~528MB
~15.5G
Nhận xét:
LeNet: Nhẹ, hiệu quả, nhưng giới hạn trong các tác vụ đơn giản
AlexNet: Bước nhảy vọt về hiệu suất, với chi phí tính toán đáng kể
VGG: Cải thiện độ chính xác, nhưng với chi phí là mô hình nặng và chậm hơn nhiều
Sự chuyển tiếp từ VGG đến các kiến trúc mới hơn
VGG đánh dấu đỉnh cao của CNN "truyền thống" với thiết kế khá đơn giản. Sau VGG, các kiến trúc CNN đã phát triển theo những hướng mới:
GoogLeNet/Inception (2014)
Giới thiệu module Inception với tích chập song song
Giảm đáng kể số tham số (chỉ ~7M) so với VGG (~138M)
Sử dụng global average pooling thay thế cho fully connected
ResNet (2015)
Đột phá với kết nối tắt (skip connections)
Cho phép huấn luyện mạng cực kỳ sâu (lên đến 152 lớp)
Giải quyết vấn đề biến mất gradient
MobileNet, EfficientNet (2017-2019)
Tối ưu hóa cho thiết bị di động và edge computing
Sử dụng tích chập tách rời (depthwise separable convolutions)
Kết hợp kiến trúc và tìm kiếm tự động
Code mẫu: Triển khai LeNet, AlexNet và VGG với PyTorch
LeNet-5
import torch.nn as nn
class LeNet5(nn.Module):
def __init__(self, num_classes=10):
super(LeNet5, self).__init__()
# C1: Convolutional Layer (6@28x28)
self.c1 = nn.Conv2d(1, 6, kernel_size=5)
# S2: Average Pooling Layer (6@14x14)
self.s2 = nn.AvgPool2d(kernel_size=2, stride=2)
# C3: Convolutional Layer (16@10x10)
self.c3 = nn.Conv2d(6, 16, kernel_size=5)
# S4: Average Pooling Layer (16@5x5)
self.s4 = nn.AvgPool2d(kernel_size=2, stride=2)
# C5: Convolutional Layer (120@1x1)
self.c5 = nn.Conv2d(16, 120, kernel_size=5)
# F6: Fully Connected Layer (84)
self.f6 = nn.Linear(120, 84)
# Output Layer (10)
self.output = nn.Linear(84, num_classes)
def forward(self, x):
# C1 -> activation -> S2
x = self.s2(torch.tanh(self.c1(x)))
# C3 -> activation -> S4
x = self.s4(torch.tanh(self.c3(x)))
# C5 -> activation
x = torch.tanh(self.c5(x))
# Flatten -> F6 -> activation -> output
x = x.view(-1, 120)
x = torch.tanh(self.f6(x))
x = self.output(x)
return xAlexNet
import torch.nn as nn
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
# Conv1
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0),
nn.ReLU(inplace=True),
nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
nn.MaxPool2d(kernel_size=3, stride=2),
# Conv2
nn.Conv2d(96, 256, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
nn.MaxPool2d(kernel_size=3, stride=2),
# Conv3
nn.Conv2d(256, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
# Conv4
nn.Conv2d(384, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
# Conv5
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.classifier = nn.Sequential(
# FC6
nn.Dropout(p=0.5),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
# FC7
nn.Dropout(p=0.5),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
# FC8 (Output)
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), 256 * 6 * 6)
x = self.classifier(x)
return xVGG-16
import torch.nn as nn
class VGG16(nn.Module):
def __init__(self, num_classes=1000):
super(VGG16, self).__init__()
# Block 1
self.block1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# Block 2
self.block2 = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# Block 3
self.block3 = nn.Sequential(
nn.Conv2d(128, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# Block 4
self.block4 = nn.Sequential(
nn.Conv2d(256, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# Block 5
self.block5 = nn.Sequential(
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# Classifier
self.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, num_classes)
)
# Weight initialization
self._initialize_weights()
def forward(self, x):
x = self.block1(x)
x = self.block2(x)
x = self.block3(x)
x = self.block4(x)
x = self.block5(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)Kết luận
LeNet, AlexNet và VGG đại diện cho ba giai đoạn quan trọng trong sự phát triển của CNN, mỗi kiến trúc đều mang lại những đột phá và bài học kiến trúc có giá trị:
LeNet đặt nền móng cho CNN với các nguyên tắc cơ bản về tích chập và pooling.
AlexNet chứng minh sức mạnh của học sâu trên bộ dữ liệu lớn và giới thiệu nhiều kỹ thuật mới.
VGG đơn giản hóa thiết kế CNN và chứng minh sức mạnh của kiến trúc đồng nhất, sâu.
Mặc dù ngày nay đã có nhiều kiến trúc hiện đại hơn, ba kiến trúc này vẫn được sử dụng rộng rãi làm nền tảng cho các ứng dụng và nghiên cứu mới. Chúng không chỉ quan trọng về mặt lịch sử mà còn tiếp tục cung cấp những hiểu biết có giá trị cho việc thiết kế các mạng CNN hiệu quả.
Hiểu rõ về LeNet, AlexNet và VGG là bước đầu tiên quan trọng cho bất kỳ ai muốn đi sâu vào lĩnh vực thị giác máy tính và học sâu. Từ những nền tảng này, các nhà nghiên cứu và kỹ sư đã phát triển các kiến trúc tiên tiến hơn như ResNet, DenseNet, EfficientNet và các biến thể Transformer cho thị giác máy tính, tiếp tục đẩy ranh giới của công nghệ AI ngày càng xa hơn.
Last updated