PyTorch 实现经典模型3:VGG
VGG
網絡結構
代碼
1) 導入必需的包
# 1) 導入必需的包 import torch import torch.nn as nn import torch.nn.functional as F import torchvision.transforms as transforms2) 搭建網絡模型
# 2) 搭建網絡模型 class VGG(nn.Module):def __init__(self):super(VGG, self).__init__()self.layer11 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1)self.layer12 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1)self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)self.layer21 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1)self.layer22 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1)self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)self.layer31 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1)self.layer32 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1)self.layer33 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1)self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)self.layer41 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1)self.layer42 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1)self.layer43 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1)self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)self.layer51 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1)self.layer52 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1)self.layer53 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1)self.pool5 = nn.MaxPool2d(kernel_size=2, stride=2)self.fc1 = nn.Linear(7*7*512, 4096)self.fc2 = nn.Linear(4096, 4096)self.fc3 = nn.Linear(4096, 1000)def forward(self, x):x = self.pool1(nn.ReLU(self.layer12(nn.ReLU(self.layer11(x)))))x = self.pool2(nn.ReLU(self.layer22(nn.ReLU(self.layer21(x)))))x = self.pool3(nn.ReLU(self.layer33(nn.ReLU(self.layer32(nn.ReLU(self.layer31(x)))))))x = self.pool4(nn.ReLU(self.layer43(nn.ReLU(self.layer42(nn.ReLU(self.layer41(x)))))))x = self.pool5(nn.ReLU(self.layer53(nn.ReLU(self.layer52(nn.ReLU(self.layer51(x)))))))x = x.view(-1,7*7*512)x = self.fc1(x)x = self.fc2(x)x = self.fc3(x)return x3) 導入使用的數據集、網絡結構、優化器、損失函數等
4) 訓練模型
5) 保存模型結構參數
6) 加載模型并測試模型效果
論文幾點注意
感受野
感受野(Receptive Field)的定義是卷積神經網絡每一層輸出的特征圖(feature map)上的像素點在輸入圖片上映射的區域大小。通俗解釋就是特征圖上的一個點跟原圖上有關系的點的區域。
感受野被稱作是CNN中最重要的概念之一,目標檢測流行的算法如 SSD,Faster RCNN 和 prior box 和 anchor box 的設計都是以感受野為依據做的設計。
思考:
- 如果conv1:5x5 stride=1,valid感受野是多少?
結論:
- 一個卷積核(5x5)感受野大小與兩個3x3卷積核感受野等效,以此類推三個3x3卷積核感受野與一個7x7卷積核等效。
感受野計算公式:
rn=rn?1+(kn?1)∏i=1n?1sir_n=r_{n-1}+(k_n-1)\prod_{i=1}^{n-1}s_irn?=rn?1?+(kn??1)i=1∏n?1?si?
其中,rn?1r_{n-1}rn?1?:上一層感受野大小;knk_nkn?:本層卷積核尺寸;sis_isi?:卷積步幅。
還有寫作其他形式
RFl+1=RFl+(kernal_size?1)?strideRF_{l+1}=RF_l+(kernal\_size-1)*strideRFl+1?=RFl?+(kernal_size?1)?stride
eg:(原圖感受野大小為 1)
| conv1: | 3x3 | stride=1 | valid | 1+(3-1)=3 |
| conv2: | 3x3 | stride=1 | valid | 3+(3-1)*1=5 |
| conv3: | 3x3 | stride=1 | valid | 5+(3-1)*1*1=7 |
| conv4: | 3x3 | stride=1 | valid | 7+(3-1)*1*1*2=11 |
| maxp: | 2x2 | stride=1 | valid | 11+(2-1)*1*1*2*1=13 |
注意:感受野這里計算理論值,實際起作用的感受野大小小于理論感受野。
3*3卷積核,1*1卷積核
為什么使用3*3卷積核?
3個3*3卷積核感受野與一個7*7卷積核感受野等效,但是三個3*3卷積之間加入了激活函數,與僅適用一個7*7卷積核相比,深度更深且增加了非線性。
假設輸入數據通道大小為C,3個C通道的3*3卷積核參數量為 3*(C*3*3*C)=27C*C。1個C通道的7*7卷積核參數量為C*7*7*C=49C*C。
1*1卷積核的作用?
eg:mobilenet使用1*1卷積核來擴維;
resnet使用1*1卷積核來減小維度。
VGG 網絡特點
VGG使用多個小卷積核(3*3) 的卷積層代替大的卷積層,一方面可以減少參數,另一方面相當于進行了更多的非線性映射,以增加網絡的擬合/表達能力。
相比 AlexNet 的 3*3 池化核,VGG 全部采用 2*2 的池化核。
VGG常用結構層為 16 層,19 層(僅計算conv,fc層),AlexNet 為 8 層(5個conv,3個fc)。
網絡測試階段將訓練階段的是三個全連接替換為三個卷積,測試時重用訓練時的參數,使得測試得到的全卷積網絡因為無全連接的限制,因而可以接收任意寬或高為輸入。
[Integrated Recognition Localization and Detection using Convolutional Networks]
卷積層替換全連接層
全連接層計算公式為:fc=wT+bfc=w^T+bfc=wT+b。假設輸入到全連接層特征大小為7x7
x5,輸出特征大小為1000x1.首先將輸入特征變為一個列向量。
7?7?5→(245,1)則x大小為(245,1)7*7*5 \rightarrow (245,1)\\ 則\ x\ 大小為(245,1)7?7?5→(245,1)則?x?大小為(245,1)
然后與全連接層權重相乘,偏置相加
w大小為(245,100)b大小為(1000?1)w\ 大小為(245,100)\\ b\ 大小為(1000*1)w?大小為(245,100)b?大小為(1000?1)
假如測試時輸入的特征大小為 14x14x5,需要輸出的特征仍為 1000x1。xxx大小變為(980,1)。而此時www大小為(245,1000),會出現尺寸不匹配問題。
而如果使用卷積層,使用 1000 個 7x7x5 的卷積代替 fc 層,卷積參數量為 7x7x5
x1000 與 fc 層參數量相同,所以可以將 fc 層學習到的參數賦給卷積層。
假設輸入特征為 7x7x5,令 stride=1。最后輸出尺度為 [1,1,1,1000] 可以降維為 [1,1000]。
如果輸入特征為 14x14x5,最后得到特征為 [1,2,2,1000] 即為一個 scoremap,我們對它求平均得到 [1,1000] 向量。
微調(Fine-tuning) 概念
使用預訓練的神經網絡模型,來訓練我們自己的數據集合。使用訓練好的權重來初始化我們的網絡,而不是隨機初始化。在實踐中,我們通常不會完全從頭開始訓練DCNN,這是因為有能滿足深度網絡需求的足夠大小的數據集相當少見。作為代替,常見的是在一個大型數據集上預訓練一個DCNN,然后使用這一訓練的DCNN的權重作為初始設置或作為相關任務的固定特征提取器。
什么情況下使用?
為什么微調會有效?
我們可以利用網絡前幾層學到的通用特征,僅讓網絡學習數據的抽象特征,節省資源和時間。
微調(Fine-tuning):遷移學習策略取決于多種因素,但是最重要的兩個是新數據量的大小及新數據集與原數據集的相似度。以下為4種主要情景:
只需訓練最后的輸出層,即最后一層,因為可能分類的數量不同,最后一層需要做修改。
這是最理想的情況,我們可以微調整個網絡,因為數據量大不用擔心過擬合。
由于數據較小,且相似度低,這種情況微調效果不是很好,可以嘗試凍結前邊大部分卷積層,重新訓練網絡的高層卷積層及全連接層。
由于數據集很大,且相似度比較低,最好不要使用預訓練模型,從頭開始訓練整個網絡。
Ref
總結
以上是生活随笔為你收集整理的PyTorch 实现经典模型3:VGG的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyTorch 实现经典模型2:Alex
- 下一篇: PyTorch 实现经典模型4:Goog