系列文章目錄
文章目錄
- 系列文章目錄
- 前言
- 一、VGG類的搭建
- 1.源碼
- 2.初始化類
- 2.1 初始化函數
- 2.2 前向傳播函數 forward(self,x)
- 二、卷積補充
- 卷積
前言
??對于標準的 VGG net 輸入圖像的尺寸是 24 x 24,進行 32 維的下采樣之后得到一個 7 x 7 的特征圖,然后用 FC 層完成分類。在這里我們要對數據進行增強,然后 resize 到 28 * 28 的尺寸。如果直接使用 VGG net 沒有辦法直接進行 32 x 32 下采樣的。,下面我們來搭建這個串聯的網絡結構。
一、VGG類的搭建
1.源碼
import torch
import torch.nn.functional as F # 使用這個庫進行softmax
import torch.nn as nn # 使用這個庫進行卷積# 定義類
class VggBase(nn.Module):def __init__(self):# 第一步初始化函數super(VggBase, self).__init__()# 定義一些列算子,每次經過一個pooling層卷積加倍# 第一個卷積采用序列, 輸入的數據 3 x 28 x 28 ,crop 之后self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3,padding=1),nn.BatchNorm2d(64), # 輸出的通道nn.ReLU())self.max_pooling1 = nn.MaxPool2d(kernel_size=2, stride=2) # 下采樣減半# 第一個卷積采用序列之后, 輸出的數據 14*14*64self.conv2_1 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=3,padding=1),nn.BatchNorm2d(128), # 輸出的通道nn.ReLU())# 目前卷積14*14*128self.conv2_2 = nn.Sequential(nn.Conv2d(128, 128, kernel_size=3,padding=1),nn.BatchNorm2d(128), # 輸出的通道nn.ReLU())self.max_pooling2= nn.MaxPool2d(kernel_size=2, stride=2)# 輸出 7*7*128self.conv3_1 = nn.Sequential(nn.Conv2d(128, 256, kernel_size=3,padding=1),nn.BatchNorm2d(256), # 輸出的通道nn.ReLU())# 目前卷積7*7*256self.conv3_2 = nn.Sequential(nn.Conv2d(256, 256, kernel_size=3,padding=1),nn.BatchNorm2d(256), # 輸出的通道nn.ReLU())# 由于圖片7*7奇數,需要padding = 1,防止損失self.max_pooling3= nn.MaxPool2d(kernel_size=2, stride=2,padding=1)# 輸出4*4*256self.conv4_1 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3,padding=1),nn.BatchNorm2d(512), # 輸出的通道nn.ReLU())# 目前卷積4*4*512self.conv4_2 = nn.Sequential(nn.Conv2d(512, 512, kernel_size=3,padding=1),nn.BatchNorm2d(512), # 輸出的通道nn.ReLU())self.max_pooling4= nn.MaxPool2d(kernel_size=2, stride=2)#全連接層,目前的數據 batch * 4 * 4 * 512 我們要變成--> batch * (4 * 512)self.fc1 = nn.Linear(4*512,10) # 第一個輸入參數的個數是 maxpooling之后特征圖的大小 512*2*2# 輸出 2*2*512def forward(self,x):# st1取出batch_size,就是x的第0維batch_size = x.size(0)#st2 定義輸出,取第一個卷積out = self.conv1(x)out = self.max_pooling1(out)out = self.conv2_1(out)out = self.conv2_2(out)out = self.max_pooling2(out)out = self.conv3_1(out)out = self.conv3_2(out)out = self.max_pooling3(out)out = self.conv4_1(out)out = self.conv4_2(out)out = self.max_pooling4(out)# 全連接層,開始變形out = out.view(batch_size,-1) # -1 會根據具體的維度進行計算 -1 就是把 batch * 2 *2 * 512變成 batch*(4*512) 也就是batch_size * nout = self.fc1(out) # 實際上VGG有三個fc層,輸出結果 batch_size * 10out = F.log_softmax(out, dim=1) #return outdef VGGNet():return VGGNet()
??網絡的搭建不難,一個初始化類和一個前向傳播函數,我覺得重點是要去理解一下形狀是怎么變化的。如何控制padding和stride來變化形狀,不知道的話,下面講解將會很難聽懂,去補基礎吧,哈哈哈哈,點擊這里,1-9集。
2.初始化類
2.1 初始化函數
重點在卷積層,定義了四個卷積層和4個池化層,卷積一次,采用序列定義卷積層。
self.conv1 = nn.Sequential(nn.Conv2d(3,64,kernel_size=3,padding=1),nn.BatchNorm2d(64), nn.ReLU())
-
nn.Conv2d(3,64,kernel_size=3,padding=1)
- 3代表輸入通道,此處RGB通道等于3
- 64是輸出通道,也就是卷積核的數量
- kernel_size = 3,卷積核的大小 3*3 的方陣
- padding = 1,在圖片四周補一圈0,保證卷積不改變圖片尺寸,具體還得看情況。
- 卷積的步長stride默認等于1,一般不調整。
-
nn.BatchNorm2d(64) 歸一化函數,64是一定要與卷積之后的輸出通道相同。
-
nn.ReLU() 激活函數,負數變0,正數不變。
池化層:降維,改變圖片大小,不改變通道數目
self.max_pooling1 = nn.MaxPool2d(kernel_size=2, stride=2)
- kernel_size=2 卷積核大小 2*2
- stride = 2, 向右移動兩個步長,卷積核多大就移動幾個步長。看教程一般都是2
后面無非就是重復多建立幾個層,卷積和池化唄,注意,VGGNet池化之后,圖片大小變少,下一次卷積時輸出通道翻倍(卷積核翻倍)
2.2 前向傳播函數 forward(self,x)
??前向傳播就是調用前向傳播函數,然后這個函數調用初始化中的操作算子,卷積池化,在卷積再池化 … 全鏈接層,分類或回歸。順序與初始化中的操作算子一樣,只不過全連接層要處理一下。
??張量tensor(batch, C, H,W)翻譯(一組圖片,特征數目,圖片豎高,圖片橫寬),第一步統計一組圖片的數量,就是第 0 維。為什么分批次?6w張圖片或者80w張,內存不夠,我們分組傳入圖片訓練。
??全鏈接層處理:
out = self.fc1(out)
需要參數是(batch,n)目前是(batch,512,2,2)- 張量處理:
- 繼續卷積池化:(batch,512,2,2)變成(batch,1024,1,1)由于(1,1)=1個元素,即(batch,1024)
out = out.view(batch_size,-1)
自動轉化,最好是卷積吧。
out = self.fc1(out)
數據形成類別,形狀 batch *10,每張圖片在10個類別中都有數據,out = F.log_softmax(out, dim=1)
統計形成類別的概率,選擇最大相似度的打印。
二、卷積補充
卷積
??大家看了基礎視頻,我也發表一下我的看法。卷積就是特征提取,但是特征又是什么?我們熟悉一下一張圖片的輸入和張量。

圖片的tensor張量=(batch, C, H,W)翻譯(一組圖片,特征數目,圖片豎高,圖片橫寬) 一組圖片的數量是不會改變的,改變的只有特征數目,圖片的大小(最后兩個維度控制),卷積的過程理解成特征提取變多,圖片變小,越是細小,特征細節越多嘛。開始可以理解成只有紅綠藍這三種特征。

用一個卷積核33去和 R G B 這三張圖片的33區域做內積(對應位置相乘)再相加,三張圖片得到三個數,三個數再次求和得到一個元素,這就是卷積一個視野所得的新元素。然后滑動去卷積下一個元素,圖片像素不夠,為了防止遺漏細節還需要拓展叫做padding. padding = 1 ,在四周加一圈 0。比如這張 55 的圖片,33的卷積核,圖片大小只能是卷積核的倍數才能完美契合,否則需要拓展,拓展后可以比倍數多一點
我們進行padding = 1,四周加一圈0,變成77,多了一點無妨。卷積后的圖片像素依舊是 55,如下圖所示。我們卷積一般不改變圖片大小,僅僅提升通道數目,特征數目。池化的時候才改變圖片大小。怎么加padding呢?有一個技巧,選擇卷積核中心,外擴,33 擴一圈,55 擴兩圈 實際上也只有 33,發現不成倍數就 擴建一圈padding = 1, 5 * 5 的卷積核大了,完全可以使用兩個33的卷積核代替,而且計算還小。