AlexNet(詳解)——從原理到 PyTorch 實現(含訓練示例)
文章目錄
- AlexNet(詳解)——從原理到 PyTorch 實現(含訓練示例)
- 1. 發展歷史與比賽成績
- 2. AlexNet 的核心思想(一句話)
- 3. 模型結構總覽(概覽表)
- 4. 逐層計算舉例(重點:尺寸 & 參數如何得到)
- 例 1:Conv1 輸出尺寸(兩種常見約定)
- 例 2:參數量計算(按層逐項示例)
- 5. 關鍵設計點解析(為什么這些創新重要)
- 6. PyTorch 實現(完整代碼 —— 可復制粘貼)
- 7. 訓練與評估(實踐步驟 + 超參數建議)
- 8. 實驗擴展(建議做的對比實驗)
- 9. 總結
簡介(為什么寫這篇文章)
AlexNet 是 2012 年由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 提出的卷積神經網絡,它在 ILSVRC-2012 上大幅度優于當時其他方法,標志著深度學習在大規模視覺識別上的一次轉折。本文目標是:講清 AlexNet 的發展/比賽成績、核心思想與創新、逐層結構與維度/參數計算舉例,并給出一個可運行的 PyTorch 實現與訓練示例
論文地址
1. 發展歷史與比賽成績
- 作者 / 時間:Alex Krizhevsky, Ilya Sutskever, Geoffrey Hinton,發表于 NIPS 2012(論文標題 ImageNet Classification with Deep Convolutional Neural Networks)。這是 AlexNet 的權威來源。([NeurIPS 會議錄][1])
- 比賽成績:AlexNet 在 ILSVRC-2012 上獲得顯著勝出 —— top-5 錯誤率約 15.3%,相較第二名有非常大的優勢(原文和后續資料中有對比說明)。這次勝利推動了深度卷積網絡在計算機視覺領域的廣泛應用。([NeurIPS 會議錄][1], [維基百科][2])
2. AlexNet 的核心思想(一句話)
把較深的卷積網絡(比當時常見的淺網絡更深)、非飽和激活(ReLU)、大量數據(ImageNet)和 GPU 加速結合起來:通過 局部感受野 + 權值共享 + 下采樣(池化) 學習層次化特征,并用若干技巧(ReLU、數據增強、Dropout、局部響應歸一化等)防止過擬合與加速訓練,從而在大型圖像分類任務上取得突破。([NeurIPS 會議錄][1])
3. 模型結構總覽(概覽表)
說明:不同實現(paper vs Caffe vs torchvision)在輸入尺寸/補零細節上略有差異,常見將輸入視為
227×227×3
或224×224×3
。下表以常見重現(Caffe/多數教程)為例,輸出大小基于227×227
(或對224×224
做微調后也可得到相同的中間尺寸)。使用AdaptiveAvgPool2d((6,6))
可以避免輸入尺寸差異導致的維度問題(后面代碼中已采用)。本文中參數量計算以常見復現(final flatten = 256×6×6)為基準。([NeurIPS 會議錄][1], [多倫多大學計算機系][3])
層號 | 層類型 | kernel / stride / pad | 輸出通道 | 輸出尺度(示例) | 備注 |
---|---|---|---|---|---|
輸入 | — | — | 3 | 227×227×3(或 224×224×3) | 先做 scale → crop |
Conv1 | Conv 11×11, s=4, p=2 | 11×11 / 4 / 2 | 96 | 55×55×96 | ReLU → LRN → MaxPool(3,2) |
Pool1 | MaxPool 3×3, s=2 | — | — | 27×27×96 | — |
Conv2 | Conv 5×5, s=1, p=2, groups=2 | 5×5 / 1 / 2 | 256 | 27×27×256 | ReLU → LRN → Pool |
Pool2 | MaxPool 3×3, s=2 | — | — | 13×13×256 | — |
Conv3 | Conv 3×3, s=1, p=1 | 3×3 / 1 / 1 | 384 | 13×13×384 | ReLU |
Conv4 | Conv 3×3, s=1, p=1, groups=2 | 3×3 / 1 / 1 | 384 | 13×13×384 | ReLU |
Conv5 | Conv 3×3, s=1, p=1, groups=2 | 3×3 / 1 / 1 | 256 | 13×13×256 | ReLU → Pool (->6×6×256) |
FC6 | Linear | — | 4096 | 1×1×4096 | Dropout(0.5) |
FC7 | Linear | — | 4096 | 1×1×4096 | Dropout(0.5) |
FC8 | Linear | — | 1000 | logits | Softmax / CrossEntropyLoss |
注:paper 中 conv2、conv4、conv5 的“分組連接”(groups=2)設計最初出于 GPU 內存/并行的工程實現需要(在兩塊 GPU 上分別計算并部分連接),現代實現用
groups
可以在單 GPU 上復現該連接方式。([NeurIPS 會議錄][1], [PyTorch Forums][4])
4. 逐層計算舉例(重點:尺寸 & 參數如何得到)
下面先給出常用的卷積輸出公式,然后做具體示例與參數量計算。
卷積輸出尺寸公式(2D,單維):
O=?W?K+2PS?+1O = \left\lfloor\frac{W - K + 2P}{S}\right\rfloor + 1 O=?SW?K+2P??+1
其中 WWW 是輸入寬(高同理),KKK 是核大小,PPP 是 padding,SSS 是 stride,OOO 是輸出寬(或高)。
例 1:Conv1 輸出尺寸(兩種常見約定)
- 若用 輸入 227×227,kernel=11,stride=4,pad=0,則
O=(227?11)/4+1=55O=(227-11)/4+1=55O=(227?11)/4+1=55 → 輸出 55×55(很多 Caffe 實現采用 227); - 若用 輸入 224×224,但加上 pad=2(常見復現做法),kernel=11,stride=4:
O=?(224?11+2×2)/4?+1=?217/4?+1=54+1=55O=\lfloor(224-11+2×2)/4\rfloor+1=\lfloor217/4\rfloor+1=54+1=55O=?(224?11+2×2)/4?+1=?217/4?+1=54+1=55。
因此許多實現通過加 pad=2 在 224 和 227 的差異上取得相同的 55×55 輸出(實現細節不同但邏輯等價)。([多倫多大學計算機系][3])
例 2:參數量計算(按層逐項示例)
參數(weights)數目 = out_channels × in_channels × kernel_h × kernel_w
,再加上 out_channels
個偏置項(如果有 bias)。
舉幾個關鍵層(常見復現、flatten=256×6×6):
- Conv1:96×3×11×11+96=34,848+96=34,94496 \times 3 \times 11 \times 11 + 96 = 34,848 + 96 = 34,94496×3×11×11+96=34,848+96=34,944 個參數。
- Conv2(分組):paper 實現把輸入通道分到兩組(每組 48),卷積核為 5×5,輸出 256:
參數 = 256×48×5×5+256=307,200+256=307,456256 \times 48 \times 5 \times 5 + 256 = 307,200 + 256 = 307,456256×48×5×5+256=307,200+256=307,456。 - Conv3:384×256×3×3+384=885,120384 \times 256 \times 3 \times 3 + 384 = 885,120384×256×3×3+384=885,120。
- Conv4:384×192×3×3+384=663,936384 \times 192 \times 3 \times 3 + 384 = 663,936384×192×3×3+384=663,936。
- Conv5:256×192×3×3+256=442,624256 \times 192 \times 3 \times 3 + 256 = 442,624256×192×3×3+256=442,624。
- FC6(輸入 256×6×6=9216):4096×9216+4096=37,752,832+4096=37,756,9284096 \times 9216 + 4096 = 37,752,832 + 4096 = 37,756,9284096×9216+4096=37,752,832+4096=37,756,928。
- FC7:4096×4096+4096=16,781,3124096 \times 4096 + 4096 = 16,781,3124096×4096+4096=16,781,312。
- FC8:1000×4096+1000=4,096,000+1000=4,097,0001000 \times 4096 + 1000 = 4,096,000 + 1000 = 4,097,0001000×4096+1000=4,096,000+1000=4,097,000。
把這些加起來(各層之和)大約 60,965,224 ≈ 61M 參數(paper 給出的規模約 60M 左右,和上面的逐層分解是一致的常見復現結果)。這說明:FC 層占了絕大多數參數。([Stack Overflow][5], [NeurIPS 會議錄][1])
5. 關鍵設計點解析(為什么這些創新重要)
- ReLU(Rectified Linear Unit):比 sigmoid/tanh 的非線性更簡單、不飽和、反向傳播梯度消失更少,訓練更快、收斂更好。AlexNet 強調 ReLU 這是性能躍升的重要因素之一。([NeurIPS 會議錄][1])
- Local Response Normalization (LRN):paper 中用于增強局部“競爭性”,幫助泛化(現在 BN 更常用了)。LRN 在 conv1/conv2 后使用以稍微提升精度(但現代工作中效果有限)。([NeurIPS 會議錄][1])
- 分組卷積(groups=2):paper 在 conv2/conv4/conv5 采用分組連接,最初是出于 “在 2 塊GTX 580 GPU 上并行訓練 / 內存受限” 的工程需要(每塊 GPU 處理一半的通道并部分連接)。現在可用
groups
在單卡上復現。([NeurIPS 會議錄][1], [PyTorch Forums][4]) - 重采樣/池化(overlapping pooling):AlexNet 使用 kernel=3, stride=2 的 pooling(窗口有重疊),paper 指出重疊 pooling 相比不重疊可以略微提高泛化。([NeurIPS 會議錄][1])
- 數據增強(包括 PCA lighting):兩種簡單但有效的數據擴增:圖像隨機裁切/左右翻轉 + RGB 空間的 PCA 顏色擾動(paper 提到),這些“廉價”的增強能極大擴充 effective dataset 并降低過擬合。([NeurIPS 會議錄][1])
- Dropout(FC 層):在 FC6/FC7 使用 dropout(0.5) 有效降低過擬合,顯著提高泛化。([NeurIPS 會議錄][1])
6. PyTorch 實現(完整代碼 —— 可復制粘貼)
下面給出一個**忠實還原(常見復現)**的 AlexNet PyTorch 實現(包括 LRN、groups、Dropout、AdaptiveAvgPool,適配不同輸入尺寸)。把整個代碼直接復制到你的 .py/筆記本中即可運行/微調。
# alexnet_pytorch.py
import torch
import torch.nn as nn
import torch.nn.functional as Fclass AlexNetOriginal(nn.Module):def __init__(self, num_classes=1000, dropout=0.5):super(AlexNetOriginal, self).__init__()self.features = nn.Sequential(# Conv1: 3 -> 96, kernel 11, stride 4, pad 2nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),nn.ReLU(inplace=True),nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.75, k=2.0),nn.MaxPool2d(kernel_size=3, stride=2),# Conv2: 96 -> 256, kernel 5, pad 2, groups=2 (paper used 2 GPUs)nn.Conv2d(96, 256, kernel_size=5, padding=2, groups=2),nn.ReLU(inplace=True),nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.75, k=2.0),nn.MaxPool2d(kernel_size=3, stride=2),# Conv3: 256 -> 384, kernel 3, pad 1nn.Conv2d(256, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),# Conv4: 384 -> 384, kernel 3, pad 1, groups=2nn.Conv2d(384, 384, kernel_size=3, padding=1, groups=2),nn.ReLU(inplace=True),# Conv5: 384 -> 256, kernel 3, pad 1, groups=2nn.Conv2d(384, 256, kernel_size=3, padding=1, groups=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),)# ensure fixed flatten size: use adaptive pooling -> 6x6self.avgpool = nn.AdaptiveAvgPool2d((6, 6))self.classifier = nn.Sequential(nn.Dropout(p=dropout),nn.Linear(256 * 6 * 6, 4096),nn.ReLU(inplace=True),nn.Dropout(p=dropout),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Linear(4096, num_classes),)def forward(self, x):x = self.features(x)x = self.avgpool(x) # shape -> (N, 256, 6, 6)x = torch.flatten(x, 1) # shape -> (N, 256*6*6)x = self.classifier(x)return x# Example: instantiate model
# model = AlexNetOriginal(num_classes=1000)
# print(model)
說明:
LocalResponseNorm
在 PyTorch 中可用,但在現代網絡中通常被 BN(BatchNorm)替代。groups=2
用于復現原論文的分組連接;在多 GPU 時可以映射到不同設備,在單 GPU 上也能按分組工作(等價于并行的兩個卷積再 concat)。([NeurIPS 會議錄][1], [PyTorch Forums][4])
7. 訓練與評估(實踐步驟 + 超參數建議)
數據準備(paper 的處理):
- 將訓練圖像縮放,使短邊為 256(保持縱橫比)。
- 從縮放圖像提取隨機 224×224 補丁(并隨機鏡像)用于訓練;評估時使用中心裁剪(center crop)。
- 進行像素級的“lighting” PCA 擾動(paper 中提到的顏色主成分擾動)或使用更簡單的
ColorJitter
。([NeurIPS 會議錄][1])
超參數(paper 的設置,作為起點):
- 優化器:SGD(momentum)
- 初始學習率:
lr = 0.01
(paper) - momentum =
0.9
- weight_decay =
0.0005
- batch_size =
128
(如果 GPU 內存不足可降到 64/32) - 學習率衰減:當驗證誤差停滯時手動將 lr 降
×0.1
(paper 中總共減少 3 次,最終 lr≈1e-5) - 訓練輪數:paper 大約訓練 90 個 epoch(總耗時 5–6 天,用兩塊 GTX 580 GPU)。現實中通常用更強硬件或直接 fine-tune 預訓練模型。([NeurIPS 會議錄][1], [維基百科][2])
訓練代碼模板(偽代碼,關鍵點):
# 偽代碼概覽(簡化版,不含 DataLoader 構造)
model = AlexNetOriginal(num_classes=1000).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1) # 舉例for epoch in range(epochs):model.train()for images, labels in train_loader:images, labels = images.to(device), labels.to(device)logits = model(images)loss = criterion(logits, labels)optimizer.zero_grad()loss.backward()optimizer.step()# 驗證 & 學習率調整scheduler.step()# 記錄 train/val loss 與 top-1/top-5 accuracy
評估(Top-1 / Top-5):
用 torch.topk
可以計算 top-k 準確率;ImageNet 采用 top-1 與 top-5 指標。
可行替代(如果你資源有限):
- 直接使用
torchvision.models.alexnet(pretrained=True)
做 fine-tune(更快、更實用)。 - 在 CIFAR-10 / CIFAR-100 或自定義小數據集上練習,先保證實現無誤,再上大規模數據。([PyTorch Docs][6])
8. 實驗擴展(建議做的對比實驗)
- 激活函數對比:ReLU vs LeakyReLU vs ELU(訓練速度與最終精度比較)。
- 池化方式:Overlapping MaxPool(paper) vs non-overlapping vs AveragePool。
- BN vs LRN:在 conv 層后替換 LRN 為 BatchNorm,觀察訓練穩定性與收斂速度(BN 通常更好)。
- Dropout 和 權重衰減的組合:研究不同 dropout 概率和 weight_decay 對泛化影響。
- 數據增強:比較僅隨機裁剪/鏡像與加入 ColorJitter / PCA lighting 的效果。
- 優化器/學習率策略:SGD+momentum vs Adam/AdamW vs cosine lr schedule。
做這些實驗時,把對比的關鍵指標(train/val loss、top-1/top-5 accuracy、訓練時間)畫成曲線,會很直觀。
9. 總結
- AlexNet 的成功來自于“把深度網絡 + ReLU + 大規模數據 + GPU + 一些工程技巧(數據增強、dropout、LRN、分組計算)”結合起來。它證明了深度卷積網絡在大數據集上的巨大潛力,從而推動了后續更深、更高效模型的發展(如 VGG、GoogLeNet、ResNet 等)。([NeurIPS 會議錄][1], [維基百科][2])
- 實踐建議:若只想快速上手并取得良好結果,優先選擇 預訓練模型 + 微調;若目標是理解與復現原論文,按本文給出的實現與訓練超參做實驗并記錄對比會很有收獲。