雖然 AlexNet 提供了深度 CNN 可以取得良好結果的經驗證據,但它沒有提供通用模板來指導后續研究人員設計新網絡。在接下來的部分中,我們將介紹幾個常用于設計深度網絡的啟發式概念。
該領域的進展反映了芯片設計中 VLSI(超大規模集成)的進展,工程師從將晶體管放置到邏輯元件再到邏輯塊(Mead,1980 年)。同樣,神經網絡架構的設計也變得越來越抽象,研究人員從單個神經元的角度思考到整個層,現在轉向塊,重復層的模式。十年后,這已經發展到研究人員使用整個訓練模型將它們重新用于不同但相關的任務。此類大型預訓練模型通常稱為 基礎模型 (Bommasani等人,2021 年)。
回到網絡設計。使用塊的想法首先出現于牛津大學的視覺幾何組 (VGG),在他們同名的VGG網絡中(Simonyan 和 Zisserman,2014 年)。通過使用循環和子例程,可以使用任何現代深度學習框架輕松地在代碼中實現這些重復結構。
import tensorflow as tf
from d2l import tensorflow as d2l
8.2.1. VGG 塊
CNN 的基本構建塊是以下序列:(i) 帶有填充的卷積層以保持分辨率,(ii) 非線性,例如 ReLU,(iii) 池化層,例如最大池化以減少解決。這種方法的問題之一是空間分辨率下降得非??臁?/font>特別是,這強加了一個硬限制log2?d網絡上所有維度之前的卷積層(d) 用完了。例如,在 ImageNet 的情況下,以這種方式不可能有超過 8 個卷積層。
Simonyan 和 Zisserman ( 2014 )的關鍵思想是以 塊的形式通過最大池化在下采樣之間使用多個卷積。他們主要感興趣的是深度網絡還是寬網??絡表現更好。例如,連續應用兩個 3×3卷積接觸與單個相同的像素 5×5卷積確實如此。同時,后者使用了大約同樣多的參數(25?c2) 三個 3×3卷積做(3?9?c2). 在相當詳細的分析中,他們表明深度和狹窄的網絡明顯優于淺層網絡。這將深度學習置于對具有超過 100 層的典型應用的更深網絡的追求上。堆疊3×3卷積已成為后來的深度網絡的黃金標準(最近Liu等人( 2022 )才重新考慮的設計決策)。因此,小卷積的快速實現已成為 GPU 的主要內容 (Lavin 和 Gray,2016 年)。
回到 VGG:一個 VGG 塊由一系列卷積組成 3×3填充為 1 的內核(保持高度和寬度)后跟一??個2×2步長為 2 的最大池化層(每個塊后將高度和寬度減半)。在下面的代碼中,我們定義了一個函數vgg_block
來實現一個 VGG 塊。
下面的函數有兩個參數,對應于卷積層數num_convs
和輸出通道數 num_channels
。
def vgg_block(num_convs, num_channels):
blk = nn.Sequential()
for _ in range(num_convs):
blk.add(nn.Conv2D(num_channels, kernel_size=3,
padding=1, activation='relu'))
blk.add(nn.MaxPool2D(pool_size=2, strides=2))
return blk
8.2.2. VGG網絡
與 AlexNet 和 LeNet 一樣,VGG 網絡可以分為兩部分:第一部分主要由卷積層和池化層組成,第二部分由與 AlexNet 相同的全連接層組成。關鍵區別在于卷積層在保持維數不變的非線性變換中分組,然后是分辨率降低步驟,如圖 8.2.1所示。
網絡的卷積部分連續連接 圖 8.2.1中的幾個 VGG 塊(也在vgg_block
函數中定義)。這種卷積分組是一種在過去十年中幾乎保持不變的模式,盡管操作的具體選擇已經發生了相當大的修改。該變量 conv_arch
由一個元組列表(每個塊一個)組成,其中每個元組包含兩個值:卷積層數和輸出通道數,它們正是調用函數所需的參數vgg_block
。因此,VGG 定義了一個網絡家族,而不僅僅是一個特定的表現形式。要構建一個特定的網絡,我們只需迭代arch
以組成塊。
class VGG(d2l.Classifier):
def __init__(self, arch, lr=0.1, num_classes=10):
super().__init__()
self.save_hyperparameters()
conv_blks = []
for (num_convs, out_channels) in arch:
conv_blks.append(vgg_block(num_convs, out_channels))
self.net = nn.Sequential(
*conv_blks, nn.Flatten(),
nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
nn.LazyLinear(num_classes))
self.net.apply(d2l.init_cnn)
class VGG(d2l.Classifier):
def __init__(self, arch, lr=0.1, num_classes=10):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential()
for (num_convs, num_channels) in arch:
self.net.add(vgg_block(num_convs, num_channels))
self.net.add(nn.Dense(4096, activation=
評論
查看更多