官术网_书友最值得收藏!

3.3 理解殘差網絡

殘差網絡(ResNet,“Deep Residual Learning for Image Recognition”,https://arxiv.org/abs/1512.03385)是在2015年發布的,當時它們贏得了那年ImageNet挑戰賽的所有五個類別。在第1章中,提到神經網絡的層不受順序的限制,而是形成一個圖。這是我們要學習的第一個架構,它利用了這種靈活性。這也是第一個成功訓練了深度超過100層的網絡架構。

由于更好的權重初始化、新的激活函數以及標準化層,現在可以訓練深度網絡。但是,論文作者進行了一些實驗,觀察到一個56層的網絡比一個20層的網絡有更多的訓練和測試錯誤,他們認為情況不應該如此。理論上,可以采用一個淺層網絡,并在其之上堆疊恒等層(這些恒等層的輸出只是在重復輸入),從而產生一個與淺層網絡完全相同的深層網絡。然而,他們的實驗的性能還不能匹配淺層網絡的性能。

為了解決這個問題,他們提出了一種殘差塊構成的網絡。殘差塊由兩個或三個順序卷積層和一個單獨的并行恒等、(中繼器)快捷連接組成,連接第一層的輸入和最后一層的輸出。在下面的截圖中可以看到三種類型的殘差塊。

000

從左到右:原始殘差塊、原始瓶頸殘差塊、預激活殘差塊、預激活瓶頸殘差塊

每個塊有兩條并行路徑。左邊的路徑與其他網絡相似,由順序卷積層+批標準化組成。右邊的路徑包含恒等快捷連接(也稱為跳躍連接)。這兩條路徑通過元素依次求和進行合并。也就是說,左右張量具有相同的形狀,第一個張量的一個元素被加到第二個張量中相同位置的元素上。輸出是一個與輸入形狀相同的張量。實際上,前向傳播塊學習的特征,同時也傳播原始的未修改的信號。這樣,可以更接近作者所描述的原始場景。由于有了跳躍連接,網絡可以決定跳過一些卷積層,這實際上減少了它自己的深度。殘差塊使用這樣的方式填充,使塊的輸入和輸出具有相同的尺寸。多虧了這一點,可以為任意深度的網絡堆疊任意數量的塊。

現在,看看圖中的塊有什么不同:

  • 第一個塊包含兩個3×3的卷積層。這是原始的殘差塊,但如果層很寬,堆疊多個塊會使計算代價昂貴。
  • 第二個塊與第一個塊等價,但它使用了瓶頸層。首先,使用一個1×1卷積來向下采樣輸入volume的深度(見第2章)。然后,對被減少的輸入應用一個3×3(瓶頸)卷積。最后,用另一個1×1的卷積將輸出擴展到所需的深度。這一層的計算開銷比第一層少。
  • 第三個塊是由同一作者于2016年發布的最新版本(“Identity Mappings in Deep Residual Networks”,https://arxiv.org/abs/1603.05027)。它使用預激活,其中批標準化和激活函數位于卷積層之前。乍一看,這可能有些奇怪,但是由于這種設計,跳躍連接路徑可以在整個網絡中不間斷地運行。這與其他殘差塊相反,其中至少有一個激活函數位于跳躍連接的路徑上。堆疊的殘差塊的組合仍然具有順序正確的層。
  • 第四個塊是第三個塊的瓶頸版本。其原理與瓶頸殘差層v1相同。

在下表中,可以看到論文作者提出的網絡家族。

000

最流行的殘差網絡家族。殘差塊用圓角矩形表示

它們的一些特性如下:

  • 它們從一個步長為2的7×7卷積層開始,然后是3×3最大池化層。這一層也作為一個向下采樣的步驟——與輸入的224×224相比,網絡的其余部分開始于一個更小的56×56的切片。
  • 網絡其余部分的下采樣采用改進的步長為2的殘差塊實現。
  • 平均池化下采樣在所有殘差塊之后,1000單元全連接softmax層之前輸出。

ResNet家族網絡會流行,不僅因為它們的準確率,還因為它們相對簡單和殘差塊的通用性。如前所述,由于填充,殘差塊的輸入和輸出形狀可以是相同的。可以將殘差塊按不同的配置堆疊起來,以解決訓練集大小和輸入維數范圍廣泛的各種問題。由于這種普遍性,我們將在下一節中實現ResNet的一個示例。

實現殘差塊

本節使用PyTorch 1.3.1和torchvision 0.4.2實現一個預激活ResNet來對CIFAR-10圖像進行分類。讓我們開始吧。

1)和往常一樣,從導入開始。注意,使用簡短的F表示PyTorch的功能模塊(https://pytorch.org/docs/stable/nn.html#torch-nn-functional):

000

2)定義預激活常規(非瓶頸)殘差塊。將其實現為nn.Module——所有神經網絡模塊的基類。從類定義和__init__方法開始:

000

__init__方法中,只定義可學習的塊組件——包括卷積和批標準化操作。另外,請注意實現shortcut連接的方式。如果輸入維數和輸出維數相同,可以直接使用輸入張量實現快捷連接。但是,如果維度不同,必須在與主路徑相同的步長和輸出通道下,用1×1卷積來轉換輸入。維度可能因高度/寬度(stride !=1)或深度(in_slices !=self.expansion * slices)而不同。self.expansion是一個超參數,它包含在原始ResNet實現中。它允許擴展殘差塊的輸出深度。

3)實際的數據傳播是通過forward方法實現的(請注意縮進,因為它是PreActivationBlock的成員):

000

使用函數F.relu表示激活函數,因為它沒有可學習的參數。然后,如果跳躍連接是一個卷積而不是恒等連接(也就是說,塊的輸入/輸出維數不同),將重用F.relu (self.bn_1(x))為快捷連接添加非線性和批標準化。否則,我們只是重復輸入。

4)實現殘差塊的瓶頸版本。使用與非瓶頸實現相同的模板。從類定義和__init__方法開始:

000

expansion參數在原始實現之后為4。self.conv_1卷積運算表示1×1下采樣瓶頸連接,self.conv_2是真實的卷積,self.conv_3是上采樣1×1卷積。快捷機制遵循與PreActivationBlock中相同的邏輯。

5)實現PreActivationBottleneckBlock.forward方法。同樣,它遵循與PreActivationBlock相同的邏輯:

000

6)實現殘差網絡本身。從類定義(它繼承了nn. Module)和__init__方法開始:

000

網絡中包含四組殘差塊,就像最初的實現一樣。每組的塊數由num_blocks參數指定。最初的卷積使用的是步長為1的3×3過濾器,而不是原來的步長為2的7×7過濾器。這是因為32×32的CIFAR-10圖像遠小于224×224的ImageNet圖像,沒有必要進行下采樣。

7)實現PreActivationResNet._make_group方法,該方法創建一個殘差塊組。組中的所有塊的步長都為1,除了第一個塊,其中stride作為參數提供:

000

8)實現PreActivationResNet.forward方法,通過網絡傳播數據。可以看到在全連接的最后一層之前的下行采樣平均池化:

000

9)一旦完成網絡,可以實現幾種ResNet配置。以下為ResNet34,它具有34個卷積層,分組在[3,4,6,3]的非瓶頸殘差塊中:

000

10)最后,可以訓練網絡。從定義訓練和測試數據集開始。我們不會詳細討論實現的細節,因為已經在第2章中看到了一個類似的場景。用4個像素填充樣本來增加訓練集,然后從中隨機取出32×32的裁剪。具體實現如下:

000

11)然后,實例化網絡模型和訓練參數——交叉熵損失和Adam優化器:

000

12)可以為EPOCHS個epoch訓練網絡。train_model、test_modelplot_accuracy函數與2.2.1節中的一樣,在這里不再重復它們的實現。代碼如下:

000

并且在下圖中,可以看到15次迭代(訓練可能需要一段時間)的測試準確率。

000

15個epoch的測量準確率

000 本節中的代碼部分基于https://github.com/kuangliu/pytorch-cifar中的預激活ResNet實現。

本節討論了各種類型的ResNet,然后使用PyTorch實現一個ResNet。在下一節中,討論Inception網絡——另一個網絡家族,它將并行連接的使用提升到一個新的水平。

主站蜘蛛池模板: 华安县| 格尔木市| 开鲁县| 宁国市| 普定县| 仪征市| 营山县| 朝阳市| 石阡县| 招远市| 呼伦贝尔市| 裕民县| 中方县| 荆门市| 临澧县| 台北县| 蓬莱市| 始兴县| 彝良县| 法库县| 盐源县| 平江县| 美姑县| 宣汉县| 常州市| 西林县| 保定市| 涟水县| 齐齐哈尔市| 泰顺县| 平潭县| 张家界市| 嵩明县| 彰化县| 两当县| 额尔古纳市| 阜康市| 轮台县| 西乡县| 华蓥市| 津市市|