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