ResNet, Inception, EfficientNet
ResNet, Inception, EfficientNet: Kiến trúc CNN hiện đại
Sau thành công của các kiến trúc CNN cổ điển như LeNet, AlexNet và VGG, ngành học sâu đã phát triển các kiến trúc mạnh mẽ hơn để vượt qua những hạn chế của các mô hình trước đó. Bài viết này sẽ giới thiệu ba kiến trúc CNN hiện đại có ảnh hưởng sâu rộng: ResNet, Inception và EfficientNet, phân tích thiết kế, đóng góp và tác động của chúng đến lĩnh vực thị giác máy tính.
ResNet: Cách mạng hóa với kết nối tắt
1. Nguồn gốc và động lực
ResNet (Residual Network) được giới thiệu bởi Kaiming He và cộng sự từ Microsoft Research trong bài báo "Deep Residual Learning for Image Recognition" vào năm 2015. Nghiên cứu này đã giải quyết một vấn đề cốt lõi trong huấn luyện mạng sâu: hiện tượng biến mất gradient (vanishing gradient).
Trước ResNet, các nhà nghiên cứu nhận thấy rằng khi mạng trở nên sâu hơn, hiệu suất có thể bị suy giảm - không phải do overfitting mà do khó khăn trong quá trình tối ưu hóa. ResNet đã đưa ra một giải pháp đột phá bằng cách sử dụng các kết nối tắt (skip connections).
2. Khối Residual
Yếu tố then chốt của ResNet là khối residual (dư):
F(x) + xTrong đó:
F(x) là hàm mà các lớp mạng cần học
x là đầu vào ban đầu được truyền qua kết nối tắt
Thay vì cố gắng học trực tiếp một hàm chuyển đổi H(x), mạng được thiết kế để học hàm dư F(x) = H(x) - x. Điều này giúp gradient có thể dễ dàng truyền qua mạng trong quá trình huấn luyện.
3. Kiến trúc ResNet
ResNet có nhiều biến thể với số lớp khác nhau:
ResNet-18 & ResNet-34: Sử dụng khối residual đơn giản với hai lớp tích chập 3×3.
ResNet-50, ResNet-101 & ResNet-152: Sử dụng khối "bottleneck" với ba lớp tích chập (1×1, 3×3, 1×1) để giảm và khôi phục chiều sâu kênh, giúp tối ưu hiệu suất.
Cấu trúc chung của ResNet-50:
Lớp tích chập 7×7 với stride 2, 64 kênh
MaxPooling 3×3 với stride 2
4 khối residual, mỗi khối gồm nhiều khối bottleneck
Global Average Pooling
Lớp fully connected cho phân loại
4. Tác động và hiệu suất
ResNet đã thắng cuộc thi ILSVRC 2015 với tỷ lệ lỗi 3.57% (top-5), vượt qua hiệu suất của con người. Đặc biệt, ResNet-152 đạt kết quả ấn tượng mà không làm tăng độ phức tạp tính toán so với các mạng nông hơn.
5. Code mẫu: Khối Residual cơ bản với PyTorch
import torch.nn as nn
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, in_channels, out_channels, stride=1):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3,
stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3,
stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
# Skip connection
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1,
stride=stride, bias=False),
nn.BatchNorm2d(out_channels)
)
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out += self.shortcut(residual) # Add skip connection
out = self.relu(out)
return outInception: Mạng trong mạng với tích chập song song
1. Nguồn gốc và động lực
Kiến trúc Inception (còn gọi là GoogLeNet) được phát triển bởi nhóm nghiên cứu của Google do Christian Szegedy đứng đầu và được giới thiệu trong bài báo "Going Deeper with Convolutions" năm 2014. Inception được thiết kế với mục tiêu xây dựng mạng sâu hơn nhưng hiệu quả về tham số, giải quyết vấn đề chi phí tính toán và overfitting.
2. Module Inception
Đổi mới lớn nhất của Inception là "Module Inception" - một khối tích chập song song kết hợp nhiều kích thước bộ lọc khác nhau (1×1, 3×3, 5×5) và MaxPooling. Điều này cho phép mạng "nhìn" dữ liệu ở nhiều quy mô không gian khác nhau đồng thời.
Để giảm chi phí tính toán, Inception sử dụng các lớp tích chập 1×1 để giảm chiều sâu kênh trước khi áp dụng các bộ lọc lớn hơn - một kỹ thuật được gọi là "bottleneck".
3. Phát triển của Inception
Kiến trúc Inception đã trải qua nhiều phiên bản cải tiến:
Inception-v1 (GoogLeNet): Phiên bản ban đầu với 9 module Inception.
Inception-v2 & v3: Cải tiến với chuẩn hóa batch và tích chập được phân tách (factorized convolutions) - thay thế tích chập 5×5 bằng hai tích chập 3×3 liên tiếp.
Inception-v4 & Inception-ResNet: Kết hợp ý tưởng từ ResNet và Inception.
4. Kiến trúc Inception-v3
Inception-v3 bao gồm:
Các lớp tích chập ban đầu và pooling
3 module Inception với tích chập phân tách
5 module Inception tiêu chuẩn
2 module Inception với tích chập mở rộng (Expanded)
Global Average Pooling
Lớp fully connected và Softmax
5. Code mẫu: Module Inception đơn giản với PyTorch
import torch.nn as nn
import torch.nn.functional as F
class InceptionModule(nn.Module):
def __init__(self, in_channels, out_1x1, red_3x3, out_3x3, red_5x5, out_5x5, pool_proj):
super(InceptionModule, self).__init__()
# 1x1 convolution branch
self.branch1 = nn.Conv2d(in_channels, out_1x1, kernel_size=1)
# 1x1 -> 3x3 convolution branch
self.branch2_1 = nn.Conv2d(in_channels, red_3x3, kernel_size=1)
self.branch2_2 = nn.Conv2d(red_3x3, out_3x3, kernel_size=3, padding=1)
# 1x1 -> 5x5 convolution branch
self.branch3_1 = nn.Conv2d(in_channels, red_5x5, kernel_size=1)
self.branch3_2 = nn.Conv2d(red_5x5, out_5x5, kernel_size=5, padding=2)
# MaxPool -> 1x1 branch
self.branch4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
self.branch4_2 = nn.Conv2d(in_channels, pool_proj, kernel_size=1)
def forward(self, x):
branch1 = F.relu(self.branch1(x))
branch2 = F.relu(self.branch2_1(x))
branch2 = F.relu(self.branch2_2(branch2))
branch3 = F.relu(self.branch3_1(x))
branch3 = F.relu(self.branch3_2(branch3))
branch4 = self.branch4_1(x)
branch4 = F.relu(self.branch4_2(branch4))
# Concatenate along channel dimension
outputs = [branch1, branch2, branch3, branch4]
return torch.cat(outputs, 1)6. Tác động và hiệu suất
Inception đã chiến thắng cuộc thi ILSVRC 2014, đạt tỷ lệ lỗi top-5 là 6.67%. Đặc biệt, Inception-v3 đạt độ chính xác top-1 trên ImageNet là 78.8% với chỉ khoảng 24 triệu tham số, hiệu quả hơn nhiều so với VGG (138 triệu) và ngang với ResNet-50 (25 triệu).
Đóng góp quan trọng của Inception là chứng minh rằng các kiến trúc tinh gọn, thiết kế cẩn thận có thể vượt trội hơn các mạng lớn, đơn giản. Module Inception đã trở thành một thành phần phổ biến trong nhiều kiến trúc CNN hiện đại.
EfficientNet: Mở rộng mạng thông minh
1. Nguồn gốc và động lực
EfficientNet được giới thiệu bởi nhóm nghiên cứu Google Brain vào năm 2019 trong bài báo "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks". Động lực chính là giải quyết câu hỏi: "Làm thế nào để mở rộng mạng CNN một cách hiệu quả nhất?".
Trước EfficientNet, có ba cách phổ biến để mở rộng mạng:
Tăng độ sâu (thêm nhiều lớp hơn)
Tăng chiều rộng (thêm nhiều kênh hơn)
Tăng độ phân giải (tăng kích thước ảnh đầu vào)
EfficientNet đề xuất một phương pháp mới: compound scaling (mở rộng đa hợp) - mở rộng đồng thời cả ba chiều theo một tỷ lệ cân bằng.
2. Phương pháp mở rộng đa hợp (Compound Scaling)
Phương pháp mở rộng đa hợp được mô tả bằng công thức:
Độ sâu: d = α^φ
Chiều rộng: w = β^φ
Độ phân giải: r = γ^φ
Trong đó:
α, β, γ là các hệ số được xác định bằng tìm kiếm lưới (grid search)
φ là hệ số mở rộng tổng thể
Các hệ số tuân theo ràng buộc: α·β²·γ² ≈ 2
3. Kiến trúc nền tảng: EfficientNet-B0
Điểm đột phá của EfficientNet không chỉ là phương pháp mở rộng mà còn là kiến trúc cơ sở - EfficientNet-B0 - được tối ưu hóa thông qua neural architecture search (NAS).
EfficientNet-B0 bao gồm:
Các lớp tích chập ban đầu
7 khối Mobile Inverted Bottleneck Convolution (MBConv) với các kích thước bộ lọc khác nhau
Hàm kích hoạt Swish thay cho ReLU
Squeeze-and-Excitation (SE) blocks
Global Average Pooling và fully connected layer
4. Các biến thể EfficientNet
Từ EfficientNet-B0, các phiên bản lớn hơn (B1-B7) được tạo ra bằng cách áp dụng phương pháp mở rộng đa hợp với các giá trị φ khác nhau:
EfficientNet-B1: φ = 1.0
EfficientNet-B2: φ = 1.1
EfficientNet-B3: φ = 1.2
...
EfficientNet-B7: φ = 2.0
5. Code mẫu: MBConv Block với PyTorch
import torch.nn as nn
import torch.nn.functional as F
class Swish(nn.Module):
def forward(self, x):
return x * torch.sigmoid(x)
class SEBlock(nn.Module):
def __init__(self, in_channels, se_ratio=0.25):
super(SEBlock, self).__init__()
se_channels = max(1, int(in_channels * se_ratio))
self.squeeze = nn.AdaptiveAvgPool2d(1)
self.excitation = nn.Sequential(
nn.Conv2d(in_channels, se_channels, kernel_size=1),
Swish(),
nn.Conv2d(se_channels, in_channels, kernel_size=1),
nn.Sigmoid()
)
def forward(self, x):
y = self.squeeze(x)
y = self.excitation(y)
return x * y
class MBConvBlock(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size=3,
expand_ratio=6, stride=1, se_ratio=0.25, drop_rate=0.2):
super(MBConvBlock, self).__init__()
self.drop_rate = drop_rate
self.use_residual = in_channels == out_channels and stride == 1
# Expansion phase
exp_channels = in_channels * expand_ratio
if expand_ratio != 1:
self.expand = nn.Sequential(
nn.Conv2d(in_channels, exp_channels, kernel_size=1, bias=False),
nn.BatchNorm2d(exp_channels),
Swish()
)
else:
self.expand = nn.Identity()
# Depthwise convolution
self.depthwise = nn.Sequential(
nn.Conv2d(exp_channels, exp_channels, kernel_size=kernel_size,
stride=stride, padding=kernel_size//2, groups=exp_channels, bias=False),
nn.BatchNorm2d(exp_channels),
Swish()
)
# Squeeze and Excitation
self.se = SEBlock(exp_channels, se_ratio)
# Pointwise convolution (projection)
self.project = nn.Sequential(
nn.Conv2d(exp_channels, out_channels, kernel_size=1, bias=False),
nn.BatchNorm2d(out_channels)
)
# Dropout
self.dropout = nn.Dropout2d(drop_rate) if drop_rate > 0 else nn.Identity()
def forward(self, x):
# Save input for potential skip connection
residual = x
# Expansion
x = self.expand(x)
# Depthwise convolution
x = self.depthwise(x)
# Squeeze and Excitation
x = self.se(x)
# Pointwise convolution
x = self.project(x)
# Skip connection and dropout
if self.use_residual:
x = self.dropout(x)
x = x + residual
return x6. Tác động và hiệu suất
EfficientNet đã đạt được hiệu suất vượt trội trên ImageNet với ít tham số và FLOPs hơn:
EfficientNet-B0: 77.1% độ chính xác top-1 với chỉ 5.3M tham số
EfficientNet-B7: 84.3% độ chính xác top-1 với 66M tham số
So sánh, ResNeXt-101 đạt 80.9% với 84M tham số, trong khi EfficientNet-B3 đạt kết quả tương tự với chỉ 12M tham số.
So sánh các kiến trúc CNN hiện đại
1. Kích thước mô hình và hiệu suất
ResNet-50
26M
76.0%
4.1G
2015
ResNet-152
60M
77.8%
11.5G
2015
Inception-v3
24M
78.8%
5.7G
2015
EfficientNet-B0
5.3M
77.1%
0.4G
2019
EfficientNet-B3
12M
81.6%
1.8G
2019
EfficientNet-B7
66M
84.3%
37G
2019
2. Đặc điểm thiết kế chính
ResNet
Kết nối tắt
Đơn giản, hiệu quả, dễ huấn luyện
Tùy chọn thủ công về độ sâu
Inception
Tích chập song song, bottleneck 1×1
Đa quy mô, hiệu quả tham số
Phức tạp về mặt thiết kế
EfficientNet
Compound scaling, MBConv
Cân bằng tối ưu về độ sâu/rộng/phân giải
Tăng thời gian suy luận
3. Các ứng dụng thích hợp
ResNet: Nền tảng tốt cho nhiều ứng dụng khác nhau, dễ tinh chỉnh, và được hỗ trợ rộng rãi.
Inception: Phù hợp khi cần cân bằng giữa hiệu suất và kích thước mô hình, hoặc khi cần bắt các đặc trưng ở nhiều quy mô.
EfficientNet: Tối ưu cho thiết bị di động và edge computing, hoặc khi cần mô hình nhỏ nhưng hiệu suất cao.
Xu hướng thiết kế CNN hiện đại
1. Tích hợp các kỹ thuật tốt nhất
Các kiến trúc hiện đại thường kết hợp nhiều ý tưởng từ các mạng tiên phong:
ResNext: Kết hợp ResNet với khái niệm cardinality của Xception
DenseNet: Mở rộng kết nối tắt bằng cách kết nối mỗi lớp với tất cả các lớp trước đó
SENet: Thêm Squeeze-and-Excitation blocks vào các kiến trúc hiện có
EfficientNetV2: Cải tiến EfficientNet với training-aware NAS và Fused-MBConv
2. Sự chuyển dịch từ thiết kế thủ công sang tự động
Neural Architecture Search (NAS): Tìm kiếm tự động kiến trúc tối ưu
AutoML: Tự động hóa toàn bộ quy trình thiết kế và huấn luyện
Model Compression: Distillation, pruning, và quantization để tạo mô hình nhỏ gọn
3. Hướng tới suy luận hiệu quả
MobileNet, ShuffleNet: Thiết kế đặc biệt cho thiết bị di động
Depthwise Separable Convolution: Giảm đáng kể tham số và chi phí tính toán
Quantization-Aware Training: Huấn luyện mô hình phù hợp với độ chính xác thấp
Kết luận: Bài học từ các kiến trúc hiện đại
1. Các nguyên tắc thiết kế quan trọng
Kết nối tắt là cốt lõi: Hầu hết các kiến trúc hiện đại đều sử dụng kết nối tắt dưới một hình thức nào đó để giúp truyền gradient hiệu quả.
Giảm tham số với tích chập 1×1: Sử dụng bottleneck và các tích chập depthwise để giảm tham số.
Cân bằng quy mô: Tìm sự cân bằng phù hợp giữa độ sâu, chiều rộng và độ phân giải.
2. Điểm trùng lặp trong thiết kế
Các kiến trúc CNN hiện đại có một số đặc điểm chung:
Sử dụng batch normalization sau mỗi lớp tích chập
Tích hợp các kỹ thuật regularization như dropout hoặc dropconnect
Sử dụng global average pooling thay vì fully connected layers ở cuối mạng
Hàm kích hoạt tiên tiến như ReLU, Swish, hoặc SiLU
3. Tầm nhìn cho tương lai
Mặc dù gần đây các mô hình dựa trên Transformer (như ViT, Swin Transformer) đang nổi lên trong thị giác máy tính, các kiến trúc CNN vẫn có vai trò quan trọng, đặc biệt trong các ứng dụng thời gian thực và thiết bị đầu cuối.
Tương lai của CNN có thể sẽ là sự kết hợp:
Hybrid CNN-Transformer models
Specialized networks for specific tasks
Energy-aware and environmentally conscious architectures
Trong quá trình phát triển từ LeNet đến EfficientNet, chúng ta có thể thấy sự tiến hóa liên tục của kiến trúc CNN, từ những mạng đơn giản tới các thiết kế tinh vi, tự động. Bài học quan trọng là không có "one-size-fits-all" trong thiết kế CNN - mỗi kiến trúc đều có điểm mạnh và ứng dụng phù hợp riêng.
Last updated