TL;DR ResNet 用殘差連接解決退化問題,讓網路能堆到 100+ 層;EfficientNet 複合縮放平衡深度/寬度/解析度;ConvNeXt 吸收 Transformer 設計重奪 CV 王座。
目錄
系列:
世界名校 AI/CS 課程地圖
(15 / 37)
教材版本:基於 MIT 6.7960 Fall 2024 OCW。影片、投影片、作業全公開於 MIT OCW。
TL;R
ResNet 殘差連接解決退化問題;EfficientNet 複合縮放;ConvNeXt 吸收 Transformer 設計重奪 CV 王座。
背景 / 課程定位
第 6 講(L06),對應官方課表 9 月 23 日(推測)。L05 建立基礎 CNN;本講進入現代架構,探討「如何把網路堆深、堆高效、堆準」—— 這直接影響你訓練自己的模型時選什麼骨幹。
影片:Lecture 6: Modern CNN(建議從 2:30:00 開始) 投影片:Lecture 6: Modern CNN
核心概念對比
| 架構 | 年份 | 核心創新 | 解決什麼問題 |
|---|---|---|---|
| VGG (L05) | 2014 | 3×3 堆疊 | 證明深度有益,但梯度消失 |
| ResNet | 2015 | 殘差連接 | 退化問題(深網反而更差) |
| MobileNet | 2017 | 深度可分離卷積 | 行動端輕量化 |
| EfficientNet | 2019 | 複合縮放 | 系統化平衡深度/寬度/解析度 |
| ConvNeXt | 2022 | 吸收 Transformer 設計 | 證明 CNN 仍可打贏 ViT |
系統 / 方法架構
1. ResNet 殘差連接
x → [Conv-BN-ReLU] → [Conv-BN] → + (skip x) → ReLU
↑
identity shortcut
- 學習殘差 $F(x) = H(x) - x$,優化目標從「絕對映射」變「增量」
- 退化問題:plain 網路加深後訓練誤差反而上升;ResNet 讓最壞情況退化成 identity(拷貝上一層)
2. 深度可分離卷積 (Depthwise Separable)
標準卷積: C_in × C_out × k × k 參數
可分離: (C_in × k × k) + (C_in × C_out × 1 × 1) 參數
計算量減少 ~ k² × C_out / (1 + k²)
- MobileNet: 3×3 depthwise + 1×1 pointwise
- 例:輸入 64 通道、輸出 128、核 3×3
- 標準:$64 \times 128 \times 9 = 73728$
- 可分離:$64 \times 9 + 64 \times 128 = 8768$(省 8.4×)
3. EfficientNet 複合縮放
$$\text{depth}: d=\alpha^\phi, \quad \text{width}: w=\beta^\phi, \quad \text{resolution}: r=\gamma^\phi$$ 約束 $\alpha \cdot \beta^2 \cdot \gamma^2 \approx 2$(固定總計算量)
- B0→B7:$\phi$ 從 0 到 7,系統化放大
- 關鍵:單獨縮放任一度都次優;複合縮放最優
4. ConvNeXt 設計選擇
| 設計元素 | 來源 | 效果 |
|---|---|---|
| 7×7 大核 (depthwise) | Swin Transformer | 增大感受野 |
| 反轉瓶頸 (inverted bottleneck) | MobileNetV2 | 類 Transformer FFN |
| 無偏置、LayerNorm | Transformer | 訓練更穩定 |
| GELU 激活 | Transformer | 略優於 ReLU |
實作啟發
PyTorch 實作:ResNet 殘差塊
import torch
import torch.nn as nn
import torch.nn.functional as F
class ResidualBlock(nn.Module):
def __init__(self, in_ch, out_ch, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_ch, out_ch, 3, stride, 1, bias=False)
self.bn1 = nn.BatchNorm2d(out_ch)
self.conv2 = nn.Conv2d(out_ch, out_ch, 3, 1, 1, bias=False)
self.bn2 = nn.BatchNorm2d(out_ch)
# shortcut: 1×1 卷積對齊維度(當 in_ch ≠ out_ch 或 stride>1)
self.shortcut = nn.Sequential()
if in_ch != out_ch or stride != 1:
self.shortcut = nn.Sequential(
nn.Conv2d(in_ch, out_ch, 1, stride, bias=False),
nn.BatchNorm2d(out_ch)
)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x) # 殘差連接
return F.relu(out)
# 堆疊 ResNet-18 風格
class ResNet18(nn.Module):
def __init__(self, num_classes=10):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, 7, 2, 3, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.pool = nn.MaxPool2d(3, 2, 1)
self.layer1 = self._make_layer(64, 64, 2)
self.layer2 = self._make_layer(64, 128, 2, stride=2)
self.layer3 = self._make_layer(128, 256, 2, stride=2)
self.layer4 = self._make_layer(256, 512, 2, stride=2)
self.gap = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Linear(512, num_classes)
def _make_layer(self, in_ch, out_ch, blocks, stride=1):
layers = [ResidualBlock(in_ch, out_ch, stride)]
for _ in range(1, blocks):
layers.append(ResidualBlock(out_ch, out_ch))
return nn.Sequential(*layers)
def forward(self, x):
x = self.pool(F.relu(self.bn1(self.conv1(x))))
x = self.layer1(x); x = self.layer2(x)
x = self.layer3(x); x = self.layer4(x)
x = self.gap(x).flatten(1)
return self.fc(x)
深度可分離卷積實作
class DepthwiseSeparableConv(nn.Module):
def __init__(self, in_ch, out_ch, kernel=3):
super().__init__()
self.depthwise = nn.Conv2d(in_ch, in_ch, kernel, padding=kernel//2, groups=in_ch, bias=False)
self.pointwise = nn.Conv2d(in_ch, out_ch, 1, bias=False)
self.bn = nn.BatchNorm2d(out_ch)
def forward(self, x):
return F.relu(self.bn(self.pointwise(self.depthwise(x))))
直接調用預訓練模型(實務推薦)
import torchvision.models as models
# ResNet-50 預訓練(ImageNet 權重)
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)
# EfficientNet-B0
effnet = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.IMAGENET1K_V1)
# ConvNeXt-Tiny
convnext = models.convnext_tiny(weights=models.ConvNeXt_Tiny_Weights.IMAGENET1K_V1)
批判性反思
| 架構 | 優點 | 局限 / 注意 |
|---|---|---|
| ResNet | 解決退化、易訓練、成為骨幹標準 | 仍受感受野限制;超大模型不如後續架構 |
| MobileNet/EfficientNet | 輕量、移動端友好 | 小模型準確率天花板低;需仔細調複合縮放 |
| ConvNeXt | 證明 CNN 仍具競爭力、設計清晰 | 仍不如 ViT 在超大數據表現;推理成本較高 |
| Transformer (ViT) | 大數據 SOTA、可擴展 | 需海量數據/預訓練;小數據不如 CNN |
課程強調:選骨幹看三件事——(1) 數據量(小數據選 CNN/ConvNeXt,大數據可試 ViT);(2) 部署限制(行動端選 MobileNet/EfficientNet);(3) 準確率需求(追求極致選 EfficientNetV2/ConvNeXt-XXL)。不要盲目追新,要看約束條件。
參考資料
- Lecture 6: Modern CNN (MIT OCW 6.7960 Fall 2024) — 投影片 PDF
- Lecture 6 Video (YouTube) — 關鍵段落:0:00–15:00 ResNet;15:00–30:00 MobileNet/EfficientNet;30:00–45:00 ConvNeXt
- He et al., "Deep Residual Learning for Image Recognition" (CVPR 2016) — ResNet
- Howard et al., "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications" (2017)
- Tan & Le, "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks" (ICML 2019)
- Liu et al., "A ConvNet for the 2020s" (CVPR 2022) — ConvNeXt
- PyTorch 官方文檔:torchvision.models
Glossary
Loading...