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) + x

Trong đó:

  • 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:

  1. Lớp tích chập 7×7 với stride 2, 64 kênh

  2. MaxPooling 3×3 với stride 2

  3. 4 khối residual, mỗi khối gồm nhiều khối bottleneck

  4. Global Average Pooling

  5. 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 out

Inception: 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:

  1. Các lớp tích chập ban đầu và pooling

  2. 3 module Inception với tích chập phân tách

  3. 5 module Inception tiêu chuẩn

  4. 2 module Inception với tích chập mở rộng (Expanded)

  5. Global Average Pooling

  6. 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:

  1. Các lớp tích chập ban đầu

  2. 7 khối Mobile Inverted Bottleneck Convolution (MBConv) với các kích thước bộ lọc khác nhau

  3. Hàm kích hoạt Swish thay cho ReLU

  4. Squeeze-and-Excitation (SE) blocks

  5. 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 x

6. 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

Kiến trúc
Tham số
Top-1 Acc (ImageNet)
FLOPS
Năm

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

Kiến trúc
Đổi mới chính
Ưu điểm
Nhược điểm

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