雖然 AlexNet 提供了深度 CNN 可以取得良好結(jié)果的經(jīng)驗(yàn)證據(jù),但它沒有提供通用模板來指導(dǎo)后續(xù)研究人員設(shè)計(jì)新網(wǎng)絡(luò)。在接下來的部分中,我們將介紹幾個(gè)常用于設(shè)計(jì)深度網(wǎng)絡(luò)的啟發(fā)式概念。
該領(lǐng)域的進(jìn)展反映了芯片設(shè)計(jì)中 VLSI(超大規(guī)模集成)的進(jìn)展,工程師從將晶體管放置到邏輯元件再到邏輯塊(Mead,1980 年)。同樣,神經(jīng)網(wǎng)絡(luò)架構(gòu)的設(shè)計(jì)也變得越來越抽象,研究人員從單個(gè)神經(jīng)元的角度思考到整個(gè)層,現(xiàn)在轉(zhuǎn)向塊,重復(fù)層的模式。十年后,這已經(jīng)發(fā)展到研究人員使用整個(gè)訓(xùn)練模型將它們重新用于不同但相關(guān)的任務(wù)。此類大型預(yù)訓(xùn)練模型通常稱為 基礎(chǔ)模型 (Bommasani等人,2021 年)。
回到網(wǎng)絡(luò)設(shè)計(jì)。使用塊的想法首先出現(xiàn)于牛津大學(xué)的視覺幾何組 (VGG),在他們同名的VGG網(wǎng)絡(luò)中(Simonyan 和 Zisserman,2014 年)。通過使用循環(huán)和子例程,可以使用任何現(xiàn)代深度學(xué)習(xí)框架輕松地在代碼中實(shí)現(xiàn)這些重復(fù)結(jié)構(gòu)。
import torch from torch import nn from d2l import torch as d2l
from mxnet import init, np, npx from mxnet.gluon import nn from d2l import mxnet as d2l npx.set_np()
import jax from flax import linen as nn from d2l import jax as d2l
import tensorflow as tf from d2l import tensorflow as d2l
8.2.1. VGG 塊
CNN 的基本構(gòu)建塊是以下序列:(i) 帶有填充的卷積層以保持分辨率,(ii) 非線性,例如 ReLU,(iii) 池化層,例如最大池化以減少解決。這種方法的問題之一是空間分辨率下降得非常快。特別是,這強(qiáng)加了一個(gè)硬限制log2?d網(wǎng)絡(luò)上所有維度之前的卷積層(d) 用完了。例如,在 ImageNet 的情況下,以這種方式不可能有超過 8 個(gè)卷積層。
Simonyan 和 Zisserman ( 2014 )的關(guān)鍵思想是以 塊的形式通過最大池化在下采樣之間使用多個(gè)卷積。他們主要感興趣的是深度網(wǎng)絡(luò)還是寬網(wǎng)??絡(luò)表現(xiàn)更好。例如,連續(xù)應(yīng)用兩個(gè) 3×3卷積接觸與單個(gè)相同的像素 5×5卷積確實(shí)如此。同時(shí),后者使用了大約同樣多的參數(shù)(25?c2) 三個(gè) 3×3卷積做(3?9?c2). 在相當(dāng)詳細(xì)的分析中,他們表明深度和狹窄的網(wǎng)絡(luò)明顯優(yōu)于淺層網(wǎng)絡(luò)。這將深度學(xué)習(xí)置于對具有超過 100 層的典型應(yīng)用的更深網(wǎng)絡(luò)的追求上。堆疊3×3卷積已成為后來的深度網(wǎng)絡(luò)的黃金標(biāo)準(zhǔn)(最近Liu等人( 2022 )才重新考慮的設(shè)計(jì)決策)。因此,小卷積的快速實(shí)現(xiàn)已成為 GPU 的主要內(nèi)容 (Lavin 和 Gray,2016 年)。
回到 VGG:一個(gè) VGG 塊由一系列卷積組成 3×3填充為 1 的內(nèi)核(保持高度和寬度)后跟一??個(gè)2×2步長為 2 的最大池化層(每個(gè)塊后將高度和寬度減半)。在下面的代碼中,我們定義了一個(gè)函數(shù)vgg_block來實(shí)現(xiàn)一個(gè) VGG 塊。
下面的函數(shù)有兩個(gè)參數(shù),對應(yīng)于卷積層數(shù)num_convs和輸出通道數(shù) num_channels。
def vgg_block(num_convs, out_channels): layers = [] for _ in range(num_convs): layers.append(nn.LazyConv2d(out_channels, kernel_size=3, padding=1)) layers.append(nn.ReLU()) layers.append(nn.MaxPool2d(kernel_size=2,stride=2)) return nn.Sequential(*layers)
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
def vgg_block(num_convs, out_channels): layers = [] for _ in range(num_convs): layers.append(nn.Conv(out_channels, kernel_size=(3, 3), padding=(1, 1))) layers.append(nn.relu) layers.append(lambda x: nn.max_pool(x, window_shape=(2, 2), strides=(2, 2))) return nn.Sequential(layers)
def vgg_block(num_convs, num_channels): blk = tf.keras.models.Sequential() for _ in range(num_convs): blk.add( tf.keras.layers.Conv2D(num_channels, kernel_size=3, padding='same', activation='relu')) blk.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2)) return blk
8.2.2. VGG網(wǎng)絡(luò)
與 AlexNet 和 LeNet 一樣,VGG 網(wǎng)絡(luò)可以分為兩部分:第一部分主要由卷積層和池化層組成,第二部分由與 AlexNet 相同的全連接層組成。關(guān)鍵區(qū)別在于卷積層在保持維數(shù)不變的非線性變換中分組,然后是分辨率降低步驟,如圖 8.2.1所示。
圖 8.2.1從 AlexNet 到 VGG。關(guān)鍵區(qū)別在于 VGG 由層塊組成,而 AlexNet 的層都是單獨(dú)設(shè)計(jì)的。
網(wǎng)絡(luò)的卷積部分連續(xù)連接 圖 8.2.1中的幾個(gè) VGG 塊(也在vgg_block函數(shù)中定義)。這種卷積分組是一種在過去十年中幾乎保持不變的模式,盡管操作的具體選擇已經(jīng)發(fā)生了相當(dāng)大的修改。該變量 conv_arch由一個(gè)元組列表(每個(gè)塊一個(gè))組成,其中每個(gè)元組包含兩個(gè)值:卷積層數(shù)和輸出通道數(shù),它們正是調(diào)用函數(shù)所需的參數(shù)vgg_block。因此,VGG 定義了一個(gè)網(wǎng)絡(luò)家族,而不僅僅是一個(gè)特定的表現(xiàn)形式。要構(gòu)建一個(gè)特定的網(wǎng)絡(luò),我們只需迭代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='relu'), nn.Dropout(0.5), nn.Dense(4096, activation='relu'), nn.Dropout(0.5), nn.Dense(num_classes)) self.net.initialize(init.Xavier())
class VGG(d2l.Classifier): arch: list lr: float = 0.1 num_classes: int = 10 training: bool = True def setup(self): conv_blks = [] for (num_convs, out_channels) in self.arch: conv_blks.append(vgg_block(num_convs, out_channels)) self.net = nn.Sequential([ *conv_blks, lambda x: x.reshape((x.shape[0], -1)), # flatten nn.Dense(4096), nn.relu, nn.Dropout(0.5, deterministic=not self.training), nn.Dense(4096), nn.relu, nn.Dropout(0.5, deterministic=not self.training), nn.Dense(self.num_classes)])
class VGG(d2l.Classifier): def __init__(self, arch, lr=0.1, num_classes=10): super().__init__() self.save_hyperparameters() self.net = tf.keras.models.Sequential() for (num_convs, num_channels) in arch: self.net.add(vgg_block(num_convs, num_channels)) self.net.add( tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(4096, activation='relu'), tf.keras.layers.Dropout(0.5), tf.keras.layers.Dense(4096, activation='relu'), tf.keras.layers.Dropout(0.5), tf.keras.layers.Dense(num_classes)]))
原始VGG網(wǎng)絡(luò)有5個(gè)卷積塊,其中前兩個(gè)各有一個(gè)卷積層,后三個(gè)各有兩個(gè)卷積層。第一個(gè)塊有 64 個(gè)輸出通道,隨后的每個(gè)塊將輸出通道的數(shù)量加倍,直到該數(shù)量達(dá)到 512。由于該網(wǎng)絡(luò)使用 8 個(gè)卷積層和 3 個(gè)全連接層,因此通常稱為 VGG-11。
VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))).layer_summary( (1, 1, 224, 224))
Sequential output shape: torch.Size([1, 64, 112, 112]) Sequential output shape: torch.Size([1, 128, 56, 56]) Sequential output shape: torch.Size([1, 256, 28, 28]) Sequential output shape: torch.Size([1, 512, 14, 14]) Sequential output shape: torch.Size([1, 512, 7, 7]) Flatten output shape: torch.Size([1, 25088]) Linear output shape: torch.Size([1, 4096]) ReLU output shape: torch.Size([1, 4096]) Dropout output shape: torch.Size([1, 4096]) Linear output shape: torch.Size([1, 4096]) ReLU output shape: torch.Size([1, 4096]) Dropout output shape: torch.Size([1, 4096]) Linear output shape: torch.Size([1, 10])
VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))).layer_summary( (1, 1, 224, 224))
Sequential output shape: (1, 64, 112, 112) Sequential output shape: (1, 128, 56, 56) Sequential output shape: (1, 256, 28, 28) Sequential output shape: (1, 512, 14, 14) Sequential output shape: (1, 512, 7, 7) Dense output shape: (1, 4096) Dropout output shape: (1, 4096) Dense output shape: (1, 4096) Dropout output shape: (1, 4096) Dense output shape: (1, 10)
VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512)), training=False).layer_summary((1, 224, 224, 1))
Sequential output shape: (1, 112, 112, 64) Sequential output shape: (1, 56, 56, 128) Sequential output shape: (1, 28, 28, 256) Sequential output shape: (1, 14, 14, 512) Sequential output shape: (1, 7, 7, 512) function output shape: (1, 25088) Dense output shape: (1, 4096) custom_jvp output shape: (1, 4096) Dropout output shape: (1, 4096) Dense output shape: (1, 4096) custom_jvp output shape: (1, 4096) Dropout output shape: (1, 4096) Dense output shape: (1, 10)
VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))).layer_summary( (1, 224, 224, 1))
Sequential output shape: (1, 112, 112, 64) Sequential output shape: (1, 56, 56, 128) Sequential output shape: (1, 28, 28, 256) Sequential output shape: (1, 14, 14, 512) Sequential output shape: (1, 7, 7, 512) Sequential output shape: (1, 10)
如您所見,我們將每個(gè)塊的高度和寬度減半,最終達(dá)到 7 的高度和寬度,然后展平表示以供網(wǎng)絡(luò)的完全連接部分處理。 Simonyan 和 Zisserman ( 2014 )描述了 VGG 的其他幾種變體。事實(shí)上,在引入新架構(gòu)時(shí),提出具有不同速度-精度權(quán)衡的網(wǎng)絡(luò)系列已經(jīng)成為常態(tài)。
8.2.3. 訓(xùn)練
由于 VGG-11 在計(jì)算上比 AlexNet 要求更高,我們構(gòu)建了一個(gè)通道數(shù)較少的網(wǎng)絡(luò)。這對于 Fashion-MNIST 的訓(xùn)練來說綽綽有余。模型訓(xùn)練過程與8.1節(jié)AlexNet類似。再次觀察驗(yàn)證和訓(xùn)練損失之間的密切匹配,表明只有少量過度擬合。
model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01) trainer = d2l.Trainer(max_epochs=10, num_gpus=1) data = d2l.FashionMNIST(batch_size=128, resize=(224, 224)) model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn) trainer.fit(model, data)
model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01) trainer = d2l.Trainer(max_epochs=10, num_gpus=1) data = d2l.FashionMNIST(batch_size=128, resize=(224, 224)) trainer.fit(model, data)
model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01) trainer = d2l.Trainer(max_epochs=10, num_gpus=1) data = d2l.FashionMNIST(batch_size=128, resize=(224, 224)) trainer.fit(model, data)
trainer = d2l.Trainer(max_epochs=10) data = d2l.FashionMNIST(batch_size=128, resize=(224, 224)) with d2l.try_gpu(): model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01) trainer.fit(model, data)
8.2.4. 概括
有人可能會爭辯說 VGG 是第一個(gè)真正現(xiàn)代的卷積神經(jīng)網(wǎng)絡(luò)。雖然 AlexNet 引入了許多使深度學(xué)習(xí)大規(guī)模有效的組件,但可以說是 VGG 引入了關(guān)鍵屬性,例如多個(gè)卷積塊以及對深度和窄網(wǎng)絡(luò)的偏好。它也是第一個(gè)實(shí)際上是整個(gè)類似參數(shù)化模型系列的網(wǎng)絡(luò),為從業(yè)者提供了復(fù)雜性和速度之間的充分權(quán)衡。這也是現(xiàn)代深度學(xué)習(xí)框架大放異彩的地方。不再需要生成 XML 配置文件來指定網(wǎng)絡(luò),而是通過簡單的 Python 代碼組裝所述網(wǎng)絡(luò)。
最近 ParNet (Goyal等人,2021 年) 證明,可以通過大量并行計(jì)算使用更淺的架構(gòu)來實(shí)現(xiàn)有競爭力的性能。這是一個(gè)令人興奮的發(fā)展,希望它能影響未來的建筑設(shè)計(jì)。不過,在本章的剩余部分,我們將追溯過去十年的科學(xué)進(jìn)步之路。
8.2.5. 練習(xí)
與 AlexNet 相比,VGG 在計(jì)算方面要慢得多,而且需要更多的 GPU 內(nèi)存。
比較 AlexNet 和 VGG 所需的參數(shù)數(shù)量。
比較卷積層和全連接層中使用的浮點(diǎn)運(yùn)算數(shù)量。
您如何減少全連接層產(chǎn)生的計(jì)算成本?
當(dāng)顯示與網(wǎng)絡(luò)各層相關(guān)的維度時(shí),我們只能看到與 8 個(gè)塊(加上一些輔助變換)相關(guān)的信息,即使網(wǎng)絡(luò)有 11 層。剩下的 3 層去了哪里?
使用 VGG 論文(Simonyan 和 Zisserman,2014 年)中的表 1構(gòu)建其他常見模型,例如 VGG-16 或 VGG-19。
對 Fashion-MNIST 中的分辨率進(jìn)行上采樣8 從28×28到224×224尺寸非常浪費(fèi)。嘗試修改網(wǎng)絡(luò)架構(gòu)和分辨率轉(zhuǎn)換,例如,將其輸入改為 56 或 84 維。你能在不降低網(wǎng)絡(luò)準(zhǔn)確性的情況下這樣做嗎?考慮 VGG 論文(Simonyan 和 Zisserman,2014 年),了解在下采樣之前添加更多非線性的想法。
-
網(wǎng)絡(luò)
+關(guān)注
關(guān)注
14文章
7586瀏覽量
89008 -
pytorch
+關(guān)注
關(guān)注
2文章
808瀏覽量
13282
發(fā)布評論請先 登錄
相關(guān)推薦
評論